/* ═══ 管理端 · 采集健康 /admin/health + 选品洞察占位 /admin/insights ═══
   只放这两屏独有的规则。共用的在 base.css / components.css / screens.css
   （四大数网格 .headline 与管理条 .adminbar 已经在 screens.css 里）。
   颜色一律取令牌；这一份里出现任何 #hex 都是 bug（tools/selfcheck.py 会查）。

   这一屏的视觉只有一条硬规则：**四类结果靠图案 + 明度双编码，不靠纯色**
   （WCAG 1.4.1）。红只留给严重度，这里一点红都不用 —— 采集结果的四分类
   不是严重度，把 proxy_error 画成红会让人把「我们这边出口抖了」读成事故。 */

.s-health { display: flex; flex-direction: column; gap: var(--space-4); }
.s-health .hslot:empty { display: none; }
.s-health .hbody { display: flex; flex-direction: column; gap: var(--space-4); }

/* 四类结果的四种质地：一次定义，图例 / 竖条 / 合计条 / 表格计数共用同一组。
   定义成变量而不是四份 CSS，是为了让 JS 那边的合计条（chart.js 的 stackBar
   吃的是一个 background 值）与这边的竖条永远是同一种质地 —— 两份必然漂移。 */
.s-health {
  --mix-ok: var(--c-neutral-400);
  --mix-block: repeating-linear-gradient(45deg,
    var(--c-neutral-900) 0 2px, var(--c-neutral-200) 2px 5px);
  --mix-degraded: repeating-linear-gradient(0deg,
    var(--c-neutral-600) 0 2px, var(--c-neutral-100) 2px 4px);
  --mix-proxy: repeating-linear-gradient(90deg,
    var(--c-neutral-800) 0 2px, var(--c-neutral-50) 2px 5px);
}

/* ── 卡 ── */
.s-health .hcard { border: 1px solid var(--border-hairline); border-radius: var(--radius-10);
                   background: var(--c-neutral-0); box-shadow: var(--shadow-card); }
.s-health .hcard > header { display: flex; align-items: baseline; gap: var(--space-3);
                            flex-wrap: wrap; padding: var(--space-3) var(--space-4);
                            border-bottom: 1px solid var(--border-hairline); }
.s-health .hcard > header h3 { font-size: var(--size-md); }
.s-health .pad { padding: var(--space-3) var(--space-4); display: flex;
                 flex-direction: column; gap: var(--space-2); }
.s-health .sub2 { color: var(--c-neutral-500); font-size: var(--size-sm); }
.s-health .foot { margin: 0; font-size: var(--size-11); color: var(--c-neutral-500);
                  line-height: var(--leading-snug); max-width: 92ch; }
.s-health .foot b { font-weight: 600; color: var(--c-neutral-900); }

/* ── 二档异常：就地插、3px 灰左条 + 断线图标、有形无色（红只给一档）── */
.s-health .notice.lvl2 { border-left: 3px solid var(--c-neutral-400); align-items: flex-start; }
.s-health .notice.lvl2 > svg { color: var(--c-neutral-500); flex-shrink: 0; margin-top: 1px; }
.s-health .l2t { font-size: var(--size-md); margin-bottom: var(--space-1); }
.s-health .l2p { margin: 0; font-size: var(--size-base); color: var(--c-neutral-600);
                 line-height: var(--leading-snug); max-width: 88ch; }
.s-health .notice.lvl2 .acts { margin-top: var(--space-2); display: flex; gap: var(--space-2); }

/* ── ③ 四个大数：数 · 正常范围 · 越界怎么办 ──
   「怎么办」那一行是这一屏存在的一半理由：值班的人光看数字判断不了要不要动手。 */
.s-health .headline .sub { font-size: var(--size-11); color: var(--c-neutral-500);
                           margin-bottom: var(--space-2); line-height: var(--leading-snug); }
.s-health .headline .range { font-size: var(--size-11); color: var(--c-neutral-500);
                             margin-bottom: 5px; }
.s-health .headline .todo { font-size: var(--size-sm); line-height: var(--leading-loose);
                            color: var(--c-neutral-600); }
/* 越界只在有阈值的那两个数上变色。出口可用率没有阈值，所以它永远不会拿到 .hit。 */
.s-health .headline > div.hit { border-color: var(--c-severity-high); }

