/* 数据管理台样式（沿用小程序新皮肤口径）
 *
 * 口径（与 miniapp 新皮肤一致，也是需求点名的）：
 *   冷灰底 #F5F6F7 / 白面 #FFFFFF / 1px 分隔线 #E7E9EC
 *   墨 #111315 / 次文字 #4B5563 / 强调腾讯蓝 #0052D9
 *   圆角 12px、无阴影、无渐变、无衬线；按钮不用胶囊（12px 圆角）。
 *
 * 只有一条规则例外：抽屉/弹窗的遮罩用半透明黑 —— 那是"层"的表达，
 * 不是装饰，去掉它就看不出"这块内容浮在页面上"。
 */

:root {
  --bg: #f5f6f7;
  --surface: #ffffff;
  --line: #e7e9ec;
  --ink: #111315;
  --muted: #4b5563;
  --accent: #0052d9;
  --accent-weak: #e8f0fe;
  --danger: #d92d20;
  --ok: #0f7b45;
  --warn: #b25e09;
  --radius: 12px;
  --mono: "Cascadia Mono", Consolas, "Courier New", monospace;
}

* {
  box-sizing: border-box;
}

html,
body {
  margin: 0;
  padding: 0;
  height: 100%;
}

body {
  /* 整站骨架：页面就是一条纵向 flex（登录页 / 应用 / 兜底页只显示一个），
   * 高度锁在视口里，滚动交给各区域自己 —— 页面本身永远不出现第二层滚动条。 */
  display: flex;
  flex-direction: column;
  overflow: hidden;
  background: var(--bg);
  color: var(--ink);
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "PingFang SC",
    "Hiragino Sans GB", "Microsoft YaHei", sans-serif;
  font-size: 14px;
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
}

a {
  color: var(--accent);
  text-decoration: none;
}

.hidden {
  display: none !important;
}

/* ---------------------------------------------------------------- 登录页 */

.login {
  flex: 1 1 auto;
  min-height: 0;
  overflow: auto;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px;
}

.login .card {
  width: 100%;
  max-width: 420px;
  padding: 28px;
}

.login h1 {
  margin: 0 0 4px;
  font-size: 20px;
  font-weight: 600;
}

.login .hint {
  color: var(--muted);
  margin: 0 0 20px;
  font-size: 13px;
}

/* ---------------------------------------------------------------- 布局 */

/* 两栏骨架：侧边栏 + 主内容，整体撑满视口剩下的高度（不随内容长短变化） */
.app {
  flex: 1 1 auto;
  min-height: 0;
  display: grid;
  grid-template-columns: 196px 1fr;
}

.sidebar {
  background: var(--surface);
  border-right: 1px solid var(--line);
  padding: 20px 12px;
  display: flex;
  flex-direction: column;
  gap: 4px;
  min-height: 0;
  overflow-y: auto;
}

.brand {
  padding: 0 10px 16px;
  font-weight: 600;
}

.brand small {
  display: block;
  color: var(--muted);
  font-weight: 400;
  font-size: 12px;
}

.nav-item {
  display: block;
  width: 100%;
  text-align: left;
  padding: 9px 12px;
  border: 1px solid transparent;
  border-radius: var(--radius);
  background: transparent;
  color: var(--ink);
  font: inherit;
  cursor: pointer;
}

.nav-item:hover {
  background: var(--bg);
}

.nav-item.active {
  background: var(--accent-weak);
  border-color: #cfe0fb;
  color: var(--accent);
  font-weight: 600;
}

.sidebar-foot {
  margin-top: auto;
  padding: 12px 10px 0;
  border-top: 1px solid var(--line);
  color: var(--muted);
  font-size: 12px;
}

