/* ==========================================================================
   GEO 采样调度中心 · 设计系统
   --------------------------------------------------------------------------
   零依赖、无框架、无 bootstrap（任务书 §4.1）。全部手写。

   这套样式的目标不是「好看」，是「看起来值钱」。B2B 后台的廉价感通常来自
   五个地方，下面每条都对着一个具体手法：

     1. 数字不等宽导致列参差      → 全局 tabular-nums
     2. 到处重阴影，脏            → 用 1px 描边承担层级，阴影只到 .04
     3. 主色铺满全屏              → 主色只在「动作」和「当前项」出现
     4. 字号跳变大、行高随意      → 固定字阶，正文 1.6 / 数字 1.2
     5. 状态没有语义色，全靠文字   → 语义色成对（底 + 边 + 字），三档明度

   改动约定：只改视觉，不改类名。视图依赖的类名是公开接口，删一个页面就塌。
   ========================================================================== */

:root {
    /* ── 中性色：偏冷，跟精密仪器行业更搭 ─────────────────────────── */
    --bg:          #f3f4f7;
    --surface:     #ffffff;
    --surface-2:   #fafbfc;
    --surface-3:   #f5f6f8;
    --line:        #e7e9ee;
    --line-2:      #dce0e6;
    --line-3:      #cbd1d9;

    --text:        #14181f;
    --text-2:      #4d5560;
    --text-3:      #858d99;
    --text-4:      #a8afb9;

    /* ── 语义色：主色只在动作与当前项上出现 ───────────────────────── */
    --accent:      #2563eb;
    --accent-h:    #1d4ed8;
    --accent-soft: #eef4ff;
    --accent-line: #c9dbff;

    --ok:          #0f9f6e;
    --ok-soft:     #e8f9f1;
    --ok-line:     #b5ebd3;

    --warn:        #b45309;
    --warn-soft:   #fff8eb;
    --warn-line:   #fbe2b0;

    --bad:         #d92d20;
    --bad-soft:    #fef3f2;
    --bad-line:    #fccfcb;

    /* ── 深色侧栏 ─────────────────────────────────────────────────── */
    --side:        #0d1117;
    --side-2:      #161c26;
    /* 侧栏浅色文字的两档明度。
       原来是 .66 / .26 两档，实测对比度 8.5 / 2.3 —— 分组标题那档只有 2.3，
       而 WCAG AA 对正文的门槛是 4.5。深色底上的浅字还有个额外的视觉损失：
       白字在近黑背景上会「外溢」，同一字号看着比浅底上细一圈，所以理论
       对比度够了也还是会觉得糊。两档都往上提，并新增 --side-text-2 专门
       给分组标题 / 副名 / 页脚这类次级信息，不再各处散写 rgba。 */
    --side-text:   rgba(255, 255, 255, .82);   /* 菜单项 · 约 12.7:1 */
    --side-text-2: rgba(255, 255, 255, .52);   /* 分组 · 副名 · 页脚 · 约 5.6:1 */
    --side-line:   rgba(255, 255, 255, .07);

    /* ── 尺度 ─────────────────────────────────────────────────────── */
    --r-sm: 7px;
    --r-md: 9px;
    --r-lg: 12px;
    --r-xl: 16px;

    /* 阴影只做到「几乎看不见」，层级交给描边 */
    --sh-1: 0 1px 2px rgba(16, 24, 40, .04), 0 1px 3px rgba(16, 24, 40, .03);
    --sh-2: 0 4px 12px rgba(16, 24, 40, .06), 0 1px 3px rgba(16, 24, 40, .04);
    --sh-3: 0 12px 32px rgba(16, 24, 40, .10), 0 2px 8px rgba(16, 24, 40, .04);

    --ease: cubic-bezier(.4, 0, .2, 1);
    --mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, "Liberation Mono", monospace;

    --side-w: 228px;
    --top-h: 60px;
}

* { box-sizing: border-box; }