/* ── ④ 近 24 小时 ── */
.s-health .legend { display: flex; align-items: center; gap: var(--space-3); flex-wrap: wrap;
                    font-size: var(--size-11); color: var(--c-neutral-600); }
.s-health .lg { display: inline-flex; align-items: center; gap: 5px; }
.s-health .sw { display: inline-block; width: 11px; height: 11px; border-radius: 2px;
                border: 1px solid var(--c-neutral-200); flex-shrink: 0; }
.s-health .sw.ok { background: var(--mix-ok); }
.s-health .sw.block { background: var(--mix-block); }
.s-health .sw.degraded { background: var(--mix-degraded); }
.s-health .sw.proxy { background: var(--mix-proxy); }

.s-health .mix { display: flex; align-items: flex-end; gap: 3px; height: 104px; }
.s-health .mixcol { flex: 1; min-width: 0; height: 100%; display: flex;
                    flex-direction: column; justify-content: flex-end; align-items: stretch; }
.s-health .mixbar { display: flex; flex-direction: column-reverse; width: 100%;
                    border-radius: 2px 2px 0 0; overflow: hidden;
                    background: var(--c-neutral-50); min-height: 2px; }
.s-health .mixbar i.seg { display: block; width: 100%; }
.s-health .mixbar i.seg.ok { background: var(--mix-ok); }
.s-health .mixbar i.seg.block { background: var(--mix-block); }
.s-health .mixbar i.seg.degraded { background: var(--mix-degraded); }
.s-health .mixbar i.seg.proxy { background: var(--mix-proxy); }
/* 没有采集记录的那一小时：铺满斜纹到顶。**不是零高度的空条** ——
   零高度会被读成「那一小时一次检查都没失败」，而真相是「那一小时我们根本没测」。 */
.s-health .mixbar.none { height: 100%;
  background-image: repeating-linear-gradient(45deg,
    var(--c-provenance-missing-hatch-chart) 0 3px, transparent 3px 8px);
  background-color: transparent; border: 1px dotted var(--c-neutral-200); }
.s-health .hx { display: block; height: 14px; margin-top: 3px; text-align: center;
                font-family: var(--font-mono); font-size: var(--size-xs);
                color: var(--c-neutral-500); overflow: hidden; white-space: nowrap; }

.s-health .mixsum { display: flex; align-items: center; gap: var(--space-3); flex-wrap: wrap;
                    margin-top: var(--space-2); font-size: var(--size-sm);
                    color: var(--c-neutral-600); }
.s-health .mixsum-l { flex-shrink: 0; }
.s-health .mixsum .stackbar { flex: 1; min-width: 140px; }
.s-health .mixsum-n { font-size: var(--size-sm); color: var(--c-neutral-600); }

/* ── ⑤ 停采红线：只陈述，一个按钮都没有 ── */
.s-health .rl { display: flex; align-items: center; gap: var(--space-2); flex-wrap: wrap;
                padding: 6px 0; font-size: var(--size-base);
                border-bottom: 1px solid var(--border-hairline); }
.s-health .rl:last-of-type { border-bottom: 0; }
.s-health .rl > svg { color: var(--c-neutral-500); flex-shrink: 0; }
/* 命中：二档形态。有形无色 —— 3px 灰左条，不用红。 */
.s-health .rl.hit { border-left: 3px solid var(--c-neutral-400); padding-left: var(--space-2);
                    background: var(--c-neutral-25); }
.s-health .rlname { color: var(--c-neutral-900); }
.s-health .rlstate { font-size: var(--size-sm); color: var(--c-neutral-600); }
.s-health .rl.hit .rlstate { font-weight: 600; color: var(--c-neutral-900); }
.s-health .rlsince { margin-left: auto; font-family: var(--font-mono);
                     font-size: var(--size-11); color: var(--c-neutral-500); }

/* ── ⑥ 采集机 ── */
.s-health .kvgrid { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
                    gap: var(--space-2) var(--space-4); }
.s-health .kv { display: flex; align-items: baseline; gap: var(--space-2);
                font-size: var(--size-base); min-width: 0; }