/* 主内容：自己占满剩余高度、自己滚动（侧边栏因此永远不动） */
.main {
  display: flex;
  flex-direction: column;
  min-height: 0;
  overflow: auto;
  /* 纵向照旧可滚；**横向显式关掉** —— 见下方 `.chart .col .tip` 的说明：
   * 趋势图的浮层曾经溢出到这里，让本容器多出一条横向滚动条（+ 可视高度少 15px），
   * 于是"鼠标停在柱子边界"就变成"浮层与滚动条一起闪"。表格自己有
   * `.table-wrap { overflow-x: auto }`，这里本来就不需要横向滚。
   * `scrollbar-gutter: stable` 再把纵向滚动条的位置**预留**出来：
   * 内容高度变化时不会因为滚动条出现/消失而让整页宽度跳 15px（那是另一种闪）。 */
  overflow-x: hidden;
  scrollbar-gutter: stable;
  padding: 24px 28px 48px;
  max-width: 1400px;
}

.page-head {
  flex: none; /* 标题区高度固定，不参与拉伸/压缩 */
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 16px;
  margin-bottom: 16px;
}

.page-head h2 {
  margin: 0;
  font-size: 18px;
  font-weight: 600;
}

.page-head p {
  margin: 2px 0 0;
  color: var(--muted);
  font-size: 13px;
}

/* ------------------------------------------- 页面骨架：卡片不随行数变高
 *
 * 目标：三种情况（0 行 / 2 行 / 20+ 行）看到**同一张卡片**，
 * 高度只由视口决定，切换筛选时整块不会上下跳：
 *   #content 吃掉标题区以下的剩余高度（flex: 1 + min-height: 0）
 *   .list-card 再吃掉 #content 的高度 → 卡片高度 = 视口 − 顶栏 − 标题区
 *   卡片内部：表格区自己滚，脚注与分页条留在原地（分页条贴卡片底部）
 * 用 flex 撑开而不是 calc(100vh − …)：标题区/工具条高度改了也不用改魔法数字。
 */

#content {
  flex: 1 1 auto;
  min-height: 0;
  display: flex;
  flex-direction: column;
}

/* 列表卡片（用户 / 反馈 / 请求的表格卡片）：撑满剩余高度 */
.list-card {
  flex: 1 1 auto;
  min-height: min(420px, 62vh); /* 兜底：请求页下面还有排行卡片时，别把表格压没 */
  display: flex;
  flex-direction: column;
  overflow: hidden; /* 滚动交给内部区域，卡片自己不被内容撑开 */
}

.list-card > .toolbar {
  flex: none;
}

/* 表格 + 脚注 + 分页条的容器：一列到底 */
.list-body {
  flex: 1 1 auto;
  min-height: 0;
  display: flex;
  flex-direction: column;
}

/* 只有表格在滚：工具条、脚注、分页条始终可见 */
.list-body > .table-wrap {
  flex: 0 1 auto;
  min-height: 0;
  overflow: auto;
}

/* 空态 / 错误块：在卡片里横向纵向居中（0 行时卡片高度不变） */
.list-body > .state {
  flex: 1 1 auto;
  min-height: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
}

/* 分页条固定在卡片底部（不是紧贴最后一行） */
.list-body > .pager {
  flex: none;
  margin-top: auto;
  padding-top: 14px;
}

/* ---------------------------------------------------------------- 卡片 / 栅格 */

.card {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 16px 18px;
}

.card + .card {
  margin-top: 16px;
}

.card h3 {
  margin: 0 0 12px;
  font-size: 14px;
  font-weight: 600;
}

.grid {
  display: grid;
  gap: 12px;
}

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

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

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

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

.stat {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 14px 16px;
}

.stat .label {
  color: var(--muted);
  font-size: 13px;
}

.stat .value {
  font-size: 24px;
  font-weight: 600;
  margin-top: 4px;
}

.stat .sub {
  color: var(--muted);
  font-size: 12px;
  margin-top: 2px;
}

/* ---------------------------------------------------------------- 趋势柱状图 */

.chart {
  display: flex;
  align-items: flex-end;
  gap: 4px;
  height: 180px;
  padding-top: 8px;
}

.chart .col {
  flex: 1 1 0;
  min-width: 0;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  height: 100%;
  gap: 2px;
  position: relative;
}

