/* 宏建视频运维监管系统 · 管理端样式 */
:root {
  --primary: #2f6fed;
  --red: #e34d59;
  --green: #2f9e6f;
  --amber: #f0a020;
  --purple: #7c5cff;
  --ink: #1b2540;
  --ink2: #5b6b8c;
  --ink3: #9aa5bd;
  --line: #e6ebf5;
  --bg: #f5f7fb;
}
* { box-sizing: border-box; }
[v-cloak] { display: none; }
html, body { margin: 0; height: 100%; }
body {
  font-family: -apple-system, BlinkMacSystemFont, "PingFang SC", "Microsoft YaHei", sans-serif;
  background: var(--bg); color: var(--ink);
}
.small { font-size: 12.5px; }
.tiny { font-size: 11.5px; }
.muted { color: var(--ink3); }
.bold { font-weight: 600; }
.mono { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; }
.ellip { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.red { color: var(--red); }
.green { color: var(--green); }
.ok { color: var(--green); font-weight: 600; }
.warn { color: var(--amber); font-weight: 600; }
.breach { color: var(--red); font-weight: 600; }
.spacer { flex: 1; }
.hint { font-size: 11.5px; color: var(--ink3); font-weight: 400; }

/* ============ 登录 ============ */
.login-page {
  min-height: 100vh; display: flex; align-items: center; justify-content: center;
  background: linear-gradient(135deg, #eef3ff 0%, #f6f8fc 45%, #eaf1ff 100%);
}
.login-box {
  width: 380px; background: #fff; border: 1px solid var(--line); border-radius: 16px;
  padding: 38px 34px 26px; box-shadow: 0 12px 40px rgba(31, 61, 122, .1);
}
.login-brand { font-size: 21px; font-weight: 700; text-align: center; letter-spacing: .5px; }
.login-brand span { color: var(--primary); }
.login-sub { text-align: center; color: var(--ink3); font-size: 12.5px; margin-top: 8px; }
.login-tip {
  margin-top: 16px; padding-top: 14px; border-top: 1px dashed var(--line);
  font-size: 12px; color: var(--ink3); text-align: center;
}

/* ============ 布局 ============ */
.layout { height: 100vh; }
.aside {
  background: #101a33; color: #c8d2e6; display: flex; flex-direction: column;
  border-right: 1px solid #16223f;
}
.logo {
  height: 58px; display: flex; align-items: center; padding: 0 20px;
  font-size: 16.5px; font-weight: 700; color: #fff; letter-spacing: .5px;
  border-bottom: 1px solid #1d2a49;
}
.logo span { color: #6f9bff; margin-left: 4px; }
.menu { flex: 1; padding: 10px 0; overflow-y: auto; }
.menu-item {
  display: flex; align-items: center; gap: 9px; padding: 11px 20px; cursor: pointer;
  font-size: 13.5px; color: #c8d2e6; transition: .15s; position: relative;
}
.menu-item:hover { background: #17223d; color: #fff; }
.menu-item.active { background: #1c2a4d; color: #fff; }
.menu-item.active::before {
  content: ''; position: absolute; left: 0; top: 8px; bottom: 8px; width: 3px;
  background: #4d86ff; border-radius: 0 3px 3px 0;
}
.menu-item .mi { font-size: 14px; width: 18px; text-align: center; opacity: .85; }
.menu-item .badge { margin-left: auto; }

/* 二级菜单（台账管理 → 项目管理 / 点位管理 / 合同风险） */
.mi-arrow { margin-left: auto; font-size: 10px; opacity: .55; transition: transform .18s; }
.mi-arrow.open { transform: rotate(180deg); }
.submenu { padding: 2px 0 4px; }
.menu-sub {
  display: flex; align-items: center; padding: 8px 20px 8px 46px;
  font-size: 13px; color: #a9b6d0; cursor: pointer; position: relative; transition: .15s;
}
.menu-sub:hover { background: #17223d; color: #fff; }
.menu-sub.active { background: #1c2a4d; color: #fff; font-weight: 500; }
.menu-sub.active::before {
  content: ''; position: absolute; left: 0; top: 6px; bottom: 6px; width: 3px;
  background: #4d86ff; border-radius: 0 3px 3px 0;
}
.aside-foot { padding: 12px 20px; border-top: 1px solid #1d2a49; font-size: 11.5px; color: #7f8ca8; line-height: 1.9; }

.header {
  height: 58px; background: #fff; border-bottom: 1px solid var(--line);
  display: flex; align-items: center; padding: 0 18px; gap: 10px;
}
.hd-title { font-size: 15.5px; font-weight: 600; }
.hd-right { margin-left: auto; display: flex; align-items: center; gap: 10px; }
.hd-right .user { font-size: 13px; color: var(--ink2); }
.main { padding: 14px; overflow-y: auto; background: var(--bg); }

/* ============ KPI ============ */
.kpi-row { display: grid; grid-template-columns: repeat(auto-fit, minmax(158px, 1fr)); gap: 12px; }
.kpi {
  background: #fff; border: 1px solid var(--line); border-radius: 12px; padding: 14px 16px;
  border-left: 3px solid var(--primary);
}
.kpi-l { font-size: 12.5px; color: var(--ink2); }
.kpi-v { font-size: 27px; font-weight: 700; line-height: 1.3; font-variant-numeric: tabular-nums; }
.kpi-f { font-size: 11px; color: var(--ink3); }
.kpi.blue { border-left-color: var(--primary); }
.kpi.green { border-left-color: var(--green); }
.kpi.red { border-left-color: var(--red); }
.kpi.amber { border-left-color: var(--amber); }
.kpi.purple { border-left-color: var(--purple); }
.kpi.red .kpi-v { color: var(--red); }
.kpi.amber .kpi-v { color: var(--amber); }
.kpi.green .kpi-v { color: var(--green); }

/* ============ 面板 ============ */
.panel {
  background: #fff; border: 1px solid var(--line); border-radius: 12px; padding: 14px 16px;
}
.panel-h {
  font-size: 13.5px; font-weight: 600; margin-bottom: 10px;
  display: flex; align-items: center; gap: 8px;
}
.chart { width: 100%; }
.toolbar {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  background: #fff; border: 1px solid var(--line); border-radius: 12px;
  padding: 10px 14px; margin-bottom: 12px;
}
.pager { display: flex; justify-content: flex-end; margin-top: 10px; }

/* ============ 接入 ============ */
.ingest-form { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.preview-stat { display: grid; grid-template-columns: repeat(auto-fit, minmax(118px, 1fr)); gap: 10px; }
.ps {
  background: #f8fafd; border: 1px solid var(--line); border-radius: 10px;
  padding: 10px 12px; display: flex; flex-direction: column; gap: 2px;
}
.ps span { font-size: 11.5px; color: var(--ink3); }
.ps b { font-size: 19px; font-weight: 700; font-variant-numeric: tabular-nums; }
.ps.hi { background: #eef4ff; border-color: #c6dbff; }
.ps.hi b { color: var(--primary); }
.warn-box {
  margin-top: 10px; padding: 10px 14px; border-radius: 10px;
  background: #fff8e8; border: 1px solid #ffe4b0; color: #8a6100; font-size: 12.5px; line-height: 1.9;
}

/* ============ 台账 ============ */
.proj-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(272px, 1fr)); gap: 12px; }
.proj-card {
  background: #fff; border: 1px solid var(--line); border-radius: 12px; padding: 13px 15px;
}
.pc-h { display: flex; align-items: center; gap: 8px; margin-bottom: 4px; }
.pc-code { font-size: 14px; font-weight: 600; flex: 1; min-width: 0; }
/* 项目卡片头的操作按钮：默认淡出，hover 才明显，避免卡片显得杂乱 */
.pc-acts { margin-left: auto; display: flex; gap: 2px; flex-shrink: 0; opacity: .45; transition: opacity .15s; }
.proj-card:hover .pc-acts { opacity: 1; }
.pc-acts .el-button { padding: 0 2px; height: 20px; font-size: 11.5px; }
.pc-body {
  display: grid; grid-template-columns: 1fr 1fr; gap: 6px 10px; margin: 10px 0;
  font-size: 12.5px;
}
.pc-body span { color: var(--ink3); margin-right: 6px; font-size: 11.5px; }
.pc-body b { font-variant-numeric: tabular-nums; }
.pc-foot {
  border-top: 1px dashed var(--line); padding-top: 8px; font-size: 11.5px; color: var(--ink2); line-height: 1.8;
}

/* ============ 人员 ============ */
/* min 取 205px：1440 屏下能让 9 人排成 5+4 两行；取 230px 时只有 4 列，9 人会排成 4+4+1，
   最后一行只剩一个卡片、右侧大片留白，看上去像布局坏了。 */
.staff-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(205px, 1fr)); gap: 12px; }
.staff-card { border: 1px solid var(--line); border-radius: 10px; padding: 12px 14px; background: #fbfcfe; }
.sc-top { display: flex; align-items: center; gap: 10px; margin-bottom: 10px; }
/* 人员卡片头的姓名块与操作区：姓名可截断，操作按钮靠右 */
.sc-name { flex: 1; min-width: 0; }
.sc-name .bold { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.sc-acts { margin-left: auto; display: flex; gap: 2px; flex-shrink: 0; opacity: .45; transition: opacity .15s; }
.staff-card:hover .sc-acts { opacity: 1; }
.sc-acts .el-button { padding: 0 2px; height: 20px; font-size: 11.5px; }
.avatar {
  width: 38px; height: 38px; border-radius: 50%; background: #e8f0ff; color: var(--primary);
  display: flex; align-items: center; justify-content: center; font-weight: 700; font-size: 15px;
}
.sc-body { font-size: 12px; color: var(--ink2); line-height: 1.95; }
.sc-body span { color: var(--ink3); margin-right: 6px; font-size: 11.5px; }

/* ============ 抽屉 ============ */
.drawer-sec {
  margin: 18px 0 10px; font-size: 13px; font-weight: 600; color: var(--ink);
  padding-left: 8px; border-left: 3px solid var(--primary);
}
.drawer-actions {
  margin-top: 18px; padding-top: 14px; border-top: 1px solid var(--line);
  display: flex; gap: 8px; flex-wrap: wrap;
}

/* ============ Element Plus 微调 ============ */
.el-table th.el-table__cell { background: #f8fafd !important; font-weight: 600; color: var(--ink2); }
.el-table .cell { font-size: 12.5px; }
.el-tag { font-size: 11.5px; }
.el-button { font-weight: 500; }
.el-drawer__header { margin-bottom: 4px; font-weight: 600; }
.el-radio-button__inner { font-size: 12.5px; }

/* ============================================================================
   以下为补齐段：HTML 里在用、但此前 style.css 未定义的类。
   缺失会让元素退化成浏览器默认样式（标签没有底色、表格裸奔、加粗失效），
   是「页面比例/观感不对」的一类隐蔽来源 —— 浏览器不报错，只是默默不好看。
   ============================================================================ */

.strong { font-weight: 600; }

/* 状态标签（.tag 配合 green/red/amber/blue/gray 使用） */
.tag {
  display: inline-block; padding: 1px 7px; border-radius: 4px; font-size: 11.5px;
  line-height: 18px; white-space: nowrap;
  background: #eef2f9; color: var(--ink2);
}
.tag.green { background: #e8f6ef; color: #1f7a52; }
.tag.red   { background: #fdeaec; color: #b93f4a; }
.tag.amber { background: #fff4e0; color: #a86f06; }
.tag.blue  { background: #eaf1ff; color: #2559c4; }
.tag.gray  { background: #eef1f6; color: var(--ink3); }

/* 轻量数据表（月报归因分布等用；el-table 用于主数据，这种小表更省空间） */
.tbl { width: 100%; border-collapse: collapse; font-size: 12.5px; }
.tbl th, .tbl td { padding: 8px 10px; border-bottom: 1px solid var(--line); text-align: left; vertical-align: middle; }
.tbl th { font-weight: 600; color: var(--ink2); background: #f8fafd; }
.tbl tbody tr:last-child td { border-bottom: 0; }
.tbl tbody tr:hover td { background: #fafcff; }

/* ============================================================================
   看板等高对齐
   问题：首行左列是一张表、右列是两张图上下叠。el-row 会把两列拉到同高，
   但左列的面板只有内容那么高（389px），右列填满（432px）→ 左下角悬空 43px。
   做法：让带 .fill 的面板撑满列高，表格用 flex:1 吃掉剩余空间。
   ============================================================================ */
.panel.fill { height: 100%; display: flex; flex-direction: column; }
.panel.fill > .el-table,
.panel.fill > .table-wrap { flex: 1; min-height: 0; }

/* 超宽屏收紧内容宽度：避免 KPI 卡片与表格被横向拉得过扁（2560px 时卡片宽高比会到 3.85） */
@media (min-width: 1800px) {
  .main > * { max-width: 1760px; margin-left: auto; margin-right: auto; }
}

/* 构建号：方便现场一眼确认是不是最新版（发版时由 index.html 更新） */
.build-no {
  margin-left: 8px; font-size: 11px; font-weight: 400;
  color: var(--ink3, #9aa4b2); background: #f1f4f9;
  border-radius: 3px; padding: 1px 5px; vertical-align: middle;
}

/* ============ 项目列表：汇总条 + 在线率条 ============ */
.sum-strip {
  display: flex; flex-wrap: wrap; align-items: center; gap: 18px;
  padding: 9px 14px; margin-bottom: 10px;
  background: linear-gradient(90deg, #f7f9fc, #fbfcfe);
  border: 1px solid var(--line, #e6ebf2); border-radius: 8px;
  font-size: 12.5px; color: var(--ink2, #4b5563);
}
.sum-strip b { font-size: 14px; color: var(--ink, #1f2937); margin: 0 2px; }
.sum-strip b.red, .sum-strip .red { color: #d9484a; }
.sum-strip em { font-style: normal; font-size: 11.5px; margin-left: 4px; }
.sum-strip .ss-sep { width: 1px; height: 14px; background: #e2e8f0; }
.sum-strip .hint { margin-left: auto; font-size: 11.5px; color: var(--ink3, #98a2b3); }

.cell-strong { font-weight: 600; font-size: 12.8px; color: var(--ink, #1f2937); }

.rate-cell { display: flex; align-items: center; gap: 7px; }
.rate-bar {
  position: relative; flex: 1; height: 7px; min-width: 52px;
  background: #eef2f7; border-radius: 4px; overflow: visible;
}
.rate-bar i {
  display: block; height: 100%; border-radius: 4px; transition: width .3s;
}
.rate-bar i.good { background: linear-gradient(90deg, #38b26a, #5cc98a); }
.rate-bar i.bad  { background: linear-gradient(90deg, #e5484d, #f2797c); }
.rate-mark {
  position: absolute; top: -3px; width: 2px; height: 13px;
  background: #3a4a5f; opacity: .45; border-radius: 1px;
}
.rate-txt { font-size: 12px; font-weight: 600; min-width: 42px; text-align: right; }
.rate-txt.ok { color: #2f9e5f; }
.rate-txt.red { color: #d9484a; }
.rate-empty { font-size: 11.5px; color: var(--ink3, #98a2b3); }

/* ============ 合同风险 ============ */
.risk-kpis { margin-bottom: 12px; }
.risk-kpis .kpi { border-left: 3px solid #dfe6ef; }
.risk-kpis .kpi.red { border-left-color: #e5484d; }
.risk-kpis .kpi.amber { border-left-color: #e8a33d; }
.risk-kpis .kpi.blue { border-left-color: #4a7fd1; }

.risk-board {
  border: 1px solid var(--line, #e6ebf2); border-radius: 10px;
  background: #fff; overflow: hidden;
}
.risk-board-h {
  display: flex; align-items: center; gap: 12px;
  padding: 10px 14px; background: #fafbfd; border-bottom: 1px solid var(--line, #e6ebf2);
}
.risk-board-h .rb-title { font-size: 13px; font-weight: 600; color: var(--ink, #1f2937); }
.risk-board-h .hint { font-size: 11.5px; color: var(--ink3, #98a2b3); }
.risk-board .el-table { border: none; }
.risk-board .el-table::before { display: none; }

.risk-proj { display: flex; align-items: center; gap: 7px; }
.risk-proj .rp-code { font-size: 13.2px; font-weight: 600; color: var(--ink, #1f2937); }

.days-pill {
  display: inline-block; padding: 2px 9px; border-radius: 11px;
  font-size: 12px; font-weight: 600; line-height: 1.6;
}
.days-pill.critical { background: #fde8e8; color: #c92a2e; border: 1px solid #f7c6c7; }
.days-pill.overdue  { background: #fef1f1; color: #d9484a; border: 1px solid #f8d7d8; }
.days-pill.soon     { background: #fff6e6; color: #b9791d; border: 1px solid #f5e0b8; }

/* 行首色条：过期越久越重 */
.risk-table .el-table__row.risk-row-critical > td:first-child { box-shadow: inset 3px 0 0 #e5484d; }
.risk-table .el-table__row.risk-row-overdue  > td:first-child { box-shadow: inset 3px 0 0 #ef8a8c; }
.risk-table .el-table__row.risk-row-soon     > td:first-child { box-shadow: inset 3px 0 0 #e8b558; }
.risk-table .el-table__row:hover > td { background: #f8fbff !important; }

/* ============ 考核预警：下拉选项计数 + 行首色条 ============ */
.opt-count {
  float: right; margin-left: 12px; font-size: 11.5px;
  color: var(--ink3, #98a2b3);
  background: #f1f4f9; border-radius: 8px; padding: 0 6px; line-height: 17px;
}
.el-select-dropdown__item.is-selected .opt-count { background: #e6f0ff; color: #3a6fd8; }

.alert-row-high > td:first-child { box-shadow: inset 3px 0 0 #e5484d; }
.alert-row-mid  > td:first-child { box-shadow: inset 3px 0 0 #e8a33d; }

/* 表格里 kpi 数字配色补齐（汇总条用到） */
.sum-strip b.amber { color: #b9791d; }

/* ============ 系统设置 ============ */
.hint-box {
  margin-top: 12px; padding: 10px 14px; border-radius: 8px;
  background: #f8fafc; border: 1px solid var(--line, #e6ebf2);
  font-size: 12px; line-height: 1.9; color: var(--ink2, #4b5563);
}
.hint-box code {
  background: #eef2f7; border-radius: 3px; padding: 0 4px; font-size: 11.5px;
}

.perm-tag { margin: 0 4px 4px 0; }

/* 参数分组卡片 */
.cfg-group {
  border: 1px solid var(--line, #e6ebf2); border-radius: 10px;
  background: #fff; overflow: hidden; margin-bottom: 14px;
}
.cfg-group-h {
  display: flex; align-items: baseline; gap: 12px;
  padding: 10px 16px; background: #fafbfd; border-bottom: 1px solid var(--line, #e6ebf2);
}
.cfg-group-h .cgh-title { font-size: 13px; font-weight: 600; color: var(--ink, #1f2937); }
.cfg-group-h .cgh-hint { font-size: 11.5px; color: var(--ink3, #98a2b3); }

.cfg-row {
  display: grid; grid-template-columns: 240px 190px 1fr;
  align-items: center; gap: 16px;
  padding: 12px 16px; border-bottom: 1px dashed #eef2f7;
}
.cfg-row:last-child { border-bottom: none; }
.cfg-row:hover { background: #fbfdff; }
.cfg-name { font-size: 13px; font-weight: 600; color: var(--ink, #1f2937); }
.cfg-input { display: flex; align-items: center; gap: 8px; }
.cfg-unit { font-size: 12px; color: var(--ink3, #98a2b3); }
.cfg-remark { font-size: 12px; color: var(--ink2, #4b5563); line-height: 1.7; }

/* 角色弹窗里的权限分组 */
.perm-groups { width: 100%; }
.perm-group { padding: 8px 0; border-bottom: 1px dashed #eef2f7; }
.perm-group:last-child { border-bottom: none; }
.pg-title {
  font-size: 12px; font-weight: 600; color: var(--ink2, #4b5563);
  margin-bottom: 2px;
}
.pg-remark { font-size: 11px; color: var(--ink3, #98a2b3); line-height: 1.7; }
.pg-remark .pg-r { display: block; }

/* ============ 顶部「项目范围」标签 ============ */
.hd-label { font-size: 12px; color: var(--ink3, #98a2b3); margin-right: -2px; }

/* ============ 看板 · 单项目概况 ============ */
.proj-brief { padding: 14px 16px 16px; }

.pb-head {
  display: flex; align-items: flex-start; justify-content: space-between; gap: 16px;
  padding-bottom: 12px; border-bottom: 1px solid var(--line, #e6ebf2);
}
.pb-name { font-size: 15px; font-weight: 600; color: var(--ink, #1f2937); line-height: 1.5; }
.pb-sub {
  margin-top: 5px; font-size: 11.5px; color: var(--ink3, #98a2b3);
  display: flex; align-items: center; gap: 6px; flex-wrap: wrap;
}
.pb-sub .dot { color: #d0d7e2; }
.pb-rate { text-align: right; flex: 0 0 auto; }
.pb-rate-v { font-size: 22px; font-weight: 700; line-height: 1.2; }
.pb-rate-v.ok { color: #2f9e5f; }
.pb-rate-v.red { color: #d9484a; }

.pb-grid {
  display: grid; grid-template-columns: repeat(4, 1fr);
  gap: 10px 12px; margin-top: 14px;
}
.pb-cell {
  background: #fafbfd; border: 1px solid #eef2f7; border-radius: 8px;
  padding: 8px 10px;
}
.pb-k { font-size: 11px; color: var(--ink3, #98a2b3); margin-bottom: 3px; }
.pb-v { font-size: 17px; font-weight: 600; color: var(--ink, #1f2937); line-height: 1.3; }
.pb-v.small { font-size: 12px; font-weight: 500; }
.pb-v.muted { color: #aab2c0; }
.pb-v.red { color: #d9484a; }
.pb-v.amber { color: #b9791d; }

.pb-penalty {
  margin-top: 12px; padding-top: 10px; border-top: 1px dashed #eef2f7;
  display: flex; gap: 10px; align-items: baseline;
}
.pb-penalty .pb-k { flex: 0 0 auto; }

/* 列表里"点了能筛选"的单元格（如点归口项目只看该项目） */
.link-cell { color: #3a6fd8; cursor: pointer; }
.link-cell:hover { text-decoration: underline; }
