/* ══════════════════════════════════════════════════════════════════════════
   app.css — 页面层（方向 B · 现代工具风）
   ──────────────────────────────────────────────────────────────────────────
   职责：只放「某个页面专属」的样式与历史遗留类名。
        可复用组件在 components.css，令牌在 tokens.css。

   历史类名（.alert-banner / .stat-card / .remark-cell / .auto-cell /
   .detail-table / .qr-box / .login-wrap）暂时保留原名 —— 逐页改造阶段再逐步
   换成 .fz-* 组件类。保留的意义是：本阶段页面的 EJS 一行都不用动，
   换肤就已经生效；改名放到逐页阶段做，任何一步出问题都能单独回滚。
   ══════════════════════════════════════════════════════════════════════════ */

/* ══════════════════ 顶部提醒条（第 9 条：全站常态醒目）══════════════════
   这条横幅是拿真实失败换来的（目标服务是单会话的，用户一登录这边就掉线），
   所以「醒目」是需求，不是装饰：暖底 + 左侧强调色条 + 加粗标题，且不可被
   主题弱化成普通提示。 */
.alert-banner {
  background: var(--fz-warn-soft);
  border-bottom: 1px solid color-mix(in srgb, var(--fz-warn) 26%, transparent);
  border-left: 4px solid var(--fz-warn);
  padding: 11px 0;
}
.alert-banner-inner {
  max-width: var(--fz-w-page);
  margin: 0 auto;
  padding: 0 var(--fz-s5);
  display: flex;
  align-items: center;
  gap: var(--fz-s3);
}
.alert-banner-icon { color: var(--fz-warn); flex: none; display: flex; }
.alert-banner-text { flex: 1; color: color-mix(in srgb, var(--fz-warn) 82%, var(--fz-fg)); line-height: 1.5; }
.alert-banner-text strong { color: var(--fz-warn); font-size: var(--fz-fs-table); font-weight: 680; }
.alert-banner-sub { color: color-mix(in srgb, var(--fz-warn) 62%, var(--fz-fg)); font-weight: 400; }
.alert-banner-close {
  flex: none; border: 1px solid transparent; background: transparent;
  color: color-mix(in srgb, var(--fz-warn) 70%, var(--fz-fg));
  font-size: 19px; line-height: 1; cursor: pointer;
  padding: 2px 9px; border-radius: 7px;
  transition: background-color var(--fz-dur-1) var(--fz-ease);
}
.alert-banner-close:hover { background: color-mix(in srgb, var(--fz-warn) 14%, transparent); }
@media (max-width: 767.98px) {
  .alert-banner-sub { display: none; }
  .alert-banner-inner { padding: 0 var(--fz-s3); }
}

/* ══════════════════ 统计卡（仪表盘）══════════════════
   注意：仪表盘那段 DOM 被 scripts/build-oss.js 的裁剪锚点冻结，
   这里只能靠 CSS 改观感，不能动结构。所以统计卡的数字直接就是
   `<div class="stat-num" id="s-total">128</div>`，没有中间包装层。 */
.stat-card {
  transition: transform var(--fz-dur-1) var(--fz-ease), box-shadow var(--fz-dur-1) var(--fz-ease);
}
@media (hover: hover) and (pointer: fine) {
  .stat-card:hover { transform: translateY(-1px); box-shadow: var(--fz-sh-2); }
}
.stat-num { font-size: var(--fz-fs-stat); font-weight: 680; line-height: 1.15; letter-spacing: -.02em; }
.stat-label { font-size: var(--fz-fs-sm); color: var(--fz-muted); margin-top: 0; }
.stat-foot { font-size: var(--fz-fs-micro); color: var(--fz-dim); margin-top: 8px; }
.stat-total   .stat-num { color: var(--fz-fg); }
.stat-ok      .stat-num { color: var(--fz-ok); }
.stat-partial .stat-num { color: var(--fz-warn); }
.stat-warn    .stat-num { color: var(--fz-warn); }
.stat-danger  .stat-num { color: var(--fz-danger); }
.stat-muted   .stat-num { color: var(--fz-dim); }

/* 「实时」角标上的状态点。
   liveBadge 那行 HTML 被 build-oss 的裁剪锚点冻结（class 串不能改），
   所以圆点只能用伪元素加，好处是它能自动跟着 setLive() 切换的颜色走。 */
#liveBadge::before {
  content: "";
  width: 6px; height: 6px; border-radius: 50%;
  background: currentColor; flex: none;
}
#liveBadge:has(.fz-led)::before { display: none; }