.chart .bar {
  background: var(--accent);
  border-radius: 4px 4px 0 0;
  min-height: 2px;
}

.chart .bar.zero {
  background: var(--line);
}

.chart .col .tip {
  position: absolute;
  bottom: 100%;
  left: 50%;
  transform: translateX(-50%);
  background: var(--ink);
  color: #fff;
  padding: 4px 8px;
  border-radius: 8px;
  font-size: 12px;
  white-space: nowrap;
  display: none;
  z-index: 5;
  /* ↓↓↓ 这三行是"柱子边界 hover 闪烁"的修复（根因与证据见 docs/admin-console.md 第 13 节）：
   *
   * 1. `pointer-events: none` —— 浮层**永不吃鼠标事件**。它虽然挂在 `.col` 里，
   *    但 `bottom: 100%` 把它放到了柱子上方，一旦它参与命中测试，
   *    "光标下的元素"就会在浮层与柱子之间来回切换（自激的必要条件之一）。
   * 2. 溢出交给祖先裁剪（`.main { overflow-x: hidden }`）—— 原先浮层（`nowrap` +
   *    `translateX(-50%)`）对**靠右的柱子**会超出 `#main` 的内边距框，
   *    让 `#main` 多出一条横向滚动条、可视高度少 15px；鼠标停在柱子边界时
   *    `:hover` 反复通断 → 浮层与滚动条一起出现/消失 → 屏幕持续闪烁。
   * 3. 边缘柱子的浮层改为**贴边对齐**（见下方 nth-child 规则），
   *    这样裁剪根本不会发生，右侧柱子的提示仍然完整可读。 */
  pointer-events: none;
}

/* 靠左/靠右各 5 根柱子的浮层改成贴边对齐：整条提示留在图表框内。
 * 为什么是 5：最窄的情况是 30 天视图（30 根柱、每根 ≈38px），
 * 第 6 根柱子中心距图表右缘 ≈ 5.5×38 ≈ 208px > 提示的半宽（约 150px），
 * 所以"外 5 根"足够覆盖所有会越界的柱子；再用 `.tip` 的最大宽度兜底。 */
.chart .col .tip {
  max-width: 320px;
  overflow: hidden;
  text-overflow: ellipsis;
}

.chart .col:nth-child(-n + 5) .tip {
  left: 0;
  transform: none;
}

.chart .col:nth-last-child(-n + 5) .tip {
  left: auto;
  right: 0;
  transform: none;
}

.chart .col:hover .tip {
  display: block;
}

.chart-axis {
  display: flex;
  gap: 4px;
  margin-top: 6px;
}

.chart-axis span {
  flex: 1 1 0;
  text-align: center;
  color: var(--muted);
  font-size: 11px;
  overflow: hidden;
  white-space: nowrap;
}

/* ---------------------------------------------------------------- 表格 */

.table-wrap {
  overflow-x: auto;
}

table {
  width: 100%;
  border-collapse: collapse;
  font-size: 13px;
}

th,
td {
  text-align: left;
  padding: 10px 12px;
  border-bottom: 1px solid var(--line);
  vertical-align: middle;
  white-space: nowrap;
}

th {
  color: var(--muted);
  font-weight: 500;
  background: var(--surface);
}

tbody tr:last-child td {
  border-bottom: none;
}

tbody tr:hover {
  background: #fafbfc;
}

td.wrap {
  white-space: normal;
  max-width: 320px;
}

.mono {
  font-family: var(--mono);
  font-size: 12px;
}

.truncate {
  display: inline-block;
  max-width: 190px;
  overflow: hidden;
  text-overflow: ellipsis;
  vertical-align: bottom;
}

/* ---------------------------------------------------------------- 控件 */

input,
select,
textarea {
  font: inherit;
  color: inherit;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 8px 12px;
  width: 100%;
}

input:focus,
select:focus,
textarea:focus {
  outline: none;
  border-color: var(--accent);
}

select {
  width: auto;
  padding-right: 28px;
}