html, body {
    margin: 0;
    padding: 0;
    background: var(--bg);
    color: var(--text);
    font: 14px/1.6 "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", "PingFang SC",
          "Hiragino Sans GB", "Microsoft YaHei", sans-serif;
    /* 数字等宽：表格里的 8 / 12 / 100 不对齐是廉价感第一大来源 */
    font-variant-numeric: tabular-nums;
    font-feature-settings: "tnum" 1;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
}
/* 页面底色带一点点顶部光：白卡片浮起来，而不是贴在一块死灰上 */
body {
    background-image: radial-gradient(1100px 520px at 22% -8%, #eef2f9 0%, rgba(238, 242, 249, 0) 62%);
    background-attachment: fixed;
    background-repeat: no-repeat;
}

a { color: var(--accent); text-decoration: none; transition: color .15s var(--ease); }
a:hover { text-decoration: none; color: var(--accent-h); }

/* 注意：背景和边框只给 code，不给 .mono。
   .mono 是「用等宽字体」的标记，表格单元格 td.mono 也用它 ——
   把 code 的外观套上去，整列数字就会变成带框的小方块，一眼廉价。 */
code, .mono { font-family: var(--mono); font-size: 12.5px; }
code {
    background: var(--surface-3);
    border: 1px solid var(--line);
    border-radius: 5px;
    padding: .5px 5px;
}

::selection { background: var(--accent-line); color: var(--accent-h); }

/* 滚动条：默认那条粗灰条最毁质感 */
::-webkit-scrollbar { width: 8px; height: 8px; }
::-webkit-scrollbar-thumb { background: #cfd4db; border-radius: 4px; border: 2px solid transparent; background-clip: content-box; }
::-webkit-scrollbar-thumb:hover { background: #b4bac3; background-clip: content-box; }
::-webkit-scrollbar-track { background: transparent; }

/* ================================================================ 布局 */

.shell { display: flex; min-height: 100vh; }

.sidebar {
    width: var(--side-w);
    flex: 0 0 var(--side-w);
    background: linear-gradient(180deg, var(--side) 0%, #0f1520 100%);
    padding: 0 12px 14px;
    position: sticky;
    top: 0;
    height: 100vh;
    overflow-y: auto;
    display: flex;
    flex-direction: column;
    /* 侧栏右侧一条高光边，把深色块与浅色内容区分开 */
    box-shadow: inset -1px 0 0 rgba(255, 255, 255, .06);
}
.sidebar::-webkit-scrollbar-thumb { background: rgba(255, 255, 255, .14); background-clip: content-box; }

.brand {
    display: flex; align-items: center; gap: 10px;
    /* 字号提到 14.5 之后侧栏整列变高，1366×768 会溢出 48px ——
       底部「站点」「渠道」两项被推出视口，得滚才看得见。
       亏空从各处间距里匀出来，一个字都不往小改：品牌区 20/22 → 14/16。 */
    padding: 14px 10px 16px;
    margin-bottom: 4px;
    font-weight: 600; font-size: 14.5px; letter-spacing: -.01em;
    color: #fff;
    border-bottom: 1px solid var(--side-line);
}
.brand .dot {
    width: 26px; height: 26px; border-radius: 8px; flex: 0 0 26px;
    background: linear-gradient(140deg, #4f8dff 0%, #2563eb 55%, #6d3cf5 100%);
    box-shadow: 0 2px 8px rgba(37, 99, 235, .45), inset 0 1px 0 rgba(255, 255, 255, .3);
    position: relative;
}
/* 方块里挖一个小孔，像个仪表刻度，比纯色块有信息量 */
.brand .dot::after {
    content: ''; position: absolute; inset: 50% auto auto 50%;
    width: 8px; height: 8px; margin: -4px 0 0 -4px;
    border-radius: 50%; background: var(--side);
}
.brand small {
    display: block; font-weight: 400; font-size: 11.5px;
    color: var(--side-text-2); letter-spacing: .02em; margin-top: 2px;
}

.nav-group {
    margin: 12px 0 4px; padding: 0 10px;
    font-size: 11.5px; font-weight: 600; text-transform: uppercase;
    color: var(--side-text-2); letter-spacing: .09em;
}

.nav { display: flex; flex-direction: column; gap: 1px; }

.nav a {
    display: flex; align-items: center; gap: 10px;
    padding: 8px 10px; border-radius: var(--r-sm);
    color: var(--side-text); font-size: 14.5px; font-weight: 500;
    position: relative;
    transition: background .15s var(--ease), color .15s var(--ease);
}
.nav a:hover { background: rgba(255, 255, 255, .07); color: #fff; }
.nav a.on {
    background: linear-gradient(90deg, rgba(37, 99, 235, .22), rgba(37, 99, 235, .06));
    color: #fff; font-weight: 550;
}
/* 激活项的左侧指示条：比整块变蓝克制得多 */
.nav a.on::before {
    content: ''; position: absolute; left: 0; top: 50%; transform: translateY(-50%);
    width: 2.5px; height: 16px; border-radius: 0 3px 3px 0;
    background: #4f8dff; box-shadow: 0 0 8px rgba(79, 141, 255, .7);
}
.nav a svg { width: 18px; height: 18px; flex: 0 0 18px; opacity: .9; }
.nav a.on svg { opacity: 1; color: #6ea2ff; }
.nav a .badge { margin-left: auto; font-size: 11.5px; color: var(--side-text-2); font-weight: 500; }

/* 侧栏底部版本号，给深色块一个收口 */
.side-foot {
    margin-top: auto; padding: 10px 10px 2px;
    font-size: 11.5px; color: var(--side-text-2);
    border-top: 1px solid var(--side-line);
    display: flex; justify-content: space-between; gap: 8px;
}

.main { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; }

.topbar {
    display: flex; align-items: center; justify-content: space-between; gap: 16px;
    padding: 0 28px;
    height: var(--top-h);
    background: rgba(255, 255, 255, .82);
    backdrop-filter: saturate(180%) blur(12px);
    border-bottom: 1px solid var(--line);
    position: sticky; top: 0; z-index: 20;
}
.topbar h1 {
    font-size: 16.5px; margin: 0; font-weight: 600;
    letter-spacing: -.015em; color: var(--text);
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.topbar .sub { color: var(--text-3); font-size: 12.5px; margin-top: 2px; }
.topbar > div:first-child { min-width: 0; }

/* 站点切换器：多站点时才出现 */
.sitesw { display: inline-flex; align-items: center; gap: 7px; }
.sitesw > span { font-size: 12px; color: var(--text-3); white-space: nowrap; }
.sitesw select {
    width: auto; min-width: 148px;
    height: 32px; padding: 0 28px 0 10px;
    font-size: 12.5px;
    background-color: var(--surface);
    background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%23858d99' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");
    background-repeat: no-repeat; background-position: right 9px center;
    appearance: none; -webkit-appearance: none;
    border-radius: var(--r-sm);
}
.sitesw select:hover { border-color: var(--line-3); }

/* 内容区：顶栏在滚动区之上，正文统一 28px 内边距 */
/* min-width:0 不能省：flex 子项默认 min-width:auto，内容比视口宽时
   它拒绝收缩 —— 宽表格会把整页顶出横向滚动条，而卡片自己看起来完全正常。 */
.content { padding: 22px 28px 60px; flex: 1 1 auto; min-height: 0; }
.content > .card:last-child, .content > .help:last-child { margin-bottom: 0; }

/* 淡入：切页面时不闪一下白
   填充模式用 backwards，不用 both。
   both 会把终态的 transform 永久留在元素上（计算值是 matrix(1,0,0,1,0,0)，
   哪怕 keyframe 里写的是 none），而「有 transform 的祖先」是 position:fixed
   的参照物 —— 窄屏那条批量操作条（fixed 贴视口底）就会改成相对卡片定位，
   滚到表格中部时整条跑到屏幕外。
   backwards 只在动画开始前应用首帧，结束后回到元素自身的样式，没有这个问题。 */
@keyframes rise {
    from { opacity: 0; transform: translateY(6px); }
    to   { opacity: 1; transform: none; }
}
.content > .card, .content > .kpis, .content > .alert {
    animation: rise .28s var(--ease) backwards;
}

/* ================================================================ 卡片 */

.card {
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: var(--r-lg);
    box-shadow: var(--sh-1);
    margin-bottom: 18px;
    overflow: hidden;
    transition: box-shadow .2s var(--ease), border-color .2s var(--ease);
}
.card:hover { box-shadow: var(--sh-2); border-color: var(--line-2); }

.card > .hd {
    padding: 14px 18px;
    border-bottom: 1px solid var(--line);
    display: flex; align-items: center; justify-content: space-between; gap: 12px;
    background: linear-gradient(180deg, #fdfdfe, #fbfcfd);
}
.card > .hd h2 {
    font-size: 14px; margin: 0; font-weight: 600;
    letter-spacing: -.005em; color: var(--text);
    display: flex; align-items: center; gap: 7px;
}
/* 标题前的小竖条，比加粗更能分出层级 */
.card > .hd h2::before {
    content: ''; width: 3px; height: 13px; border-radius: 2px;
    background: var(--accent); opacity: .75;
    flex: 0 0 3px;
}
.card > .hd .hint { font-size: 11.5px; color: var(--text-3); font-weight: 400; }
.card > .bd { padding: 18px; }
.card > .bd.tight { padding: 0; }

/* tight 卡片（正文是表格的那种）必须放开 overflow。
   ---------------------------------------------------------------------------
   .card 上的 overflow:hidden 本来只为裁圆角，代价是它把卡片变成了
   position:sticky 的「滚动容器」—— 而这层容器自己不会滚，
   于是卡片里所有 sticky 全部静默失效：表头吸顶（thead th top:0）
   和批量条吸底（.bulkbar bottom:0）都变成「写了但没作用」。

   这类失效最难查：CSS 没报错、选择器命中、计算样式也对，
   只是滚动时元素跟着一起走。所以宁可用两行圆角代偿换回 sticky。 */
.card-tight { overflow: visible; }
.card-tight > .hd {
    border-radius: calc(var(--r-lg) - 1px) calc(var(--r-lg) - 1px) 0 0;
}

/* ================================================================ KPI */

.kpis {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(168px, 1fr));
    gap: 14px;
    margin-bottom: 18px;
}
.kpi {
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: var(--r-lg);
    padding: 15px 17px 14px;
    box-shadow: var(--sh-1);
    position: relative;
    overflow: hidden;
    transition: transform .2s var(--ease), box-shadow .2s var(--ease), border-color .2s var(--ease);
}
.kpi:hover { transform: translateY(-1px); box-shadow: var(--sh-2); border-color: var(--line-2); }
/* 顶部一道极细的主色渐变，作为「这是重点数据」的暗示 */
.kpi::before {
    content: ''; position: absolute; inset: 0 0 auto 0; height: 2px;
    background: linear-gradient(90deg, var(--accent), rgba(109, 60, 245, .5));
    opacity: 0; transition: opacity .2s var(--ease);
}
.kpi:hover::before { opacity: 1; }

.kpi .label {
    font-size: 11.5px; color: var(--text-3); font-weight: 500;
    letter-spacing: .02em;
    display: flex; align-items: center; gap: 6px;
}
.kpi .value {
    font-size: 27px; font-weight: 650; line-height: 1.15;
    letter-spacing: -.03em; margin: 6px 0 3px;
    color: var(--text);
}
.kpi .value small { font-size: 12.5px; font-weight: 500; color: var(--text-3); margin-left: 3px; letter-spacing: 0; }
.kpi .value.tone-ok { color: var(--ok); }
.kpi .value.tone-bad { color: var(--bad); }
.kpi .value.tone-warn { color: var(--warn); }
.kpi .foot { font-size: 11.5px; color: var(--text-4); line-height: 1.5; }

/* ================================================================ 表格 */

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

thead th {
    text-align: left; font-weight: 600; color: var(--text-2);
    background: linear-gradient(180deg, #f8f9fb, #f1f3f6);
    border-bottom: 1px solid var(--line);
    padding: 9px 14px; white-space: nowrap;
    font-size: 11.5px; letter-spacing: .04em;
    /* 顶栏是 sticky top:0、z-index 20 的半透明毛玻璃条。
       表头如果也贴 0，会被它压在下面（看起来像「没吸顶」）。
       所以让出 --top-h，并且 z-index 必须低于顶栏。 */
    position: sticky; top: var(--top-h); z-index: 2;
}
/* 表格行高：11px 是「宽松」档，一屏只能放 12 行左右。
   后台表格的信息密度比呼吸感重要 —— 老板要在不看滚动条的前提下比完 5 家竞品。
   9px 一行省 4px，8 行就是 32px，刚好能多露出一行。 */
tbody td {
    padding: 9px 14px;
    border-bottom: 1px solid #f1f3f6;
    vertical-align: middle;
    color: var(--text);
}
tbody tr:last-child td { border-bottom: none; }
tbody tr { transition: background .12s var(--ease); }
tbody tr:hover { background: #f8faff; }
thead th:first-child, tbody td:first-child { padding-left: 18px; }
thead th:last-child, tbody td:last-child { padding-right: 18px; }

td.num, th.num { text-align: right; font-variant-numeric: tabular-nums; }
td.mono, th.mono { font-family: var(--mono); font-size: 12px; }
td .sub { color: var(--text-3); font-size: 11.5px; display: block; margin-top: 1px; }
/* 分数 + 等级必须排在同一行。用 .sub 会把等级挤到下一行、还左对齐 ——
   一眼看过去像「C 单独占了一格」，读的人要先愣一下才反应过来那是等级。 */
.score-w { white-space: nowrap; }
.score-w .g { color: var(--text-3); font-size: 11.5px; margin-left: 3px; }
tbody td code { background: transparent; border: none; padding: 0; color: var(--text-2); }

/* ---- 批量勾选 -------------------------------------------------------------
   表格里第一条/最后一条的 18px 内边距是为文字留的，勾选列不需要 ——
   勾选框贴着那 18px 会让整列看起来缩进了一大截，跟表头对不齐。 */
.tbl-bulk { position: relative; }
/* 小屏横向滚动：列多的表在 390 宽下会被撑到 600+，右侧「操作」列
   整体出界 —— 表格看着正常，按钮点不到。桌面保持 visible，
   否则每张表都成滚动容器，thead 的 sticky 会当场失效。 */
.tbl-pick th.pk,
.tbl-pick td.pk { width: 42px; padding-left: 18px; padding-right: 0; }
.tbl-pick thead th.pk { padding-top: 0; padding-bottom: 0; }
.tbl-pick tbody tr.is-picked { background: #f7f9ff; }

/* 自绘勾选框。系统的原生 checkbox 在浅色表格里偏软（圆角 + 灰边），
   和这一版「细线 + 硬角」的语言不同；这里统一成 16px 方形，
   选中填近黑而不是填主色 —— 一屏可能勾十几行，填蓝会满屏发亮。

   边框色为什么不能用 --line-3（#cbd1d9）：
   白底上它的对比度只有 1.5:1，1px 的线在 2x 屏上等于消失 ——
   功能明明做好了，用的人却报「没有勾选删除」。看不见 = 没有。
   这里用 #8b94a2，约 3.1:1，刚好过 WCAG 非文本对比度 3:1 的线：
   看得见，又不至于抢过正文。 */
.ck {
    -webkit-appearance: none; appearance: none;
    width: 16px; height: 16px; margin: 0; vertical-align: -3px;
    border: 1.5px solid #7c8695; border-radius: 3.5px;
    background: linear-gradient(180deg, #fff, #f4f6f8);
    cursor: pointer; position: relative;
    box-shadow: inset 0 1px 1px rgba(20, 24, 31, .04);
    transition: background .12s var(--ease), border-color .12s var(--ease);
}
/* 点击热区比视觉尺寸大一圈：16px 的方块要精确点到左上一角，
   对触控板不友好。伪元素透明、不占位，纯扩热区。 */
.ck::before { content: ''; position: absolute; inset: -7px; }
.ck:hover { border-color: var(--text-2); }
/* 整行悬停时把勾选框一起提亮 —— 鼠标停在哪一行，哪一行的
   「这里能勾」就应该亮起来，不用先去瞄准那个小方块。 */
.tbl-pick tbody tr:hover .ck { border-color: var(--text-2); }
.ck:checked,
.ck:indeterminate { background: var(--text); border-color: var(--text); }
.ck:checked::after {
    content: ''; position: absolute; left: 4px; top: 1px;
    width: 4px; height: 8px;
    border: solid #fff; border-width: 0 1.5px 1.5px 0;
    transform: rotate(45deg);
}
/* 半选态画横杠：全选/部分选必须能一眼分开，
   否则「勾了 3 条」和「全选」在视觉上没有区别 */
.ck:indeterminate::after {
    content: ''; position: absolute; left: 3px; top: 6px;
    width: 7px; height: 1.5px; background: #fff;
}

/* 批量操作条：没有勾选时完全不占位（display:none，不是 opacity:0）——
   常年挂一条灰色的「已选 0 条」是后台里最没用的那行字。
   有勾选时 sticky 贴视口底：表格长的时候不用滚回去才能操作。 */
.bulkbar {
    display: none;
    position: sticky; bottom: 0; z-index: 3;
    align-items: center; gap: 14px;
    padding: 10px 18px;
    background: var(--surface);
    border-top: 1px solid var(--line);
    box-shadow: 0 -6px 16px rgba(20, 24, 31, .06);
}
.bulkbar.on { display: flex; }
.bulkbar-n { font-size: 12.5px; color: var(--text-2); white-space: nowrap; }
.bulkbar-n b { font-family: var(--mono); font-size: 14px; color: var(--text); font-weight: 600; }
.bulkbar-acts { display: flex; gap: 8px; flex-wrap: wrap; margin-left: auto; }
.bulkbar-acts .btn { box-shadow: none; }
.bulkbar-x {
    flex: 0 0 auto; width: 26px; height: 26px; line-height: 1;
    border: 0; background: transparent; color: var(--text-3);
    font-size: 17px; cursor: pointer; border-radius: 4px;
}
.bulkbar-x:hover { background: var(--surface-2); color: var(--text); }

.empty {
    padding: 44px 16px; text-align: center;
    color: var(--text-3); font-size: 14px;
    background-image: radial-gradient(circle at 50% 0%, #fafbfd, transparent 70%);
}
.empty b { display: block; color: var(--text-2); font-weight: 600; margin-bottom: 4px; font-size: 14px; }

/* ================================================================ 标签 */

.tag {
    display: inline-flex; align-items: center; gap: 4px;
    padding: 1.5px 8px; border-radius: 6px;
    font-size: 11.5px; font-weight: 600; line-height: 1.6;
    white-space: nowrap;
    border: 1px solid transparent;
}
.tag.gray  { background: var(--surface-3); color: var(--text-2); border-color: var(--line); }
.tag.blue  { background: var(--accent-soft); color: var(--accent); border-color: var(--accent-line); }
.tag.green { background: var(--ok-soft);     color: var(--ok);     border-color: var(--ok-line); }
.tag.amber { background: var(--warn-soft);   color: var(--warn);   border-color: var(--warn-line); }
.tag.red   { background: var(--bad-soft);    color: var(--bad);    border-color: var(--bad-line); }

.why { color: var(--text-3); font-size: 11.5px; }

/* ================================================================ 表单 */

label.f { display: block; margin-bottom: 15px; }
label.f > span {
    display: block; font-size: 12.5px; color: var(--text-2);
    margin-bottom: 6px; font-weight: 550;
}
label.f > small {
    display: block; font-size: 11.5px; color: var(--text-3);
    margin-top: 6px; line-height: 1.55;
}

input[type=text], input[type=password], input[type=number], input[type=time],
input[type=date], input[type=email], input[type=url], select, textarea {
    width: 100%; height: 36px; padding: 0 11px;
    font-size: 14px; font-family: inherit;
    background: var(--surface); color: var(--text);
    border: 1px solid var(--line-2); border-radius: var(--r-sm);
    outline: none;
    transition: border-color .15s var(--ease), box-shadow .15s var(--ease), background .15s var(--ease);
}
textarea { height: auto; padding: 9px 11px; resize: vertical; min-height: 84px; line-height: 1.65; }
input:hover, select:hover, textarea:hover { border-color: var(--line-3); }
input:focus, select:focus, textarea:focus {
    border-color: var(--accent);
    box-shadow: 0 0 0 3px rgba(37, 99, 235, .10);
    background: #fff;
}
input::placeholder, textarea::placeholder { color: var(--text-4); }
/* :not(.ck) 不能省。input[type=checkbox] 的权重是 0,1,1，
   比 .ck（0,1,0）高一级 —— 少了它，后面 .ck 里写的尺寸永远不生效，
   而且不报错、看着也「像那么回事」，只有量一下才知道还是 15px。 */
input[type=checkbox]:not(.ck), input[type=radio] { width: 15px; height: 15px; accent-color: var(--accent); }

.row   { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: 0 18px; }
.row-2 { display: grid; grid-template-columns: 1fr 1fr; gap: 0 18px; }
@media (max-width: 1080px) { .row-2 { grid-template-columns: 1fr; } }

/* 网格子项默认 min-width:auto，意思是「不许窄于内容的 min-content」。
   听着合理，实际会把带表格的卡片整个撑开：table 有 min-width:620px，
   于是轨道被顶成 620，卡片 620，最后整页横向滚出去 ——
   390 的屏上量到的文档宽是 692，右侧半张卡永远够不着。
   卡片里的 .bd.tight 明明已经 overflow-x:auto，却因为卡片自己就不窄，
   根本没机会滚。给 0 才算把「横向滚动由谁负责」这件事定下来。 */
.row-2 > * { min-width: 0; }

/* ================================================================ 按钮 */

.btn {
    display: inline-flex; align-items: center; justify-content: center; gap: 6px;
    height: 34px; padding: 0 14px;
    font-size: 12.5px; font-weight: 550; font-family: inherit;
    border-radius: var(--r-sm);
    border: 1px solid var(--line-2);
    background: var(--surface);
    color: var(--text);
    cursor: pointer; white-space: nowrap;
    box-shadow: 0 1px 2px rgba(16, 24, 40, .04);
    transition: background .15s var(--ease), border-color .15s var(--ease),
                box-shadow .15s var(--ease), transform .1s var(--ease), color .15s var(--ease);
}
.btn:hover {
    background: var(--surface-2);
    border-color: var(--line-3);
    color: var(--text);
    box-shadow: 0 2px 6px rgba(16, 24, 40, .07);
}
.btn:active { transform: translateY(.5px); box-shadow: none; }

.btn.primary {
    background: linear-gradient(180deg, #3b74ef 0%, #2563eb 100%);
    border-color: #2159d4; color: #fff; font-weight: 600;
    box-shadow: 0 1px 2px rgba(37, 99, 235, .28), inset 0 1px 0 rgba(255, 255, 255, .16);
}
.btn.primary:hover {
    background: linear-gradient(180deg, #2f6bf0 0%, #1d4ed8 100%);
    border-color: #1c4fc4; color: #fff;
    box-shadow: 0 3px 10px rgba(37, 99, 235, .32), inset 0 1px 0 rgba(255, 255, 255, .16);
}

.btn.danger { color: var(--bad); border-color: var(--bad-line); }
.btn.danger:hover { background: var(--bad-soft); border-color: #f7b3ac; color: var(--bad); }

.btn.ok { color: var(--ok); border-color: var(--ok-line); }
.btn.ok:hover { background: var(--ok-soft); color: var(--ok); }

.btn.sm { height: 28px; padding: 0 10px; font-size: 11.5px; border-radius: 6px; }
.btn:disabled, .btn[disabled] { opacity: .45; cursor: not-allowed; box-shadow: none; }

.btn-text {
    background: none; border: none; box-shadow: none;
    color: var(--accent); padding: 0 4px; height: auto;
    font-size: 12.5px; font-weight: 500;
}
.btn-text:hover { background: none; box-shadow: none; text-decoration: underline; }

/* 行内操作组。
   这里必须是 nowrap：放在表格最后一列时，一换行就会把「编辑」挤到第二行、
   并且因为 td 的 text-align 变成单独居中的一坨，视觉上像表格坏了。
   宽度不够时正确的做法是让浏览器把宽度从其他列让过来（table-layout: auto 默认会这么做），
   而不是让按钮自己折行。 */
/* 顶栏两个控件之间给 10px：站点下拉和它右边那个按钮的边框会贴在一起，
   6px 的通用间距在这种「下拉 + 按钮」组合上看起来像连成了一个控件。 */
.topbar .actions { gap: 10px; }

.actions { display: flex; gap: 6px; flex-wrap: nowrap; align-items: center; }
td > .actions { white-space: nowrap; }
/* 但「一排可换行的按钮」是另一种东西：预设渠道那一排有 10 个，
   在窄屏或卡片宽度不够时必须折行，用 nowrap 会被直接裁掉半个按钮。
   加 .wrap 显式放开 —— 默认不换行是为了表格，不是为了所有地方。 */
.actions.wrap { flex-wrap: wrap; }

/* 分段开关 */
.seg {
    display: inline-flex; background: var(--surface-3);
    border: 1px solid var(--line); border-radius: var(--r-sm);
    padding: 3px; gap: 2px;
}
.seg a, .seg button {
    padding: 4px 11px; height: 26px;
    font-size: 12px; font-weight: 500; font-family: inherit;
    border-radius: 5px; border: none;
    background: transparent; color: var(--text-2);
    cursor: pointer; display: inline-flex; align-items: center;
    transition: all .15s var(--ease);
}
.seg a:hover, .seg button:hover { color: var(--text); }
.seg .on {
    background: var(--surface); color: var(--accent);
    font-weight: 600;
    box-shadow: 0 1px 2px rgba(16, 24, 40, .08);
}

/* 开关 */
.switch { display: inline-flex; align-items: center; gap: 8px; cursor: pointer; font-size: 12.5px; user-select: none; }
.switch input { display: none; }
.switch i {
    width: 36px; height: 20px; border-radius: 20px;
    background: var(--line-3);
    position: relative; display: inline-block;
    transition: background .2s var(--ease);
    flex: 0 0 36px;
}
.switch i::after {
    content: ''; position: absolute; top: 2px; left: 2px;
    width: 16px; height: 16px; border-radius: 50%;
    background: #fff;
    box-shadow: 0 1px 3px rgba(16, 24, 40, .28);
    transition: transform .2s var(--ease);
}
.switch input:checked + i { background: var(--ok); }
.switch input:checked + i::after { transform: translateX(16px); }

/* ---- 渠道勾选列表（计划编辑）----
   原来这里是个要求手填「如 1,3」的文本框：得先去渠道页把 ID 记下来，
   再回来敲逗号。填错了不报错，只是那条计划默默少跑一个渠道 ——
   报告里少一个渠道投票，比报错难查得多。 */

.pk-box {
    border: 1px solid var(--line); border-radius: 10px;
    background: var(--surface-2);
    margin: 10px 0 8px; padding: 3px;
    max-height: 372px; overflow-y: auto;
    scrollbar-width: thin;
    transition: opacity .15s var(--ease);
}
.pk-box.hide { display: none; }

.pk-item {
    display: grid;
    grid-template-columns: 24px minmax(0, 1fr) auto;
    align-items: center; gap: 1px 10px;
    padding: 8px 11px; border-radius: 7px;
    cursor: pointer;
}
.pk-item + .pk-item { box-shadow: inset 0 1px 0 var(--line); }
.pk-item:hover { background: #fff; }
/* 选不中的项压暗但仍看得见 —— 直接不显示的话，
   用户会以为这个渠道被系统弄丢了 */
.pk-item.off { cursor: not-allowed; opacity: .62; }
.pk-item.off:hover { background: transparent; }

.pk-nm { font-size: 13.5px; font-weight: 550; color: var(--text); }
.pk-md {
    grid-column: 2; font-size: 12.5px; color: var(--text-3);
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.pk-tag {
    grid-row: 1 / span 2; grid-column: 3;
    font-size: 11.5px; padding: 2px 7px; border-radius: 5px;
    background: var(--surface-3); color: var(--text-3); white-space: nowrap;
}
.pk-tag.warn { background: var(--warn-soft); color: var(--warn); }
.pk-tag.bad  { background: var(--bad-soft);  color: var(--bad); }

.pk-bar { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin-bottom: 8px; }
.pk-hint { font-size: 12.5px; color: var(--text-3); }
.pk-hint b { color: var(--text-2); font-variant-numeric: tabular-nums; }

/* ================================================================ 提示条 */

.alert {
    display: flex; gap: 10px; align-items: flex-start;
    padding: 11px 15px;
    border-radius: var(--r-md);
    font-size: 14px; line-height: 1.6;
    margin-bottom: 16px;
    border: 1px solid transparent;
    animation: rise .24s var(--ease) both;
}
.alert.ok   { background: var(--ok-soft);     border-color: var(--ok-line);     color: #08694a; }
.alert.warn { background: var(--warn-soft);   border-color: var(--warn-line);   color: #8a4207; }
.alert.bad  { background: var(--bad-soft);    border-color: var(--bad-line);    color: #9c2118; }
.alert.info { background: var(--accent-soft); border-color: var(--accent-line); color: #1c47b5; }
.alert b { font-weight: 650; }
.alert code { background: rgba(255, 255, 255, .6); border-color: rgba(0, 0, 0, .06); }

/* ================================================================ 趋势图 */

.trend { width: 100%; height: auto; display: block; }
.trend .grid { stroke: var(--line); stroke-width: 1; stroke-dasharray: 3 3; }
.trend .axis { fill: var(--text-3); font-size: 10px; font-variant-numeric: tabular-nums; }
.trend .line {
    fill: none; stroke: var(--accent); stroke-width: 2.2;
    stroke-linejoin: round; stroke-linecap: round;
    filter: drop-shadow(0 2px 4px rgba(37, 99, 235, .22));
}
.trend .area { fill: url(#g1); }
.trend .pt { fill: #fff; stroke: var(--accent); stroke-width: 1.8; }
.trend .gap-label { fill: var(--text-4); font-size: 10px; }

/* 30 天格子 */
.grid30 { display: grid; grid-template-columns: repeat(30, 1fr); gap: 3px; }
.grid30 i {
    display: block; aspect-ratio: 1 / 1; border-radius: 3px;
    background: var(--surface-3);
    border: 1px solid var(--line);
    transition: transform .12s var(--ease), box-shadow .12s var(--ease);
    cursor: default;
}
.grid30 i:hover { transform: scale(1.35); box-shadow: var(--sh-2); z-index: 2; position: relative; }
.grid30 i.on {
    background: linear-gradient(180deg, #4f8dff, var(--accent));
    border-color: #2159d4;
}
/* 没采：斜纹。绝不能画成 0% 的实心块 —— 那是伪造数据。
   纹路比早先淡一档：连续 30 天没采时，深纹会把整条格子变成一面噪点墙。 */
.grid30 i.miss {
    background: repeating-linear-gradient(45deg,
        #f5f7fa, #f5f7fa 2px, #e4e8ee 2px, #e4e8ee 4px);
    border-color: var(--line-2);
}

.legend { display: flex; gap: 16px; font-size: 11.5px; color: var(--text-3); margin-top: 10px; align-items: center; }
.legend i { display: inline-block; width: 10px; height: 10px; border-radius: 3px; margin-right: 5px; vertical-align: -1px; }

/* 完整性条 */
.bar { height: 6px; border-radius: 4px; background: var(--surface-3); overflow: hidden; }
.bar > i { display: block; height: 100%; border-radius: 4px; background: linear-gradient(90deg, #4f8dff, var(--accent)); }

/* ================================================================ 登录 */

.login-wrap {
    min-height: 100vh;
    display: grid; place-items: center;
    padding: 24px;
    position: relative;
    background:
        radial-gradient(780px 480px at 12% 6%, rgba(37, 99, 235, .30), transparent 62%),
        radial-gradient(720px 460px at 88% 94%, rgba(109, 60, 245, .26), transparent 64%),
        linear-gradient(165deg, #080b12 0%, #111a2b 48%, #080b12 100%);
}
/* 极淡点阵：精密仪器行业该有的那种「刻度感」，比纯渐变有信息量 */
.login-wrap::before {
    content: '';
    position: fixed; inset: 0;
    background-image: radial-gradient(rgba(255, 255, 255, .05) 1px, transparent 1px);
    background-size: 22px 22px;
    pointer-events: none;
}
.login-box { width: 100%; max-width: 404px; position: relative; }
.login-box .card {
    margin: 0;
    border: 1px solid rgba(255, 255, 255, .09);
    box-shadow: 0 28px 70px rgba(0, 0, 0, .5), 0 2px 10px rgba(0, 0, 0, .32);
    background: #fff;
    padding: 36px 32px 30px;
    position: relative;
    overflow: hidden;
    animation: rise .4s var(--ease) both;
}
/* 卡片顶部一道品牌渐变，把这张白卡跟「随便一个表单」区分开 */
.login-box .card::before {
    content: '';
    position: absolute; inset: 0 0 auto 0; height: 3px;
    background: linear-gradient(90deg, #4f8dff, #6d3cf5 55%, #4f8dff);
}
.login-box .hd-brand {
    display: flex; align-items: center; gap: 10px; margin-bottom: 22px;
}
.login-box .hd-brand .dot {
    width: 30px; height: 30px; border-radius: 9px;
    background: linear-gradient(140deg, #4f8dff, #2563eb 55%, #6d3cf5);
    box-shadow: 0 3px 12px rgba(37, 99, 235, .4);
    position: relative;
}
.login-box .hd-brand .dot::after {
    content: ''; position: absolute; inset: 50% auto auto 50%;
    width: 9px; height: 9px; margin: -4.5px 0 0 -4.5px;
    border-radius: 50%; background: #fff;
}
.login-box h1 { font-size: 17.5px; margin: 0; font-weight: 650; letter-spacing: -.015em; }
.login-box p { margin: 0 0 20px; color: var(--text-3); font-size: 12.5px; }
.login-box .btn { width: 100%; height: 40px; font-size: 13.5px; margin-top: 4px; }
.login-foot { text-align: center; margin-top: 18px; font-size: 11.5px; color: var(--side-text-2); }

/* ================================================================ 其他 */

.pager {
    display: flex; gap: 6px; align-items: center; justify-content: flex-end;
    padding: 12px 18px; border-top: 1px solid var(--line);
    font-size: 12.5px; color: var(--text-3);
    background: var(--surface-2);
}
.pager a, .pager span {
    padding: 4px 9px; border-radius: 6px;
    border: 1px solid var(--line-2);
    background: var(--surface);
    color: var(--text-2);
    transition: all .15s var(--ease);
}
.pager a:hover { border-color: var(--accent); color: var(--accent); }
.pager .cur {
    background: var(--accent); border-color: var(--accent);
    color: #fff; font-weight: 600;
}
.pager .off { opacity: .45; }

.help { font-size: 12px; color: var(--text-3); line-height: 1.75; }
.help code { background: var(--surface-3); padding: 1px 5px; }
.help b { color: var(--text-2); }
.inline-form { display: inline; }
.sec-title {
    font-size: 11px; color: var(--text-3);
    letter-spacing: .09em; text-transform: uppercase; font-weight: 600;
    margin: 24px 0 10px;
}
.fieldset {
    border: 1px solid var(--line); border-radius: var(--r-md);
    padding: 16px 18px 2px; margin-bottom: 18px;
    background: var(--surface-2);
}
.fieldset > legend {
    font-size: 12px; color: var(--text-2); font-weight: 600;
    padding: 0 7px; letter-spacing: .01em;
}
.hide { display: none !important; }

/* 双栏（看板用） */
.row-2.keep { grid-template-columns: 1fr 1fr; }

/* 计量小条：竞品榜的宽度指示 */
.meter { display: flex; align-items: center; gap: 9px; }
.meter .bar { flex: 1 1 auto; min-width: 44px; }

/* ================================================================ 卡片脚注 */

/* 脚注是「这张表的口径说明 + 跳转」的位置。
   它必须跟表体分开一档：浅底 + 上边框，否则会被当成表格的最后一行。 */
.card > .ft {
    padding: 10px 18px;
    border-top: 1px solid var(--line);
    background: var(--surface-2);
    font-size: 11.5px; color: var(--text-3); line-height: 1.6;
    display: flex; align-items: center; justify-content: space-between; gap: 12px;
}
.card > .ft b { color: var(--text-2); font-weight: 600; }

/* ================================================================ 标签状态点 */

/* 「启用 / 停用 / 失败」这类状态，只靠底色区分在色弱和打印时都会糊成一片。
   加一个同色小圆点，形状本身就成了第二重编码。 */
.tag > i.dot {
    width: 6px; height: 6px; border-radius: 50%;
    flex: 0 0 6px; background: currentColor;
    opacity: .85;
}
/* 进行中的状态给一点呼吸感，暗示「这个还在变」 */
.tag > i.dot.live { animation: pulse 1.8s var(--ease) infinite; }
@keyframes pulse {
    0%, 100% { opacity: .85; box-shadow: 0 0 0 0 currentColor; }
    50%      { opacity: .45; box-shadow: 0 0 0 3px rgba(180, 83, 9, .12); }
}

/* ================================================================ KPI 迷你柱 */

/* 每张 KPI 卡底下那排小柱子。
   用 flex + 百分比高度而不是 SVG：卡片宽度是自适应的（grid auto-fit），
   SVG 缩放会把柱子之间的间隙一起拉伸，30 根柱子就会歪。
   抽屉里也用同一套柱子（更高一些），所以选择器写成两处共用。 */
.kpi .spark,
.drawer-bd .spark {
    display: flex; align-items: flex-end; gap: 2px;
    height: 24px;
}
.kpi .spark { margin-top: 10px; }
.drawer-bd .spark { height: 52px; gap: 2px; }

.kpi .spark i,
.drawer-bd .spark i {
    flex: 1 1 0; min-width: 0;
    /* 0% 也要能看见一根 1.5px 的短柱：那代表「采了、确实是 0」，
       跟「没采」（下面的斜纹）是完全不同的两件事。 */
    min-height: 1.5px;
    height: 0;
    background: linear-gradient(180deg, #7aa8ff, var(--accent));
    border-radius: 1.5px 1.5px 1px 1px;
    transition: opacity .15s var(--ease);
}
/* 没采：一整根空的灰槽。
   这里刻意**不用**斜纹 —— 试过，数据稀疏时（比如近 14 天只采了 1 天）
   13 根斜纹柱会糊成一面噪点墙，视觉重量压过唯一那根真数据。
   「没采」应该是背景，不是主体。空槽 + tooltip 说明就够了。
   （30 天格子那边仍用斜纹：那是方块矩阵，一格一格的纹路读得出来。） */
.kpi .spark i.miss,
.drawer-bd .spark i.miss {
    height: 100%;
    background: #f1f3f6;
}
.kpi:hover .spark i { opacity: .92; }

/* ================================================================ 抽屉 */

.drawer { position: fixed; inset: 0; z-index: 90; display: none; }
.drawer.open { display: block; }

.drawer-mask {
    position: absolute; inset: 0;
    background: rgba(13, 17, 23, .38);
    backdrop-filter: blur(1.5px);
    animation: fadeIn .2s var(--ease) both;
}
@keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } }

/* 从右滑入。位移只给 18px：整屏横推会让「我刚才在看哪」丢失，
   小位移 + 淡入既表达了层级变化，又不会打断阅读位置。 */
.drawer-panel {
    position: absolute; top: 0; right: 0; bottom: 0;
    width: min(468px, 92vw);
    background: var(--surface);
    box-shadow: -20px 0 52px rgba(16, 24, 40, .20), -1px 0 0 rgba(16, 24, 40, .06);
    display: flex; flex-direction: column;
    animation: slideIn .26s var(--ease) both;
}
@keyframes slideIn {
    from { transform: translateX(18px); opacity: .55; }
    to   { transform: translateX(0);    opacity: 1; }
}

.drawer-hd {
    display: flex; align-items: flex-start; justify-content: space-between; gap: 12px;
    padding: 16px 18px 14px;
    border-bottom: 1px solid var(--line);
    background: linear-gradient(180deg, #fdfdfe, #fbfcfd);
    flex: 0 0 auto;
}
.drawer-hd h3 {
    margin: 0; font-size: 14.5px; font-weight: 650; letter-spacing: -.01em;
    min-width: 0;
}
.drawer-hd .sub { font-size: 11.5px; color: var(--text-3); font-weight: 400; margin-top: 3px; line-height: 1.5; }

.drawer-x {
    flex: 0 0 30px; width: 30px; height: 30px;
    display: grid; place-items: center;
    border: 1px solid var(--line-2); border-radius: var(--r-sm);
    background: var(--surface); color: var(--text-3);
    cursor: pointer; transition: all .15s var(--ease);
}
.drawer-x:hover { background: var(--surface-3); color: var(--text); border-color: var(--line-3); }
.drawer-x svg { width: 15px; height: 15px; }

.drawer-bd { flex: 1 1 auto; overflow-y: auto; padding: 16px 18px 26px; }

/* 抽屉里的加载态与空态 */
.drawer-bd .loading { padding: 40px 0; text-align: center; color: var(--text-4); font-size: 12.5px; }
.drawer-bd .loading::after {
    content: ''; display: block; width: 18px; height: 18px; margin: 12px auto 0;
    border: 2px solid var(--line-2); border-top-color: var(--accent);
    border-radius: 50%; animation: spin .7s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }

/* 抽屉里的小节标题 */
.drawer-bd .dz-title {
    font-size: 11px; color: var(--text-3); font-weight: 600;
    letter-spacing: .08em; text-transform: uppercase;
    margin: 20px 0 9px;
}
.drawer-bd .dz-title:first-child { margin-top: 0; }

/* 抽屉里的原文片段：引用块，让「AI 在哪句话里提到了它」可核 */
.quote {
    border-left: 2px solid var(--accent-line);
    background: var(--surface-2);
    padding: 9px 12px; border-radius: 0 var(--r-sm) var(--r-sm) 0;
    font-size: 12.5px; line-height: 1.7; color: var(--text-2);
    margin-bottom: 8px;
}
.quote mark {
    background: var(--accent-soft); color: var(--accent-h);
    padding: 0 2px; border-radius: 3px; font-weight: 600;
}
.quote .qmeta {
    float: right; margin-left: 10px;
    font-family: var(--mono); font-size: 10.5px; color: var(--text-4);
}

/* 抽屉里的三数概览 */
.dz-stats { display: grid; grid-template-columns: repeat(3, 1fr); gap: 9px; margin-bottom: 4px; }
.dz-stats > div {
    background: var(--surface-2); border: 1px solid var(--line);
    border-radius: var(--r-sm); padding: 9px 11px;
}
.dz-stats .k { display: block; font-size: 11px; color: var(--text-3); }
.dz-stats .v {
    display: block; font-size: 17px; font-weight: 650;
    margin-top: 2px; letter-spacing: -.02em;
    font-variant-numeric: tabular-nums; color: var(--text);
}
.dz-stats .v small { font-size: 11.5px; font-weight: 500; color: var(--text-3); margin-left: 2px; }

/* 打开抽屉时锁住背景滚动，避免滚轮把底下的页面带着滚 */
body.drawer-open { overflow: hidden; }

/* 可点击的行：给一个明确的交互暗示，否则没人会想到点表格行 */
tr.is-clickable { cursor: pointer; }
tr.is-clickable:hover td { background: #f8faff; }
/* 「详情」入口做成轻微右对齐的箭头，比在每行塞一个按钮干净。
   颜色不能给 text-4：那样不 hover 时几乎看不见，等于没提示。 */
.row-go { color: var(--text-3); font-size: 15px; line-height: 1; text-align: right; transition: color .15s var(--ease), transform .15s var(--ease); }
tr.is-clickable:hover .row-go { color: var(--accent); transform: translateX(1px); }

/* ================================================================ 现场检测 */

/* 这一页跟其它页的定位不一样：它是给客户看的，不是给自己用的。
   所以只有这里允许出现大字号和居中排版 —— 其余页面保持后台的紧凑密度。
   克制在别处，放开在这里，对比本身就是「这页很重要」的信号。 */

.onb-hero {
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: var(--r-lg);
    padding: 42px 36px 34px;
    margin-bottom: 14px;
    text-align: center;
}

.onb-kicker {
    display: inline-block;
    font-size: 11px; letter-spacing: .09em;
    color: var(--accent); background: var(--accent-soft);
    border: 1px solid var(--accent-line);
    padding: 4px 12px; border-radius: 999px;
    margin-bottom: 18px;
}

.onb-h {
    margin: 0 0 14px;
    font-size: 26px; line-height: 1.4;
    font-weight: 650; letter-spacing: -.022em; color: var(--text);
}

.onb-lead {
    margin: 0 auto 28px; max-width: 540px;
    font-size: 14px; line-height: 1.8; color: var(--text-2);
}

.onb-form { max-width: 600px; margin: 0 auto; }

/* 输入框和按钮做成一个整体，而不是两个并排的元素：
   一眼就能看出「在这里打字，然后按这里」，不需要读说明。

   ★ 高度必须由容器显式给，不能让子元素各自决定。
   原来写的是 align-items: stretch + 让 input 自己撑，实测在 Chrome 里
   <input> 不会被 flex 撑开：容器内高 46px，input 只有 36px 且顶对齐，
   于是文字比左边的 https:// 低 2px、底边还空出 10px（就是「文本框没对齐」那条）。
   改成容器定高 48 + 子元素 height:100%，三者的中线才是同一条。 */
.onb-input {
    display: flex; align-items: stretch;
    height: 48px;
    border: 1px solid var(--line-2); border-radius: var(--r-md);
    background: var(--surface-2);
    transition: border-color .15s var(--ease), box-shadow .15s var(--ease), background .15s var(--ease);
}
.onb-input:focus-within {
    border-color: var(--accent);
    background: #fff;
    box-shadow: 0 0 0 3px rgba(37, 99, 235, .09);
}

/* 协议做成下拉，而不是写死一段文字。
   写死 https:// 等于替客户做了决定 —— 没装证书的站根本连不上，
   而现场最常遇到的恰恰是这种站（老企业站、内网映射、刚上线的）。
   外观仍按原来的「前缀」处理：无边无底、等宽字体、灰一档。 */
.onb-scheme { display: flex; align-items: center; flex: 0 0 auto; padding-left: 16px; }
.onb-scheme select {
    appearance: none; -webkit-appearance: none;
    width: auto; height: 100%; margin: 0; padding: 0 16px 0 0;
    border: 0; border-radius: 0; box-shadow: none; background-color: transparent;
    font-family: var(--mono); font-size: 14px; color: var(--text-4);
    cursor: pointer;
    /* 小三角用两层渐变画出来，省一个伪元素 */
    background-image:
        linear-gradient(45deg, transparent 50%, currentColor 50%),
        linear-gradient(135deg, currentColor 50%, transparent 50%);
    background-position: calc(100% - 7px) calc(50% + 1px), calc(100% - 3px) calc(50% + 1px);
    background-size: 4px 4px, 4px 4px;
    background-repeat: no-repeat;
}
.onb-scheme select:hover { color: var(--text-2); }

/* 这三个属性必须显式清掉。
   全局的 input:focus 会加 box-shadow + border-radius + 白底，
   套在这里就在输入区里画出一个带圆角的白框，看起来像「框里有框」。
   焦点样式统一交给外层的 :focus-within 去做。 */
.onb-input input {
    flex: 1 1 auto; min-width: 0;
    width: auto; height: 100%;
    border: 0; border-radius: 0; outline: 0; box-shadow: none;
    background: transparent;
    padding: 0 10px; font-size: 15px; color: var(--text);
    font-family: var(--mono);
}
.onb-input input:focus { border: 0; border-radius: 0; box-shadow: none; background: transparent; }
.onb-scheme select:focus { box-shadow: none; }
.onb-input .btn { margin: 6px; border-radius: 6px; padding: 0 22px; }
.onb-hint { margin-top: 11px; font-size: 12px; color: var(--text-3); }

.onb-steps {
    display: grid; grid-template-columns: repeat(3, 1fr);
    gap: 12px; margin-bottom: 14px;
}
.onb-step {
    display: flex; gap: 12px;
    background: var(--surface); border: 1px solid var(--line);
    border-radius: var(--r-md); padding: 16px;
}
.onb-num {
    flex: 0 0 auto; width: 22px; height: 22px; border-radius: 50%;
    background: var(--accent-soft); color: var(--accent);
    border: 1px solid var(--accent-line);
    display: flex; align-items: center; justify-content: center;
    font-size: 11.5px; font-weight: 650;
}
.onb-step b { display: block; font-size: 14px; margin-bottom: 5px; color: var(--text); }
.onb-step span { display: block; font-size: 12px; line-height: 1.7; color: var(--text-3); }

.onb-foot { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
.onb-foot > div {
    background: var(--surface-3); border: 1px solid var(--line);
    border-radius: var(--r-md); padding: 15px 16px;
}
/* 只有卡片的标题 b 变块级，正文段落里的 <b> 必须保持行内。
   写成 .onb-foot b 时踩过：正文那句「体检分反映的是 <b>站点被 AI 读取的技术条件</b>，
   不等于 AI 现在有没有提你」被切成三行，粗体那行还和下一行叠在一起 ——
   在 1440 宽的演示屏上很明显，客户会以为页面坏了。 */
.onb-foot > div > b { display: block; font-size: 12.5px; color: var(--text-2); margin-bottom: 7px; }
.onb-foot p { margin: 0; font-size: 12px; line-height: 1.75; color: var(--text-3); }

/* ---- 结果页顶部 ---- */
.ona-top {
    display: flex; gap: 30px; align-items: flex-start;
    background: var(--surface); border: 1px solid var(--line);
    border-radius: var(--r-lg); padding: 26px;
    margin-bottom: 14px;
}
.ona-ring { flex: 0 0 128px; text-align: center; }
.ona-ring svg { width: 128px; height: 128px; display: block; }
.ona-grade { margin-top: 4px; font-size: 12.5px; font-weight: 650; letter-spacing: .02em; }
/* 分数环下面这行占比说明：环只有 128px 宽，写「这只是基建完备度，
   占 GEO 健康分的 30%」会折成三行，把环顶歪。所以压到 10.5px 一句短的，
   完整口径挂 title —— 想深究的人悬停就能看到四项权重。 */
.ona-share { margin-top: 3px; font-size: 10.5px; color: var(--text-4); line-height: 1.45; }
.ona-share b { color: var(--text-3); font-weight: 650; }

.ona-sum { flex: 1 1 auto; min-width: 0; }
.ona-host b { font-size: 19px; letter-spacing: -.012em; color: var(--text); }

/* 站名 + 重测排成一行，用 flex 对齐而不是 vertical-align：
   后者按字体基线算，19px 的站名和 28px 的按钮实测差 4.5px，
   换字体或改字号就会重新歪，这一层不能交给字体度量决定。 */
.ona-hostline { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.ona-retry { flex: 0 0 auto; }
.ona-retry button { white-space: nowrap; }

.ona-host .sub { display: block; margin-top: 4px; font-size: 12px; color: var(--text-3); }

.ona-line { margin: 15px 0 0; display: flex; gap: 8px; flex-wrap: wrap; }
.ona-chip {
    font-size: 12px; color: var(--text-2);
    background: var(--surface-3); border: 1px solid var(--line);
    padding: 4px 11px; border-radius: 999px;
}
.ona-chip b { margin-left: 5px; font-variant-numeric: tabular-nums; }

/* 结论句独立成块并带左侧竖线：这是整页唯一一段「我们替客户下的判断」，
   视觉上必须跟数据区分开，否则会被当成又一条指标。 */
.ona-verdict {
    margin: 15px 0 0;
    font-size: 14px; line-height: 1.8; color: var(--text);
    padding: 13px 16px; background: var(--surface-2);
    border-left: 2px solid var(--accent);
    border-radius: 0 var(--r-sm) var(--r-sm) 0;
}

.ona-fetch {
    margin-top: 15px; display: flex; gap: 18px; flex-wrap: wrap;
    font-size: 11.5px; color: var(--text-3);
}
.ona-fetch b { color: var(--text-2); font-variant-numeric: tabular-nums; }
.ona-meta { margin-top: 9px; font-size: 11.5px; color: var(--text-4); }

/* ---- 体检历史 ---- */
.ona-hist-top {
    display: flex; align-items: center; justify-content: space-between;
    gap: 14px; margin-bottom: 14px; flex-wrap: wrap;
}
.ona-hist-top b { font-size: 14px; }
.ona-hist-top .sub { margin-left: 9px; font-size: 11.5px; color: var(--text-4); }

/* 差值条：现场被问「比上次好点没」时就指这一块。
   左边竖线 + 大数字，让差值比分数本身更先被看到 —— 客户关心的是「动了没有」，
   不是「现在是 84 还是 87」。 */
.ona-delta {
    display: flex; align-items: center; gap: 16px;
    padding: 14px 18px; margin-bottom: 14px;
    background: var(--surface); border: 1px solid var(--line);
    border-left-width: 3px; border-radius: var(--r-md);
}
.ona-delta-num {
    flex: 0 0 auto; font-size: 30px; font-weight: 700;
    font-variant-numeric: tabular-nums; line-height: 1;
}
.ona-delta-txt { font-size: 12.5px; line-height: 1.75; color: var(--text-2); }
.ona-delta-txt b { color: var(--text); font-variant-numeric: tabular-nums; }

.ona-delta.up   { border-left-color: var(--ok);   background: linear-gradient(90deg, var(--ok-soft), rgba(255, 255, 255, 0) 60%); }
.ona-delta.up   .ona-delta-num { color: var(--ok); }
.ona-delta.down { border-left-color: var(--bad);  background: linear-gradient(90deg, var(--bad-soft), rgba(255, 255, 255, 0) 60%); }
.ona-delta.down .ona-delta-num { color: var(--bad); }
.ona-delta.flat { border-left-color: var(--line-3); }
.ona-delta.flat .ona-delta-num { color: var(--text-3); }

/* ---- 检查项 ---- */
.chk-group {
    background: var(--surface); border: 1px solid var(--line);
    border-radius: var(--r-md); margin-bottom: 12px; overflow: hidden;
}
.chk-gh {
    display: flex; align-items: center; justify-content: space-between;
    padding: 11px 16px; background: var(--surface-3);
    border-bottom: 1px solid var(--line);
    font-size: 12.5px; font-weight: 650; color: var(--text-2);
}
.chk-gs { font-variant-numeric: tabular-nums; font-size: 14px; }
.chk-gs small { font-size: 10.5px; color: var(--text-4); font-weight: 400; }

.chk { border-bottom: 1px solid var(--line); }
.chk:last-child { border-bottom: 0; }
.chk > summary {
    display: flex; align-items: center; gap: 11px;
    padding: 10px 16px; cursor: pointer; list-style: none;
    font-size: 12.5px;
}
.chk > summary::-webkit-details-marker { display: none; }
.chk > summary:hover { background: var(--surface-2); }

.chk-dot {
    flex: 0 0 auto; width: 7px; height: 7px; border-radius: 50%;
    background: var(--text-4);
}
.chk.ok   .chk-dot { background: var(--ok); }
.chk.warn .chk-dot { background: var(--warn); }
.chk.na   .chk-dot { background: var(--line-3); }
/* 失败项给一个外发光圈，不是为了好看 —— 一屏 12 行里必须一眼找到该修的那两行 */
.chk.fail .chk-dot { background: var(--bad); box-shadow: 0 0 0 3px var(--bad-soft); }
.chk.fail > summary { background: linear-gradient(90deg, var(--bad-soft), rgba(254, 243, 242, 0) 55%); }

.chk-name { flex: 0 0 130px; font-weight: 600; color: var(--text); }
.chk-ev { flex: 1 1 auto; min-width: 0; color: var(--text-2); }
.chk-w { flex: 0 0 auto; font-size: 11px; color: var(--text-4); font-variant-numeric: tabular-nums; }
.chk-body {
    padding: 0 16px 13px 33px;
    font-size: 12px; line-height: 1.8; color: var(--text-3);
}

/* ---- 建站表单里的推导开关 ---- */
.onb-ai {
    margin-top: 14px; padding: 15px 16px;
    background: var(--accent-soft); border: 1px solid var(--accent-line);
    border-radius: var(--r-md);
}
.onb-check { display: flex; gap: 10px; align-items: flex-start; cursor: pointer; }
.onb-check input { margin-top: 2px; width: auto; flex: 0 0 auto; }
.onb-check b { display: block; font-size: 14px; color: var(--text); margin-bottom: 4px; }
.onb-check small { display: block; font-size: 11.5px; line-height: 1.7; color: var(--text-2); }

@media (max-width: 900px) {
    .onb-steps, .onb-foot { grid-template-columns: 1fr; }
    .onb-hero { padding: 28px 18px 24px; }
    .onb-h { font-size: 21px; }
    .ona-top { flex-direction: column; gap: 16px; align-items: center; text-align: center; }
    .ona-line { justify-content: center; }
    .chk-name { flex: 0 0 96px; }
    .chk-w { display: none; }

    /* 顶栏在 390 宽下会顶出 39px：站点选择器 + 「生成报告」按钮
       加起来 349px，而可用宽度只有 278px。选择器可以缩，按钮不能没有 ——
       缩的是选择器的宽度，按钮留着，靠 flex 自己让位。
       计划页更糟（67px），那边还多一个筛选输入框。 */
    .topbar .actions { min-width: 0; gap: 6px; }
    .topbar .sitesw { min-width: 0; }
    .topbar .sitesw select { max-width: 108px; }
}

/* 打印：偶尔要把看板打出来交给老板 */
@media print {
    .sidebar, .topbar .actions { display: none; }
    .main > .card, .kpis { break-inside: avoid; }
    body { background: #fff; }
}

/* 短视口再收一档。
   1280×720（老笔电、或把浏览器拉成半屏）下整列还有 48px 亏空，
   底部的「站点」「渠道」会被推出视口。侧栏虽然有 overflow-y:auto 兜底，
   但深色条上的滚动条几乎看不见 —— 用户不会知道下面还有两项。
   断点放在 780 而不是 760：1366×768 实测内容刚好铺满 768，可 scrollHeight
   还是 782 —— 多出来的正是侧栏自己的 padding-bottom，于是能往下拖 14px，
   底部那条版本号被切掉一截。这类「差一点点」比差 48px 更难受。
   14 个菜单项 × 4px padding = 56px，够补上，字号依然一点不动。 */
@media (min-width: 901px) and (max-height: 780px) {
    .nav a { padding: 6px 10px; }
    .nav-sep { margin: 8px 0 2px; }
    .brand { padding: 12px 10px 14px; }
    .sidebar { padding-bottom: 10px; }   /* 720 高度下最后差 2px，从这里出 */
}

/* ================================================================ 窄屏 */

/* 后台主要在电脑上用，但看板这种东西老板会拿手机点开看一眼。
   原来没有断点：侧栏固定 228px，430px 的手机上内容区只剩 200px，
   表格文字被挤成一列竖排，等于打不开。
   这里只做最小可用：侧栏收成图标条 + 表格横向滚动，不做抽屉式导航。 */
@media (max-width: 900px) {
    :root { --side-w: 56px; }

    .sidebar { padding: 0 8px 16px; }
    /* 文字全藏起来，只留图标。用 display:none 而不是 font-size:0：
       后者会影响 flex 的 gap，图标位置会歪。 */
    .brand > span, .nav a span, .nav-group,
    .side-foot, .brand small { display: none; }
    .brand { justify-content: center; padding: 18px 0; }
    .nav a { justify-content: center; padding: 10px 0; }
    /* 激活项的左侧竖条在 56px 宽里会贴到图标上，改成整块高亮 */
    .nav a.on::before { display: none; }

    .topbar { padding: 0 14px; gap: 10px; }
    /* 站点切换器会顶出横向滚动条：select 的宽度由最长 option 决定，
       「质朋仪器 kosaka-cn.com」这种名字能把它撑到 180px 以上，
       加上左右内边距就超了 390 的屏（实测台账页顶出 44px、对比页 34px）。
       窄屏先省掉「站点」二字，再给 select 一个上限，长的交给浏览器截断。 */
    .sitesw > span { display: none; }
    .sitesw select { min-width: 0; max-width: 150px; }
    .content { padding: 14px 14px 40px; }

    .row-2, .row-2.keep { grid-template-columns: 1fr; }
    .kpis { grid-template-columns: repeat(auto-fit, minmax(140px, 1fr)); gap: 10px; }

    /* 表格不许压到读不出来：给一个下限，让它横向滚，而不是把列挤成竖排 */
    table { min-width: 620px; }
    .card > .bd.tight { overflow-x: auto; -webkit-overflow-scrolling: touch; }

    /* 窄屏必须撤掉表头吸顶。
       上面那句 overflow-x:auto 把 .bd 变成了滚动容器（一个方向非 visible，
       另一个方向的 visible 会被算成 auto），而它自己纵向不滚 ——
       于是 thead 的 sticky top 改成相对这一层算，表头直接错位盖到第一行上。
       横向滚动容器 + 纵向吸顶本来也互相打架：手机上没有谁的表格是竖着看一半
       再横着看的。 */
    thead th { position: static; }

    /* 勾选列在窄屏收窄：42px 在 1440 下不算什么，在 390 的屏上等于一整列
       文字被挤走。勾选框本身只有 15px，18px 的左内边距在这里也多余。 */
    .tbl-pick th.pk,
    .tbl-pick td.pk { width: 32px; padding-left: 10px; }

    /* 批量条在窄屏改成浮在视口底的小条。
       不能继续用 sticky：上面的 overflow-x:auto 让 .bd 成了滚动容器，
       sticky 的参照物变成它而不是视口，于是「勾完 24 行里的第 3 条，
       还得滚一千多像素回去才能点暂停」。
       悬浮条比全宽底栏好 —— 手机上一屏只有十几行，不该再被一条满宽栏压掉。 */
    .bulkbar.on {
        position: fixed; left: 12px; right: 12px; bottom: 12px; z-index: 50;
        padding: 9px 12px; gap: 10px;
        border: 1px solid var(--line); border-radius: 10px;
        box-shadow: 0 10px 28px rgba(20, 24, 31, .16);
    }
    .bulkbar-acts { gap: 6px; }

    .card > .ft { flex-wrap: wrap; gap: 4px; }

    .drawer-panel { width: 100%; }
    .dz-stats { grid-template-columns: 1fr 1fr; }
}

/* ==========================================================================
   洞察（口径偏差 / 丢单场景 / 引用源）
   --------------------------------------------------------------------------
   这三页面向的读者是「被客户盯着看的销售」，不是坐在工位上的运营。
   所以字号比后台其他页大一号，留白更宽，每一块都要能指着屏幕念出来。

   一条贯穿三页的规矩：证据（AI 原话）用引号块，判断（我们说的话）用正文。
   两者视觉上必须分得开 —— 客户很容易把我们的判断当成 AI 原话，
   一旦他自己去验证发现对不上，整份报告就废了。
   ========================================================================== */

.ins-intro {
    background: var(--surface); border: 1px solid var(--line);
    border-radius: var(--r-lg); padding: 18px 20px; margin-bottom: 16px;
}
.ins-intro b { font-size: 14px; font-weight: 650; color: var(--text); }
.ins-intro p { margin: 8px 0 0; font-size: 14px; line-height: 1.75; color: var(--text-2); }
.ins-intro .ins-rule {
    margin-top: 12px; padding-top: 12px; border-top: 1px dashed var(--line-2);
    font-size: 12.5px; color: var(--text-3);
}

/* ---- 页头统计条 ---- */
.ins-stats {
    display: flex; flex-wrap: wrap; gap: 1px; margin-bottom: 16px;
    background: var(--line); border: 1px solid var(--line);
    border-radius: var(--r-lg); overflow: hidden;
}
.ins-stat {
    flex: 1 1 0; min-width: 110px;
    background: var(--surface); padding: 13px 16px;
}
.ins-stat b {
    display: block; font-size: 20px; font-weight: 650; letter-spacing: -.02em;
    font-variant-numeric: tabular-nums; color: var(--text); line-height: 1.2;
}
.ins-stat span { display: block; margin-top: 3px; font-size: 11.5px; color: var(--text-3); }
.ins-stat.bad b { color: var(--bad); }
.ins-stat.bad { background: var(--bad-soft); }
.ins-stat.warn b { color: var(--warn); }

/* ---- 口径偏差 ---- */
.cl-list { display: flex; flex-direction: column; gap: 12px; }

.cl {
    background: var(--surface); border: 1px solid var(--line);
    border-left: 3px solid var(--line-3);
    border-radius: var(--r-md); padding: 16px 18px;
}
/* 硬伤用左边线加粗 + 底色微红。一屏里必须一眼找出来，
   混在一堆同级卡片里，客户会平均分配注意力，等于没有重点。 */
.cl-s1 { border-left-color: var(--bad); background: linear-gradient(90deg, var(--bad-soft) 0%, var(--surface) 90px); }
.cl-s2 { border-left-color: var(--warn); }
.cl-s3 { border-left-color: var(--line-3); }

.cl-hd { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin-bottom: 10px; }
.cl-fund {
    font-size: 11px; font-weight: 650; letter-spacing: .02em;
    padding: 2px 7px; border-radius: 4px;
    background: var(--surface-3); color: var(--text-2);
}
.cl-s1 .cl-fund { background: var(--bad-soft); color: var(--bad); }
.cl-q { font-size: 12.5px; color: var(--text-3); flex: 1 1 auto; }
.cl-tag.bad {
    font-size: 10.5px; font-weight: 650; padding: 2px 6px; border-radius: 4px;
    background: var(--bad); color: #fff; letter-spacing: .04em;
}

/* 引号块 = AI 原话。这一块是全页最有说服力的东西，
   所以给它独立的底色和左引号，绝不和正文混排。 */
.cl-quote {
    margin: 0 0 12px; padding: 11px 14px 11px 30px;
    background: var(--surface-2); border: 1px solid var(--line);
    border-radius: 0 var(--r-sm) var(--r-sm) 0; position: relative;
    font-size: 14px; line-height: 1.75; color: var(--text);
}
.cl-quote::before {
    content: '“'; position: absolute; left: 9px; top: 4px;
    font-size: 26px; line-height: 1; color: var(--text-4); font-family: Georgia, serif;
}

.cl-row { display: flex; gap: 12px; margin-bottom: 8px; align-items: flex-start; }
.cl-k {
    flex: 0 0 52px; font-size: 11.5px; color: var(--text-3);
    padding-top: 2px; letter-spacing: .02em;
}
.cl-v { flex: 1 1 auto; font-size: 14px; line-height: 1.7; color: var(--text-2); }
.cl-gap { color: var(--warn); font-size: 12.5px; }

.cl-more { margin-top: 4px; }
.cl-more summary {
    cursor: pointer; font-size: 12px; color: var(--accent);
    list-style: none; padding: 5px 0; user-select: none;
}
.cl-more summary::-webkit-details-marker { display: none; }
.cl-more summary::before { content: '▸ '; font-size: 10px; }
.cl-more[open] summary::before { content: '▾ '; }
.cl-ans {
    margin-top: 6px; padding: 12px 14px; background: var(--surface-3);
    border: 1px solid var(--line); border-radius: var(--r-sm);
    font-size: 12.5px; line-height: 1.8; color: var(--text-2);
    white-space: pre-wrap; max-height: 320px; overflow: auto;
}

/* ---- 丢单场景 ---- */
.ls {
    background: var(--surface); border: 1px solid var(--line);
    border-radius: var(--r-lg); padding: 18px 20px; margin-bottom: 12px;
}
.ls-hd { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; padding-bottom: 12px; border-bottom: 1px solid var(--line); }
.ls-g {
    font-size: 11px; font-weight: 650; padding: 2px 8px; border-radius: 4px;
    background: var(--accent-soft); color: var(--accent);
}
.ls-rival { font-size: 14.5px; font-weight: 650; color: var(--text); }
.ls-n { margin-left: auto; font-size: 11.5px; color: var(--text-3); font-variant-numeric: tabular-nums; }

.ls-block { margin-top: 14px; }
.ls-k {
    display: block; font-size: 11px; color: var(--text-3);
    letter-spacing: .04em; margin-bottom: 6px;
}
.ls-qs { margin: 0; padding-left: 18px; }
.ls-qs li { font-size: 14px; line-height: 1.8; color: var(--text); }
.ls-quote {
    margin: 0; padding: 10px 14px; background: var(--surface-2);
    border-left: 2px solid var(--line-3); border-radius: 0 var(--r-sm) var(--r-sm) 0;
    font-size: 12.5px; line-height: 1.75; color: var(--text-2);
}
.ls-why { margin: 0; font-size: 14px; line-height: 1.75; color: var(--text-2); }

/* 该补什么 —— 整页的行动项，给它最重的底色 */
.ls-move {
    margin-top: 14px; padding: 13px 15px;
    background: var(--accent-soft); border: 1px solid var(--accent-line);
    border-radius: var(--r-md);
}
.ls-move-to {
    display: inline-block; font-size: 11px; font-weight: 650;
    color: var(--accent); letter-spacing: .03em; margin-bottom: 6px;
}
.ls-move p { margin: 0; font-size: 14px; line-height: 1.75; color: #1c3d8f; }
.ls-ft { margin-top: 10px; font-size: 11px; color: var(--text-4); }

/* ---- 引用源 ---- */
.ci-sec {
    background: var(--surface); border: 1px solid var(--line);
    border-radius: var(--r-lg); padding: 18px 20px; margin-bottom: 14px;
}
.ci-h { margin: 0 0 12px; font-size: 14px; font-weight: 650; color: var(--text); }
.ci-none { margin: 0; font-size: 12.5px; line-height: 1.8; color: var(--text-3); }
.ci-lead { margin: 0 0 12px; font-size: 12px; color: var(--text-3); }
.ci-tb { width: 100%; border-collapse: collapse; font-size: 14px; }
.ci-tb th {
    text-align: left; font-size: 11px; font-weight: 600; color: var(--text-3);
    padding: 0 0 8px; border-bottom: 1px solid var(--line); letter-spacing: .04em;
}
.ci-tb th.num { text-align: right; }
.ci-tb td { padding: 9px 0; border-bottom: 1px solid var(--line); color: var(--text-2); }
.ci-tb td.num { text-align: right; font-variant-numeric: tabular-nums; }
.ci-tb tr.self td { color: var(--text); font-weight: 600; }
.ci-tb tr:last-child td { border-bottom: 0; }
.ci-me {
    font-size: 10px; font-weight: 650; padding: 1px 5px; border-radius: 3px;
    background: var(--ok-soft); color: var(--ok); margin-left: 6px; vertical-align: 1px;
}

.ci-ents { display: flex; flex-direction: column; gap: 10px; }
.ci-ent {
    border: 1px solid var(--line); border-radius: var(--r-md);
    padding: 12px 14px; background: var(--surface-2);
}
/* 「你站上提过」用绿边：这一栏是要告诉客户「差哪几个」，
   已经覆盖的项应该安静地待在旁边，不该抢走注意力。 */
.ci-ent.covered { border-color: var(--ok-line); background: var(--ok-soft); }
.ci-ent-top { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.ci-type {
    font-size: 10.5px; font-weight: 650; padding: 2px 6px; border-radius: 3px;
    background: var(--surface-3); color: var(--text-2);
}
.ci-type.t-cert { background: var(--warn-soft); color: var(--warn); }
.ci-type.t-standard { background: var(--accent-soft); color: var(--accent); }
.ci-type.t-org { background: #f3eefe; color: #6d3fc4; }
.ci-type.t-brand { background: var(--surface-3); color: var(--text-2); }
.ci-name { font-size: 14px; font-weight: 650; color: var(--text); }
.ci-n { font-size: 11.5px; color: var(--text-3); font-variant-numeric: tabular-nums; }
.ci-flag { margin-left: auto; font-size: 11px; color: var(--text-4); }
.ci-ent.covered .ci-flag { color: var(--ok); font-weight: 600; }
.ci-hint { margin: 8px 0 0; font-size: 12.5px; line-height: 1.75; color: var(--text-2); }

.ci-cav { margin: 0; padding-left: 18px; }
.ci-cav li { font-size: 12.5px; line-height: 1.85; color: var(--text-3); margin-bottom: 6px; }
.ci-cav b { color: var(--text-2); }

/* ---- 站点对比 ---- */
.cmp-pick {
    display: flex; align-items: flex-end; gap: 12px; flex-wrap: wrap;
    background: var(--surface); border: 1px solid var(--line);
    border-radius: var(--r-lg); padding: 16px 18px; margin-bottom: 16px;
}
.cmp-pick label { display: flex; flex-direction: column; gap: 5px; }
.cmp-pick label > span { font-size: 11px; color: var(--text-3); letter-spacing: .02em; }
.cmp-pick select {
    height: 32px; padding: 0 9px; font-size: 12.5px;
    border: 1px solid var(--line-2); border-radius: var(--r-sm);
    background: var(--surface); color: var(--text); min-width: 190px;
}
.cmp-vs { font-size: 12px; color: var(--text-4); padding-bottom: 9px; }

.cmp-verdict {
    padding: 15px 18px; margin-bottom: 16px;
    background: var(--accent-soft); border: 1px solid var(--accent-line);
    border-left: 3px solid var(--accent); border-radius: 0 var(--r-md) var(--r-md) 0;
    font-size: 14px; line-height: 1.75; color: #1c3d8f;
}

.cmp-tb { width: 100%; border-collapse: collapse; font-size: 14px; background: var(--surface);
    border: 1px solid var(--line); border-radius: var(--r-lg); overflow: hidden; }
.cmp-tb th {
    text-align: left; padding: 12px 16px; font-size: 12.5px; font-weight: 650;
    color: var(--text); background: var(--surface-2); border-bottom: 1px solid var(--line);
}
.cmp-tb th small { display: block; font-size: 11px; font-weight: 400; color: var(--text-3); margin-top: 2px; }
.cmp-tb td { padding: 11px 16px; border-bottom: 1px solid var(--line); color: var(--text-2); }
.cmp-tb tr:last-child td { border-bottom: 0; }
.cmp-label { color: var(--text-3) !important; font-size: 12.5px; width: 34%; }
.cmp-tb td.win { color: var(--ok); font-weight: 650; }
.cmp-tb td.lose { color: var(--text-4); }
.cmp-tb tr.is-sum td { background: var(--surface-2); font-weight: 650; color: var(--text); }
.cmp-mark {
    font-size: 10px; font-weight: 650; padding: 1px 5px; border-radius: 3px;
    background: var(--ok-soft); color: var(--ok); margin-left: 7px; vertical-align: 1px;
}
.cmp-foot { margin-top: 14px; font-size: 12px; line-height: 1.8; color: var(--text-3); }
.cmp-foot p { margin: 0 0 6px; }
.cmp-warn { color: var(--warn); }

/* ---- 白标表单 ---- */
.wb-form {
    background: var(--surface); border: 1px solid var(--line);
    border-radius: var(--r-lg); padding: 6px 20px 20px;
}
.wb-row { display: flex; gap: 18px; padding: 16px 0; border-bottom: 1px solid var(--line); align-items: flex-start; }
.wb-row:last-of-type { border-bottom: 0; }
.wb-row > label {
    flex: 0 0 110px; font-size: 12.5px; font-weight: 550; color: var(--text-2);
    padding-top: 8px;
}
.wb-in { flex: 1 1 auto; display: flex; flex-direction: column; gap: 6px; min-width: 0; }
.wb-in input[type=text], .wb-in textarea {
    width: 100%; padding: 8px 11px; font-size: 14px;
    border: 1px solid var(--line-2); border-radius: var(--r-sm);
    background: var(--surface); color: var(--text); font-family: inherit;
}
.wb-in input[type=text]:focus, .wb-in textarea:focus {
    outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-soft);
}
.wb-in textarea { resize: vertical; line-height: 1.7; }
.wb-tip { font-size: 11.5px; color: var(--text-3); line-height: 1.65; }
.wb-err { font-size: 11.5px; color: var(--bad); }
.wb-preview {
    margin-top: 4px; padding: 10px 14px; background: var(--surface-3);
    border: 1px dashed var(--line-2); border-radius: var(--r-sm); align-self: flex-start;
}
.wb-preview img { max-height: 40px; max-width: 200px; object-fit: contain; display: block; }
/* 站内路径验不过时的提示。用 warn 色系，但比 .wb-err 轻 —— 这是提醒不是拒绝保存 */
.wb-dead {
    margin-top: 6px; padding: 8px 12px; font-size: 12.5px; line-height: 1.7;
    color: #8a4207; background: var(--warn-soft);
    border: 1px solid var(--warn-line); border-radius: var(--r-sm); align-self: flex-start;
}
.wb-dead code { font-family: var(--mono); word-break: break-all; }
.wb-color { display: flex; align-items: center; gap: 8px; }
/* 高度跟右边那个 #hex 输入框对齐（8+20+8=36）。
   差 2px 单独看不出来，但两个框并排时就显得「没对齐」。 */
.wb-color input[type=color] {
    width: 38px; height: 36px; padding: 2px; cursor: pointer;
    border: 1px solid var(--line-2); border-radius: var(--r-sm); background: var(--surface);
}
.wb-hex { max-width: 120px; font-family: var(--mono); }
.wb-swatch { display: flex; align-items: center; gap: 6px; }
.wb-swatch span { width: 26px; height: 18px; border-radius: 4px; border: 1px solid rgba(0, 0, 0, .06); }
.wb-swatch em { font-size: 11px; color: var(--text-3); font-style: normal; font-family: var(--mono); }
.wb-check { display: flex; align-items: flex-start; gap: 8px; font-size: 14px; color: var(--text-2); cursor: pointer; }
.wb-check input { margin-top: 2px; }
.wb-actions { display: flex; align-items: center; gap: 10px; padding-top: 18px; flex-wrap: wrap; }
.wb-on { font-size: 11.5px; color: var(--ok); font-weight: 600; }

/* ---- 侧栏分组 ---- */
/* 分组标题：和 .nav-group 是同一类东西，只是这个写在洞察段附近。
   两处都用 --side-text-2，别再各写一份 rgba —— 之前就是这里写着 .26，
   比 .nav-group 的 .3 又暗一档，同一屏里两个分组标题深浅不一。 */
.nav-sep {
    margin: 10px 0 2px; padding: 0 10px;
    font-size: 11.5px; font-weight: 600; letter-spacing: .09em;
    color: var(--side-text-2); text-transform: uppercase;
}

@media (max-width: 760px) {
    .ins-stat { min-width: 88px; padding: 11px 12px; }
    .ins-stat b { font-size: 17px; }
    .cl-row { flex-direction: column; gap: 3px; }
    .cl-k { flex: none; }
    .cmp-pick select { min-width: 0; width: 100%; }
    .cmp-pick label { flex: 1 1 100%; }
    .wb-row { flex-direction: column; gap: 8px; }
    .wb-row > label { flex: none; padding-top: 0; }
    .cmp-tb { font-size: 12px; }
    .cmp-tb th, .cmp-tb td { padding: 9px 10px; }
}

/* 关联站标记：域名主体相同、后缀不同（kosaka-cn.com 与 kosaka-lab.co.jp）。
   这类最容易被误读成「你的站被引了」，实际是另一个主体在替你说话。
   用琥珀色而不是绿色区分，因为它是「看着像但不是」。 */
.ci-kin {
    font-size: 10px; font-weight: 650; padding: 1px 5px; border-radius: 3px;
    background: var(--warn-soft); color: var(--warn); border: 1px solid var(--warn-line);
    margin-left: 6px; vertical-align: 1px;
}
/* 「未核」态：既不是通过也不是失败，用灰边虚线提示「这条我们不知道」 */
.ci-ent.unknown { border-style: dashed; background: var(--surface-2); }
.ci-ent.unknown .ci-flag { color: var(--text-4); }

/* ═══════════════════════════════════════════════════════════════════
   生成报告 · 配置页
   ───────────────────────────────────────────────────────────────────
   这一页只有一个真实目的：让人决定要不要附方案。
   所以视觉上把「三个数字」和「会指出哪几条」先摆出来，
   让他在勾之前就知道自己买的是什么东西。
   ═══════════════════════════════════════════════════════════════════ */
.rp-facts { display: flex; gap: 10px; flex-wrap: wrap; }
.rp-fact {
    flex: 1 1 120px; min-width: 108px;
    padding: 12px 14px;
    background: var(--surface-3); border: 1px solid var(--line);
    border-radius: var(--r-md);
}
.rp-fact b { display: block; font-size: 22px; line-height: 1.15; letter-spacing: -.02em; font-variant-numeric: tabular-nums; }
.rp-fact span { display: block; margin-top: 3px; font-size: 11.5px; color: var(--text-3); }

.rp-willfix { margin: 16px 0 0; padding: 0; list-style: none; counter-reset: rp; }
.rp-willfix li {
    position: relative;
    padding: 10px 12px 10px 36px;
    margin-bottom: 8px;
    border: 1px solid var(--line); border-radius: var(--r-sm);
    background: var(--surface);
    counter-increment: rp;
}
.rp-willfix li::before {
    content: counter(rp);
    position: absolute; left: 11px; top: 11px;
    width: 17px; height: 17px; border-radius: 50%;
    font-size: 10px; line-height: 17px; text-align: center;
    color: #fff; background: var(--text-4);
}
.rp-willfix li.bad::before { background: #d92d20; }
.rp-willfix li.warn::before { background: #b45309; }
.rp-willfix li b { display: block; font-size: 12.5px; margin-bottom: 3px; }
.rp-willfix li span { font-size: 11.5px; color: var(--text-3); line-height: 1.6; }

/* 方案总开关：整块可点，不是只有那个小方框 */
.rp-switch {
    display: flex; gap: 11px; align-items: flex-start;
    padding: 13px 15px; cursor: pointer;
    border: 1px solid var(--line-2); border-radius: var(--r-md);
    background: var(--surface-2);
    transition: border-color .15s var(--ease), background .15s var(--ease);
}
.rp-switch:hover { border-color: var(--accent); background: #fff; }
.rp-switch input { margin-top: 2px; flex: 0 0 auto; width: 15px; height: 15px; cursor: pointer; }
.rp-switch > span > b { display: block; font-size: 14px; margin-bottom: 4px; }
.rp-switch small { display: block; font-size: 11.5px; color: var(--text-3); line-height: 1.8; }
.rp-switch small b { display: inline; font-size: 11.5px; color: var(--text-2); font-weight: 600; }

/* 逐条勾选：缩进一格，视觉上属于上面那个开关 */
.rp-fixpick { margin-top: 14px; padding-left: 26px; }
.rp-fixpick[hidden] { display: none; }
.rp-fixpick-hd { margin: 0 0 8px; font-size: 11.5px; color: var(--text-3); }
.rp-pick {
    display: flex; gap: 9px; align-items: flex-start;
    padding: 8px 10px; margin-bottom: 6px; cursor: pointer;
    border: 1px solid var(--line); border-radius: var(--r-sm);
    background: var(--surface);
    transition: border-color .12s var(--ease), background .12s var(--ease);
}
.rp-pick:hover { border-color: var(--line-2); background: var(--surface-2); }
.rp-pick input { margin-top: 2px; flex: 0 0 auto; width: 14px; height: 14px; cursor: pointer; }
.rp-pick b { font-size: 12px; font-weight: 550; }
.rp-pick em { font-style: normal; margin-left: 7px; font-size: 11px; color: var(--text-4); }

/* ---------------------------------------------------------------- 站点删除面板
   删除按钮和「停用」并排，误点的概率不低。所以这一块的设计目标不是好看，
   是让人在按下去之前先把「会掉多少条」读一遍：
   清单用等宽字体列数字，危险动作压在最下面，确认按钮默认灰着。 */
.site-del-row > td { padding: 0; border-top: 0; }
.site-del {
    margin: 0 0 14px;
    padding: 14px 16px;
    background: var(--bad-soft);
    border: 1px solid var(--bad-line);
    border-radius: 10px;
}
.site-del-hd { display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap; }
.site-del-hd b { font-size: 14px; color: var(--bad); }
.site-del-hd span { font-size: 11.5px; color: var(--text-3); }
.site-del-list { list-style: none; margin: 0 0 8px; padding: 0; }
.site-del-list li {
    display: flex; align-items: baseline; gap: 8px;
    padding: 4px 0; border-bottom: 1px dashed var(--bad-line);
    font-size: 12px; color: var(--text-2);
}
.site-del-list li:last-child { border-bottom: 0; }
.site-del-list code {
    font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
    font-size: 11.5px; color: var(--text-3);
    background: var(--surface); border: 1px solid var(--bad-line);
    border-radius: 4px; padding: 1px 5px; flex: 0 0 auto;
}
.site-del-list b { color: var(--bad); font-variant-numeric: tabular-nums; }
.site-del-list span { color: var(--text-3); }
.site-del-form { margin-top: 12px; padding-top: 12px; border-top: 1px solid var(--bad-line); }
.site-del-form input[type="text"] { max-width: 320px; }
.site-del .btn.danger:disabled {
    opacity: .45; cursor: not-allowed;
    background: transparent; color: var(--text-4); border-color: var(--line-2);
}

/* ------------------------------------------------------------ 问题 ↔ 方案 对照
   两张并排的窄卡片读起来是「两份东西」，这一节要的是「同一条的两面」。
   所以用一张网格：勾选框 / 问题 / 改法，同一视觉行，中间一条竖线。
   问题用常规正文，改法用略浅的字色 —— 视线先落在问题上，再去读改法。 */
.rp-cmp { margin-top: 14px; border: 1px solid var(--line); border-radius: 10px; overflow: hidden; }
.rp-cmp-hd {
    display: grid; grid-template-columns: 34px 1fr 1.35fr;
    background: var(--surface-2); border-bottom: 1px solid var(--line);
    font-size: 11px; letter-spacing: .04em; color: var(--text-4); text-transform: uppercase;
}
.rp-cmp-hd span { padding: 7px 12px; }
/* 表头只有两格，但网格是三列：让「问题」横跨勾选框列和问题列，
   否则它会被塞进 34px 那一格里挤成一团 */
.rp-cmp-hd span:first-child { grid-column: 1 / 3; padding-left: 12px; }
.rp-cmp-hd span:last-child { border-left: 1px solid var(--line); }

.rp-cmp-row {
    display: grid; grid-template-columns: 34px 1fr 1.35fr;
    border-bottom: 1px solid var(--line);
}
.rp-cmp-row:last-child { border-bottom: 0; }
.rp-cmp-row.bad  { background: linear-gradient(90deg, rgba(217,45,32,.028), transparent 42%); }
.rp-cmp-row.warn { background: linear-gradient(90deg, rgba(181,71,0,.026), transparent 42%); }

.rp-cmp-pick {
    display: flex; justify-content: center; align-items: flex-start;
    padding: 14px 0 0; cursor: pointer;
}
.rp-cmp-pick input { width: 15px; height: 15px; cursor: pointer; accent-color: var(--text); }

/* 这一节是「读进去再决定勾不勾」，不是「扫一眼」。
   所以字号按正文给（13 起），不按辅助说明给（11.5）。
   第一版把左右都压在 11.5–12，整段十几行读完眼睛发涩 —— 那一栏是客户掏钱
   买的判断依据，用不到 12px 的灰字写，等于把最贵的内容做成了脚注。 */
.rp-cmp-prob { padding: 14px 14px 14px 0; border-left: 1px solid var(--line); }
.rp-cmp-prob b { display: block; font-size: 14px; font-weight: 600; line-height: 1.5; }
.rp-cmp-prob p { margin: 6px 0 0; font-size: 14px; line-height: 1.7; color: var(--text-2); }
.rp-cmp-prob em {
    display: block; margin-top: 7px; font-style: normal;
    font-size: 12.5px; color: var(--ok);
}

.rp-cmp-plan { padding: 14px 16px; border-left: 1px solid var(--line); background: var(--surface-2); }
.rp-cmp-one + .rp-cmp-one { margin-top: 14px; padding-top: 14px; border-top: 1px dashed var(--line); }
.rp-cmp-one > b { display: block; font-size: 14px; font-weight: 600; line-height: 1.5; }
/* 「为什么」是解释，可以小半档、淡一档；
   「怎么做」是要照着干活的，给足字号和对比度 —— 这两行原来一样大一样淡，
   读起来是一片糊，看不出该先抓哪句。 */
.rp-cmp-one .rp-why { margin: 6px 0 0; font-size: 12.5px; line-height: 1.65; color: var(--text-2); }
.rp-cmp-one .rp-how { margin: 5px 0 0; font-size: 14px; line-height: 1.7;  color: var(--text); }
.rp-cmp-none { margin: 0; font-size: 12.5px; line-height: 1.7; color: var(--text-3); font-style: italic; }

/* 总开关关掉时整块压灰，但不清空 ——
   要让人看得见「不附方案会少掉这些」，而不是看见一个空框 */
.rp-cmp.is-off { opacity: .5; }
.rp-cmp.is-off .rp-cmp-pick input { cursor: not-allowed; }

/* ==========================================================================
   生成报告 · 配置页（rf-*）
   --------------------------------------------------------------------------
   这一页原来的问题是「模板味」，不是丑。三样东西凑在一起就变成任何一个
   AI 生成的表单页：

     1. 三个等宽 KPI 方块 —— dashboard 版式，谁都能套
     2. 卡片左上角那截小竖线 + 标题 —— 2019 年以后所有后台模板都有
     3. 每节底下挂一条彩色提示条 —— 「贴心提示」是机器的语气，不是人的

   重做只做减法，靠三样东西撑版面：

     1. 等宽字体的读数与序号（仪表感，不是装饰）
     2. 一条 1px 线分节（不靠卡片堆叠建立层级）
     3. 留白

   主色只出现在「生成」按钮和勾选条上。圆角收到 4px —— 全站 7–9px 是
   中间值，这一页是「读数 / 定版」的性质，应当更硬一点。
   ========================================================================== */

.rf {
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: 4px;
    overflow: hidden;
}

.rf-sec { padding: 32px 34px; border-bottom: 1px solid var(--line); }
/* 注意：不要写 .rf-sec:last-of-type { border-bottom: 0 }。
   这里的 :last-of-type 按标签算（div），而最后那个 div 是 .rf-foot，
   所以这条选择器一个元素都匹配不到 —— 留着只会让人以为分节线已经处理过了。
   最后一段的分节线正好当底栏的上边线，所以底栏不要再加 border-top。 */

/* 分区标注：等宽、大写、拉开字距，像仪表面板上的丝印。
   用英文是因为它只承担「这是第几块」的定位功能，读不读得懂不影响操作。 */
.rf-eb {
    font-family: var(--mono);
    font-size: 10px; letter-spacing: .16em; text-transform: uppercase;
    color: var(--text-4); font-weight: 500;
    margin-bottom: 18px;
}

/* ---- 读数 ---------------------------------------------------------------- */

.rf-metrics { display: grid; grid-template-columns: repeat(3, 1fr); }
.rf-metric { padding-left: 26px; border-left: 1px solid var(--line); }
.rf-metric:first-child { padding-left: 0; border-left: 0; }
.rf-metric b {
    display: block;
    font-family: var(--mono);
    font-size: 30px; font-weight: 500; line-height: 1;
    letter-spacing: -.02em; font-variant-numeric: tabular-nums;
    color: var(--text);
}
/* 满分跟在数字后面，单位小到只起「这是读数不是编号」的提示作用 */
.rf-metric b small {
    font-size: 12px; font-weight: 400; letter-spacing: 0;
    color: var(--text-4); margin-left: -1px;
}
.rf-metric span { display: block; margin-top: 9px; font-size: 12px; color: var(--text-3); }

.rf-line {
    display: flex; align-items: center; gap: 14px; flex-wrap: wrap;
    margin-top: 24px; padding-top: 18px;
    border-top: 1px dashed var(--line);
}
.rf-line > label { font-size: 12.5px; color: var(--text-2); }
.rf-line select { max-width: 220px; }
.rf-line .rf-hint { font-size: 12px; color: var(--text-3); }

/* 数据不够时的提醒：压成一行灰字，不占用一条彩色横幅的视觉重量。
   它要说的话还是完整的，只是不再抢戏。 */
.rf-warn {
    margin: 14px 0 0; padding-left: 12px;
    border-left: 2px solid var(--warn-line);
    font-size: 12.5px; line-height: 1.7; color: var(--warn);
}

/* ---- 开关 ---------------------------------------------------------------- */

.rf-toggle { display: flex; gap: 12px; align-items: flex-start; cursor: pointer; }
.rf-toggle > span { flex: 1 1 auto; }
.rf-toggle b { display: block; font-size: 14px; font-weight: 600; line-height: 1.5; }
.rf-toggle small { display: block; margin-top: 5px; font-size: 12.5px; line-height: 1.7; color: var(--text-3); }

/* 自绘勾选框：系统中默认的那个圆角方块在浅底上偏软，
   换成细边方形，选中填近黑 —— 比填主色更安静。 */
.rf-ck {
    -webkit-appearance: none; appearance: none;
    flex: 0 0 auto; width: 15px; height: 15px; margin: 2px 0 0;
    border: 1px solid var(--line-3); border-radius: 3px;
    background: var(--surface); cursor: pointer; position: relative;
    transition: background .12s var(--ease), border-color .12s var(--ease);
}
.rf-ck:hover { border-color: var(--text-3); }
.rf-ck:checked { background: var(--text); border-color: var(--text); }
.rf-ck:checked::after {
    content: ''; position: absolute; left: 4px; top: 1px;
    width: 4px; height: 8px;
    border: solid #fff; border-width: 0 1.5px 1.5px 0;
    transform: rotate(45deg);
}
.rf-ck:disabled { cursor: not-allowed; opacity: .4; }

/* ---- 问题 ↔ 改法 -------------------------------------------------------- */

.rf-list { margin-top: 20px; border-top: 1px solid var(--line-2); }

.rf-th,
.rf-row {
    display: grid;
    grid-template-columns: 24px 38px minmax(0, 1fr) minmax(0, 1.14fr);
}
.rf-th {
    padding: 8px 0;
    border-bottom: 1px solid var(--line-2);
    font-family: var(--mono);
    font-size: 10px; letter-spacing: .14em; text-transform: uppercase;
    color: var(--text-4);
}
/* 表头只标两栏，但必须和正文落在同一列上：
   「问题」从第 3 列起（前面是勾选框和编号），「改法」多缩 24px
   跟 .rf-plan 的左内边距对齐，否则两个字的起点差半个字宽，一眼看得出来。 */
.rf-th span:first-child { grid-column: 2 / 3; }
.rf-th span:nth-child(2) { grid-column: 3 / 4; }
.rf-th span:last-child  { grid-column: 4 / 5; padding-left: 24px; }

.rf-row {
    border-bottom: 1px solid var(--line);
    transition: background .1s var(--ease);
}
.rf-row:last-child { border-bottom: 0; }
.rf-row:hover { background: #fcfcfd; }
/* 勾中状态不画整行高度的色条：一行可能有 200px 高，2px 蓝线拉到底
   就变成一条装饰线，三行并排更像贴纸。改成只让序号着色 ——
   扫一眼能数出勾了几条，但不增加任何新的形状。 */
.rf-row.is-on .rf-no { color: var(--accent); }

.rf-pick { display: block; padding: 15px 0 0; }
.rf-no {
    padding: 17px 0 0;
    font-family: var(--mono); font-size: 11px; letter-spacing: .02em;
    color: var(--text-4); font-variant-numeric: tabular-nums;
}

.rf-prob { padding: 14px 24px 16px 0; }
.rf-prob b { display: block; font-size: 14px; font-weight: 600; line-height: 1.5; }
.rf-prob p { margin: 6px 0 0; font-size: 14px; line-height: 1.72; color: var(--text-2); }
.rf-prob em { display: block; margin-top: 6px; font-style: normal; font-size: 12px; color: var(--text-3); }

.rf-plan { padding: 14px 0 16px 24px; border-left: 1px solid var(--line); }
.rf-one + .rf-one { margin-top: 16px; padding-top: 16px; border-top: 1px dashed var(--line); }
/* 右栏字号比左栏大一号，故意的：左栏是「哪儿有问题」，扫一眼就够；
   右栏是「照着做什么」，要逐句读进去。同一张表里让操作侧更重，
   比两边拉平的对称更好用。改法正文 15px —— 这一栏宽约 520px，
   一行 33 个汉字，是中文正文的舒适行长。 */
.rf-one > b { display: block; font-size: 14.5px; font-weight: 600; line-height: 1.5; }
.rf-one .rf-why { margin: 7px 0 0; font-size: 14px; line-height: 1.68; color: var(--text-2); }
.rf-one .rf-how { margin: 6px 0 0; font-size: 15px; line-height: 1.72; color: var(--text); }
.rf-none { margin: 0; font-size: 14px; line-height: 1.7; color: var(--text-3); }

/* 总开关关掉时整块压灰但不清空 —— 要看得见「不附会少掉这些」 */
.rf-list.is-off { opacity: .55; }
.rf-list.is-off .rf-row.is-on { box-shadow: none; }

/* ---- 生成结果条 ----------------------------------------------------------
   夹在清单和底栏之间的一条细线提示。不用弹窗：弹窗要人点「确定」，
   而这里要说的是「已经开好了，你继续」—— 不需要确认的事不该拦一下。 */

.rf-done {
    display: flex; align-items: center; gap: 16px; flex-wrap: wrap;
    padding: 12px 34px;
    /* 白底而不是灰底：下面紧跟着灰底的页脚，两个都用灰会粘成一整块，
       读起来像同一条信息说了两遍 */
    background: var(--surface); border-top: 1px solid var(--line);
    font-size: 14px; color: var(--text-2);
}
.rf-done[hidden] { display: none; }
.rf-done span { font-weight: 600; color: var(--text); }
/* 链接不上色：这一页通篇只有黑白灰，两个蓝字会把视线从结论上拽走。
   用常显的细下划线标出「可以点」，比换颜色安静。 */
.rf-done a {
    color: var(--text-2); text-decoration: none;
    border-bottom: 1px solid var(--line-3);
}
.rf-done a:hover { color: var(--text); border-bottom-color: var(--text); }
.rf-done a[hidden] { display: none; }

/* 失败时才上色。成功不庆祝 —— 报告不在这一页，亮一条绿只是噪音。 */
.rf-done.is-bad { background: var(--bad-soft); border-top-color: var(--bad-line); }
.rf-done.is-bad span { color: var(--bad); font-weight: 500; }

/* ---- 底部动作条 ---------------------------------------------------------- */

.rf-foot {
    display: flex; align-items: center; justify-content: space-between;
    gap: 24px; padding: 16px 34px;
    background: var(--surface-2);
}
.rf-note { margin: 0; font-size: 12px; line-height: 1.6; color: var(--text-3); }
.rf-acts { display: flex; gap: 8px; flex: 0 0 auto; }

/* 这一页的主按钮单独做：全站那套「上下渐变 + 内侧白高光 + 彩色投影」
   是模板感最重的一处，放在一个读数页上尤其不合。
   换成纯色近黑 + 零阴影 —— 定版这个动作要的是干脆，不是发光。 */
.rf-foot .btn { box-shadow: none; border-radius: 4px; }
.rf-foot .btn.primary,
.rf-foot .btn.primary:hover {
    background: var(--text);
    border-color: var(--text);
    color: #fff;
    box-shadow: none;
}
.rf-foot .btn.primary:hover { background: #000; border-color: #000; }


/* ---------------------------------------------------------------- 窄屏
   四列（勾选 / 编号 / 问题 / 改法）在 820px 以下会挤得没法读。
   改成上下堆叠：改法落到问题下面，用一条虚线隔开 —— 手机上不可能并排，
   但「这条问题配这个改法」的从属关系必须还在。 */
@media (max-width: 820px) {
    .rf-sec { padding: 22px 18px; }
    .rf-metrics { grid-template-columns: 1fr; row-gap: 18px; }
    .rf-metric { padding-left: 0; border-left: 0; }

    .rf-th { display: none; }
    .rf-row { grid-template-columns: 24px 1fr; }
    .rf-no { padding: 0 0 0 4px; align-self: start; }
    .rf-prob { grid-column: 2; padding: 12px 0 0; }
    .rf-plan {
        grid-column: 2; margin-top: 12px; padding: 12px 0 14px;
        border-left: 0; border-top: 1px dashed var(--line);
    }
    /* 堆叠以后字号必须拉平。并排时 13 / 15 那 2px 是「问题轻、改法重」的
       层级；上下摞成一条竖流之后，同样的 2px 只会读成上小下大 ——
       像两段从别处抄来的稿子拼在一起。手机上统一 15px 正文。 */
    .rf-prob b { font-size: 14.5px; }
    .rf-prob p { font-size: 15px; line-height: 1.7; }
    .rf-prob em { font-size: 14px; }
    .rf-none { font-size: 15px; }

    .rf-foot { flex-direction: column; align-items: stretch; padding: 14px 18px; }
    .rf-acts { justify-content: flex-end; }

    /* 提示条在窄屏会折成三行，间距收紧一点，不然比上面的清单还高 */
    .rf-done { padding: 10px 18px; gap: 10px; }
}