.s-health .kv dt { color: var(--c-neutral-500); flex-shrink: 0; }
.s-health .kv dd { margin: 0; color: var(--c-neutral-900); min-width: 0; }
/* 恢复演练失败：备份存在但恢复不出来 = 没有备份。这一项必须看得出是失败。 */
.s-health .bad { color: var(--c-severity-high); font-weight: 600; }
.s-health .howto { display: flex; flex-direction: column; gap: 4px;
                   border-top: 1px solid var(--border-hairline); padding-top: var(--space-2); }
.s-health .masked { display: flex; flex-direction: column; gap: 4px;
                    border-top: 1px solid var(--border-hairline); padding-top: var(--space-2); }

/* ── ⑦ 每店明细 ── */
.s-health .health-scroll { border: 0; border-top: 1px solid var(--border-hairline);
                           border-radius: 0; max-height: 62vh; overflow: auto; }
/* ⚠️ 必须写成 table.t.health-t：components.css 的 `table.t` 是 (0,1,1)，
   只写 .health-t 会被它的 min-width:720px 压过去，列就被挤扁了 ——
   「容器窄了横向滚动，绝不挤压列」是表格四条硬规则之一。 */
table.t.health-t { min-width: 1180px; }
table.t.health-t th, table.t.health-t td { padding: 8px 10px; vertical-align: top; }
/* 表头允许换行：列窄下来之后「历史被抹掉的值」这种长表头单行放不下，
   而挤压列是表格四条硬规则明令禁止的。两行表头没问题，截断有问题。 */
table.t.health-t th { font-size: var(--size-11); white-space: normal; }
/* 档位一格是上下两行：实测一行、设定一行。并排 + nowrap 会让这一格比列还宽，
   在 table-layout:fixed 下直接压到隔壁列上（实测踩到）。 */
.s-health .tier { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.s-health .tierline { white-space: nowrap; }
.s-health .snm { font-size: var(--size-base); color: var(--c-neutral-900);
                 overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.s-health .sid { font-size: var(--size-11); color: var(--c-neutral-500);
                 overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* 「· 设定 5 分钟」整块换行，不许断在「设 / 定」中间 —— 版式的低级错误。
   宁可让表横向滚动（那是表格四条硬规则允许的），也不折词。 */
.s-health td .sub2 { white-space: nowrap; }
.s-health td.t { font-family: var(--font-mono); font-size: var(--size-11); }
.s-health .sus { font-size: var(--size-sm); color: var(--c-neutral-600); }
/* 连续失败 ≥1：整行进二档形态。形状（左条 + 断线图标 + 一句话）与颜色双编码，
   而这里的「颜色」只到底色深一档为止 —— 二档不用红。 */
.s-health tr.hit { border-left: 3px solid var(--c-neutral-400); background: var(--c-neutral-25); }
.s-health tr.hit > td:first-child { box-shadow: inset 3px 0 0 var(--c-neutral-400); }
.s-health .l2note { display: flex; align-items: center; gap: 4px; margin-top: 3px;
                    font-size: var(--size-11); color: var(--c-neutral-900); }
.s-health .l2note > svg { color: var(--c-neutral-500); flex-shrink: 0; }
/* 四类计数排成 2×2，不让它按剩余宽度乱折 —— 折出来的行数会随数字位数变，
   同一列的行高就跟着抖。顺序与图例一致：成功 / 平台拦截 · 降级 / 代理故障。 */
.s-health .cnts { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));
                  gap: 2px var(--space-2); }
.s-health .cnt { display: inline-flex; align-items: center; gap: 4px;
                 font-size: var(--size-sm); white-space: nowrap; }
.s-health tr:focus-visible { outline-offset: -2px; }

/* ── 选品洞察占位 ──
   空状态骨架：居中 · 留白大 · 无边框 · 一个彩色元素都没有 · 没有进度条。
   进度条只给「还在积累」那一类，因为只有它知道还差几天；这里没人知道，给了就是骗人。 */
.s-health .insights { display: flex; justify-content: center; padding: var(--space-6) 0; }
.s-health .insights .empty { max-width: 78ch; padding: 28px 30px; }   /* GAP insights-pad */
.s-health .insights .hint.wide { max-width: 72ch; text-align: left; }

@media (max-width: 980px) {
  .s-health .mix { height: 84px; }
  .s-health .hx { font-size: var(--size-xs); }
}