.btn {
  font: inherit;
  border: 1px solid var(--line);
  background: var(--surface);
  color: var(--ink);
  border-radius: var(--radius);
  padding: 8px 14px;
  cursor: pointer;
}

.btn:hover:not(:disabled) {
  border-color: #cfd3d8;
}

.btn:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

.btn-primary {
  background: var(--accent);
  border-color: var(--accent);
  color: #fff;
}

.btn-primary:hover:not(:disabled) {
  background: #0046ba;
  border-color: #0046ba;
}

.btn-danger {
  color: var(--danger);
}

.btn-danger:hover:not(:disabled) {
  border-color: var(--danger);
}

.btn-sm {
  padding: 5px 10px;
  font-size: 13px;
}

.btn-block {
  width: 100%;
}

.toolbar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px;
  margin-bottom: 14px;
}

.toolbar .field {
  display: flex;
  align-items: center;
  gap: 6px;
  color: var(--muted);
  font-size: 13px;
}

.toolbar .field input,
.toolbar .field select {
  width: auto;
  min-width: 130px;
}

.toolbar .grow {
  flex: 1 1 auto;
}

.spacer {
  flex: 1 1 auto;
}

/* ---------------------------------------------------------------- 徽标 / 状态 */

.badge {
  display: inline-block;
  padding: 2px 8px;
  border-radius: 8px;
  font-size: 12px;
  border: 1px solid var(--line);
  color: var(--muted);
  background: var(--surface);
}

.badge-ok {
  color: var(--ok);
  border-color: #bfe3cf;
  background: #f1faf5;
}

.badge-warn {
  color: var(--warn);
  border-color: #f0d9b5;
  background: #fdf7ee;
}

.badge-danger {
  color: var(--danger);
  border-color: #f3c9c5;
  background: #fdf3f2;
}

.badge-accent {
  color: var(--accent);
  border-color: #cfe0fb;
  background: var(--accent-weak);
}

/* ---------------------------------------------------------------- 状态块（加载/空/错误） */

.state {
  padding: 28px 16px;
  text-align: center;
  color: var(--muted);
}

.state strong {
  display: block;
  color: var(--ink);
  margin-bottom: 4px;
}

.state .actions {
  margin-top: 12px;
}

.skeleton {
  height: 14px;
  border-radius: 6px;
  background: #eef0f2;
  margin: 10px 0;
  animation: pulse 1.2s ease-in-out infinite;
}

@keyframes pulse {
  0%,
  100% {
    opacity: 1;
  }
  50% {
    opacity: 0.55;
  }
}

/* ---------------------------------------------------------------- 分页 */

.pager {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-top: 14px;
  color: var(--muted);
  font-size: 13px;
}

/* ---------------------------------------------------------------- 抽屉 */

.drawer-mask,
.modal-mask {
  position: fixed;
  inset: 0;
  background: rgba(17, 19, 21, 0.35);
  z-index: 40;
}

.drawer {
  position: fixed;
  top: 0;
  right: 0;
  bottom: 0;
  width: min(560px, 94vw);
  background: var(--surface);
  border-left: 1px solid var(--line);
  z-index: 41;
  display: flex;
  flex-direction: column;
}

.drawer header {
  padding: 16px 18px;
  border-bottom: 1px solid var(--line);
  display: flex;
  align-items: center;
  gap: 12px;
}

.drawer header h3 {
  margin: 0;
  font-size: 15px;
}

.drawer .body {
  padding: 16px 18px;
  overflow-y: auto;
}

.kv {
  display: grid;
  grid-template-columns: 120px 1fr;
  gap: 6px 12px;
  margin-bottom: 18px;
  font-size: 13px;
}

.kv dt {
  color: var(--muted);
}

.kv dd {
  margin: 0;
  word-break: break-all;
}

/* ---------------------------------------------------------------- 弹窗 / 提示 */

.modal {
  position: fixed;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: min(420px, 92vw);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 20px;
  z-index: 41;
}