/* ══════════════════ 行内编辑单元格 ══════════════════ */
.remark-cell { cursor: text; border-radius: var(--fz-r-sm); transition: background-color var(--fz-dur-1) var(--fz-ease); }
.remark-cell:hover { background: var(--fz-sunken); }
.remark-cell:focus-visible { outline: 2px solid var(--fz-accent); outline-offset: -2px; }
.remark-cell .remark-text { display: inline; }
.auto-cell { cursor: pointer; }
.auto-cell:hover { background: var(--fz-sunken); }
/* 可一键复制的小单元格（ui.js 的 [data-copy] 委托负责实际复制） */
.copyable { cursor: copy; }

/* ══════════════════ 详情表（账号详情 / 设置 / 结果卡）══════════════════ */
.detail-table { width: 100%; font-size: var(--fz-fs-table); }
.detail-table > tbody > tr > th {
  width: 34%; text-align: left; font-weight: 600; color: var(--fz-muted);
  font-size: var(--fz-fs-sm); padding: 9px 12px 9px 0; vertical-align: top;
  background: transparent; border-bottom: 1px solid var(--fz-line);
}
.detail-table > tbody > tr > td { padding: 9px 0; border-bottom: 1px solid var(--fz-line); }
.detail-table > tbody > tr:last-child > th,
.detail-table > tbody > tr:last-child > td { border-bottom: 0; }
.detail-table.table-sm > :not(caption) > * > * { padding: 9px 0; }

/* 详情页可编辑字段 */
.edit-cell { cursor: text; border-radius: var(--fz-r-sm); transition: background-color var(--fz-dur-1) var(--fz-ease); }
.edit-cell:hover { background: var(--fz-sunken); }

/* ══════════════════ 登录页 ══════════════════ */
.login-wrap { min-height: 74vh; }
.login-card {
  background: var(--fz-surface); border: 1px solid var(--fz-line);
  border-radius: var(--fz-r-lg); box-shadow: var(--fz-sh-2); padding: var(--fz-s5);
}
.login-brand { text-align: center; margin-bottom: var(--fz-s5); }
.login-brand .fz-brand-mark {
  width: 34px; height: 34px; border-radius: 11px; margin: 0 auto 10px;
  background: var(--fz-accent); color: var(--fz-accent-fg);
  display: grid; place-items: center; font-size: 16px; font-weight: 700;
}
.login-brand h1 { font-size: 19px; font-weight: 680; }
.login-brand .login-sub { font-size: var(--fz-fs-sm); color: var(--fz-muted); letter-spacing: .04em; }

/* ══════════════════ 二维码区（上号页）═════════════════ */
.qr-box {
  border: 1px dashed var(--fz-line-2);
  border-radius: var(--fz-r);
  min-height: 240px;
  display: flex; align-items: center; justify-content: center;
  background: var(--fz-surface);
  padding: var(--fz-s4);
}
.qr-box img { max-width: 100%; border-radius: var(--fz-r-sm); }

/* 步骤清单（上号页）：编号用等宽小方块，比默认的 ol 数字清楚得多 */
.fz-steps { list-style: none; margin: 0; padding: 0; display: grid; gap: 10px; }
.fz-steps > li { display: grid; grid-template-columns: 22px 1fr; gap: 10px; align-items: start; font-size: var(--fz-fs-table); }
.fz-steps .n {
  width: 22px; height: 22px; border-radius: 7px; flex: none;
  background: var(--fz-sunken); color: var(--fz-muted);
  display: grid; place-items: center;
  font-family: var(--fz-font-mono); font-size: 11.5px; font-weight: 600;
}
.fz-steps > li.is-now .n { background: var(--fz-accent); color: var(--fz-accent-fg); }

/* ══════════════════ 调度 / 引擎面板（仪表盘）══════════════════ */
.sched-log {
  font-family: var(--fz-font-mono);
  font-size: var(--fz-fs-sm);
  max-height: 110px;
  overflow: auto;
  background: var(--fz-sunken);
  border-radius: var(--fz-r-sm);
  padding: 8px 10px;
}

/* ══════════════════ 错误页 ══════════════════ */
.fz-error-code {
  font-size: 68px; font-weight: 700; line-height: 1;
  letter-spacing: -.03em;
  background: linear-gradient(180deg, var(--fz-fg) 0%, var(--fz-dim) 130%);
  -webkit-background-clip: text; background-clip: text; color: transparent;
}

/* ══════════════════ 页脚 ══════════════════ */
footer.fz-footer {
  border-top: 1px solid var(--fz-line);
  margin-top: var(--fz-s6);
  padding: var(--fz-s4) var(--fz-s5);
  color: var(--fz-dim);
  font-size: var(--fz-fs-sm);
  display: flex; gap: var(--fz-s4); flex-wrap: wrap; align-items: center;
  max-width: var(--fz-w-page); margin-left: auto; margin-right: auto;
}
footer.fz-footer .fz-footer-right { margin-left: auto; }