.modal h3 {
  margin: 0 0 8px;
  font-size: 16px;
}

.modal p {
  margin: 0 0 16px;
  color: var(--muted);
}

.modal .actions {
  display: flex;
  justify-content: flex-end;
  gap: 10px;
}

.toasts {
  position: fixed;
  right: 20px;
  bottom: 20px;
  display: flex;
  flex-direction: column;
  gap: 8px;
  z-index: 60;
}

.toast {
  background: var(--surface);
  border: 1px solid var(--line);
  border-left: 3px solid var(--accent);
  border-radius: var(--radius);
  padding: 10px 14px;
  max-width: 360px;
  font-size: 13px;
}

.toast.error {
  border-left-color: var(--danger);
}

.toast.ok {
  border-left-color: var(--ok);
}

/* ================================================================ 新增视图
 *
 * 「IP 流量」「异常与封禁」两页 + 概览小卡 + 顶部状态条 + 账号登录相关。
 * 全部用**新类名**（`guard-*` / `ip-*` / `banner*` / `acct-*`），只做加法 ——
 * 既不动既有骨架（`.main` / `#content` / `.list-card`），也不会和别人的改动打架。
 */

/* ---------------------------------------------------------------- 提示条 */

.banner {
  display: flex;
  align-items: center;
  gap: 10px;
  border: 1px solid var(--line);
  border-left: 3px solid var(--accent);
  border-radius: var(--radius);
  background: var(--surface);
  padding: 10px 14px;
  margin-bottom: 14px;
  font-size: 13px;
}

.banner-warn {
  border-left-color: var(--warn);
  background: #fdf7ee;
  border-color: #f0d9b5;
}

.banner-danger {
  border-left-color: var(--danger);
  background: #fdf3f2;
  border-color: #f3c9c5;
}

.banner .banner-actions {
  margin-left: auto;
  display: flex;
  gap: 8px;
}

/* ---------------------------------------------------------------- 状态条 */

/* 反刷状态条：「检测 开/关 · 模式 真实拦截/dry-run · 自动封禁阈值 N 次/窗口」 */
.guard-strip {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px 18px;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);
  padding: 12px 16px;
  margin-bottom: 14px;
  font-size: 13px;
}

.guard-strip .item {
  display: flex;
  align-items: center;
  gap: 6px;
  color: var(--muted);
}

.guard-strip .item strong {
  color: var(--ink);
  font-weight: 600;
}

.guard-strip .dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--ok);
}

.guard-strip .dot.off {
  background: var(--danger);
}

.guard-strip .dot.dry {
  background: var(--warn);
}

/* ---------------------------------------------------------------- 可点击小卡 */

.stat.clickable {
  cursor: pointer;
  text-align: left;
  font: inherit;
}

.stat.clickable:hover {
  border-color: #cfd3d8;
}

.stat .stat-link {
  color: var(--accent);
  font-size: 12px;
  margin-top: 4px;
}

/* ---------------------------------------------------------------- 异常时间线 */

.timeline {
  border-left: 2px solid var(--line);
  margin: 8px 0 0 4px;
  padding-left: 14px;
}

.timeline-item {
  position: relative;
  padding: 0 0 14px;
}

.timeline-item::before {
  content: '';
  position: absolute;
  left: -20px;
  top: 6px;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--warn);
  border: 2px solid var(--surface);
}

.timeline-item.banned::before {
  background: var(--danger);
}

.timeline-title {
  font-size: 13px;
  font-weight: 600;
}

.timeline-meta {
  color: var(--muted);
  font-size: 12px;
  margin-top: 2px;
}

/* ---------------------------------------------------------------- 常用小件 */

.nowrap {
  white-space: nowrap;
}

.muted {
  color: var(--muted);
}

.small {
  font-size: 12px;
}

.mono-strong {
  font-family: var(--mono);
  font-size: 12px;
  font-weight: 600;
}

/* 倒计时：等宽字体，数字跳动时列宽不抖 */
.countdown {
  font-family: var(--mono);
  font-size: 12px;
}

/* 表单行（手动封禁 / 改密码）：标签 + 控件的紧凑横排 */
.form-row {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: 10px;
}

.form-row .field {
  display: flex;
  flex-direction: column;
  gap: 4px;
  color: var(--muted);
  font-size: 13px;
}

.form-row .field input,
.form-row .field select {
  width: auto;
  min-width: 150px;
}

.form-row .grow {
  flex: 1 1 200px;
}

.form-row .grow input {
  width: 100%;
}

/* 规则说明（阈值来自后端，前端不写死） */
.rule-list {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: 8px 16px;
  margin: 0;
  font-size: 13px;
}

.rule-list div {
  color: var(--muted);
}

.rule-list strong {
  color: var(--ink);
}

/* ---------------------------------------------------------------- 登录页（账号） */

.login .card .signin-row {
  margin-bottom: 12px;
}

.login .card label {
  display: block;
  color: var(--muted);
  font-size: 13px;
  margin-bottom: 4px;
}

.login details summary {
  cursor: pointer;
}

.acct-line {
  display: flex;
  align-items: center;
  gap: 6px;
}

.acct-line .acct-name {
  font-weight: 600;
  color: var(--ink);
  max-width: 120px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* 表格里的次要操作（解封 / 封禁）不要撑高行 */
td .btn + .btn {
  margin-left: 6px;
}

/* ================================================================ 身份 / openid / 强制封禁
 *
 * 这一批（2026-09）新增的三件事：**身份三态切换**、**openid 等宽 + 一键复制**、
 * **强制封禁的红色警示**。全部用新类名，只做加法：
 * 既有的 `.main` / `#content` / `.list-card` 骨架一个字节都没动 ——
 * 所以"卡片不随行数变高""分页条贴底"这些已经调好的行为不会被这批改动带偏。
 */

/* ---------------------------------------------------------------- 身份分段控件 */

/* 三态开关（全部 / 已登录 / 未登录）：用分段按钮而不是下拉 ——
 * 它会被反复切换，一眼看到"现在在看哪一类"比省一点宽度重要。 */
.seg {
  display: inline-flex;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  overflow: hidden;
  background: var(--surface);
}

.seg-btn {
  font: inherit;
  font-size: 13px;
  border: 0;
  border-right: 1px solid var(--line);
  background: var(--surface);
  color: var(--muted);
  padding: 7px 12px;
  cursor: pointer;
}

.seg-btn:last-child {
  border-right: 0;
}

.seg-btn:hover {
  background: var(--bg);
}

.seg-btn.active {
  background: var(--accent-weak);
  color: var(--accent);
  font-weight: 600;
}

/* 会员 / 未登录两个系列的配色：会员用主色，未登录用冷灰 ——
 * 与整站"冷灰底 + 腾讯蓝"的口径一致，不引第三种饱和色。 */
.seg-member {
  background: var(--accent);
}

.seg-guest {
  background: #c3cad4;
}

.seg-member-text {
  color: var(--accent);
  font-weight: 600;
}

.seg-guest-text {
  color: var(--muted);
  font-weight: 600;
}

/* ---------------------------------------------------------------- 趋势图：一根柱子两段 */

/* `.chart .bar` 原本是纯色柱；`bar-split` 是**新类**（老柱子上没有它），
 * 所以这条覆盖规则只作用于"两段柱"，不会影响既有的单色柱。 */
.chart .bar.bar-split {
  background: transparent;
  display: flex;
  flex-direction: column-reverse; /* DOM 里会员在前 → 视觉上会员在下 */
  overflow: hidden;
}

.bar-seg {
  display: block;
  width: 100%;
  min-height: 0;
}

.chart-legend,
.split-legend {
  display: flex;
  flex-wrap: wrap;
  gap: 6px 18px;
  margin-top: 8px;
  color: var(--muted);
  font-size: 12px;
}

.swatch {
  display: inline-block;
  width: 10px;
  height: 10px;
  border-radius: 3px;
  margin-right: 6px;
  vertical-align: middle;
}

.swatch-member {
  background: var(--accent);
}

.swatch-guest {
  background: #c3cad4;
}

/* ---------------------------------------------------------------- 身份构成条 */

.split-bar {
  display: flex;
  height: 10px;
  border-radius: 6px;
  overflow: hidden;
  border: 1px solid var(--line);
}

.split-seg {
  display: block;
  height: 100%;
}

.split-legend strong {
  color: var(--ink);
}

.split-legend > span {
  display: inline-flex;
  align-items: center;
}

/* ---------------------------------------------------------------- openid：等宽 + 复制 */

.copy-cell {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  max-width: 100%;
}

.mono-id {
  font-family: var(--mono);
  font-size: 12px;
  color: var(--ink);
  background: var(--bg);
  border: 1px solid var(--line);
  border-radius: 6px;
  padding: 1px 6px;
  white-space: nowrap;
}

/* 主展示位（用户台账 / 用户流量 / 抽屉的身份列表）：**不截断**，
 * 长 openid 允许在单元格里折行 —— "看得出是谁"优先于列宽好看。 */
.mono-id.mono-full {
  white-space: normal;
  word-break: break-all;
}

.copy-btn {
  font: inherit;
  font-size: 10.5px;
  line-height: 1.5;
  flex: none;
  border: 1px solid var(--line);
  border-radius: 6px;
  background: var(--surface);
  color: var(--muted);
  padding: 0 5px;
  cursor: pointer;
}

.copy-btn:hover {
  border-color: var(--accent);
  color: var(--accent);
}

/* 一格里放多个 openid（异常事件 / 封禁名单的"涉及账号"）：
 * 紧凑排版 + 尽量一行放得下 —— 表格行不能因为一个格子被撑高，
 * 否则一屏能看的异常事件从十几条掉到一两条。 */
.account-cell {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 3px 6px;
  max-width: 360px;
}

.account-cell .mono-id,
.account-cell .copy-btn {
  font-size: 11px;
}

.account-cell .copy-btn {
  padding: 0 4px;
}

.account-cell .copy-cell {
  gap: 2px;
}

/* ---------------------------------------------------------------- 勾选列 / 身份列表 */

th.pick,
td.pick {
  width: 32px;
  padding-right: 0;
}

td.pick input {
  width: auto;
}

.ident-head {
  font-size: 13px;
  margin: 14px 0 6px;
}

.ident-more {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-top: 10px;
}

/* 卡片里的提示条（用户页"游客去哪儿看"）：不参与拉伸，别把表格挤没 */
.list-card > .banner {
  flex: none;
  margin-bottom: 12px;
}

/* 「异常与封禁」页的**两张列表卡**：页面上有状态条 + 规则卡（约 230px）先占掉高度，
 * 剩下的高度两张卡竞争 —— 上面那张（异常事件）原来写死 `min-height:280px`，
 * 于是下面那张（封禁名单）只剩 260px，表格被压到只有表头（行都在，但一行都看不见）。
 * 这里给两张卡**各自**一个够用的最小高度（都是**新类名**，不动 `.list-card` 骨架），
 * 装不下时由 `.main` 自己滚动 —— 看不到数据的"固定骨架"没有意义。 */
.list-card.anomaly-card,
.list-card.ban-card {
  min-height: min(400px, 58vh);
}

/* ---------------------------------------------------------------- 高风险警示块 */

/* 强制封禁的红色警示：写清"封了会怎样、怎么救回来"。
 * `pre-line` 让确认框里的多行文案真的换行（普通说明仍然是一行灰字）。 */
.modal-alert {
  border: 1px solid #f3c9c5;
  border-left: 3px solid var(--danger);
  border-radius: var(--radius);
  background: #fdf3f2;
  color: #8a1f16;
  padding: 10px 12px;
  margin: 0 0 16px;
  font-size: 12.5px;
  line-height: 1.6;
  white-space: pre-line;
  word-break: break-all;
}

