/**
 * 主题切换：阿罗娜（浅色，默认）/ 普拉娜（深色）
 * ==================================================================
 * 分两层：
 *   ① 变量层 —— 每个主题一组变量，覆盖 assets/style.css 里 :root 的同名
 *      变量（style.css 里 240 多处都引用它们，全站底色/文字/边框/强调色跟着变）；
 *   ② 补丁层 —— style.css 里还有一批**写死的颜色**（表头、按钮渐变、状态色、
 *      各种提示条 / 弹窗 / 徽章 / 上传区 / SM 区），它们不跟变量走，
 *      所以统一在文件末尾用一组规则抬到变量上。
 *
 * ★ 「夜晚」这个主题已经不在名单里了，但本文件里**仍然没有**它的变量块 ——
 *   style.css 的 :root 就是夜晚的配色，那里一个字节都不能动（那张表只是从下拉框里去掉）。
 *   ★ 于是有一个必须守住的点：<html> 上**没有** data-theme 时（JS 被禁），
 *     页面就会回落到 style.css 的 :root = 夜晚的深蓝。所以 assets/theme.js
 *     保证**永远**至少打一个 data-theme（读不到 / 非法值都设 alona）。
 * ★ 只改颜色：补丁层里不出现 width / height / padding / margin / font-size /
 *   border-radius / display，布局、字号、间距、圆角一概不动。
 * ★ 为什么补丁层能盖住 style.css：选择器写作 html[data-theme]:not(...) 开头，
 *   比 style.css 里的单类名规则更具体，所以不用 !important；
 *   同时也盖得住 maps.php / check.php 里自带 <style> 里的同名类。
 * ★ 补丁层只对"有 data-theme 且不是夜晚"生效 —— 两个主题都吃，夜晚那条历史路线不吃。
 *
 * 变量命名：
 *   --bg / --text / --accent …      style.css 原本就有的（这里只是换值）
 *   --bg-soft / --bg-card           style.css 引用了但一直没定义的两个，顺手补上
 *   --t-xxx                         本文件新增：专门给补丁层用的
 *   --fx-xxx                        本文件新增：④ 段流光的浓度 / 配色（见那一段的 E0）
 */

/* ==================================================================
 * ① 变量层
 * ================================================================== */

/* ==================================================================
 * ★★★ 阿罗娜（alona）—— 想自己调色，改的就是下面这一块 ★★★
 * ------------------------------------------------------------------
 * 这一块里每一行 = 这套主题的一个颜色。想换成别的粉、别的蓝、别的角色配色，
 * **只改这里的值就行，不用碰任何别的文件**：
 *   · --bg / --bg-2 / --bg-3                 页面底 / 卡片 / 内嵌块
 *   · --bg-hover / --border / --border-soft  悬停底 / 描边 / 浅描边
 *   · --text / --text-dim / --text-faint     正文 / 次要字 / 最淡的字
 *   · --accent / --accent-2                  主色（按钮）/ 强调色（链接、数字）
 *   · --green / --lime / --yellow / --orange / --red   状态色（在线 / 警告 / 离线）
 *   · --shadow                               卡片投影
 *   · --t-xxx                                表头 / 标签 / 提示条 / 按钮那些的配套色
 *   · --t-bg-image / --t-spinner             页面底那两团柔光 / 转圈的颜色
 * 改完刷新页面就生效。★ 改浅色的时候记得确认字还看得清 ——
 * 跑 `node tests/test_theme_contrast.js` 会把每一对的前景/背景对比度算给你看
 * （要求 ≥ 4.5:1）。
 * ================================================================== */

/* ---------------- 阿罗娜：极浅的粉白底 + 青蓝强调色（画面里那两位的调子） ---------------- */
html[data-theme="alona"] {
    --bg:            #fdf4f7;
    /* ★ 卡片 / 表格 / 内嵌块全部是**不透明**的（--bg-2 / --bg-3 / --t-* 那一批也都是纯色或
       纯色渐变，没有一处 rgba）：流光那一层画在页面底之上、正文之下，
       卡片一不透明，光就**扫不进卡片里**，卡片里的字对比度一点不受影响（实测 11~15:1）。
       这也是"光可以开得很浓"的前提 —— 加浓只影响卡片之间 / 页头 / 页脚那些留白。 */
    --bg-2:          #ffffff;
    --bg-3:          #f7ebf2;
    --bg-hover:      #f3e2ec;
    --border:        #e9d3e2;
    --border-soft:   #f2e3ec;
    --text:          #3a3450;
    /* ★ 这两行是"流光的余量"，不是随便挑的：
       页面底上的流光只会把浅底**压深**，而页头副标题 / 页脚那两行字就压在上面。
       这一版把流光又加浓了一档（见 ④ 段），所以 --text-dim / --text-faint
       各往下走一档（#564f6c→#4f4866、#635b7b→#554e6d）：
       页面底最暗压到 L≈0.62 时，这两行字仍有 5.4:1 / 4.9:1（实测数字见报告）。 */
    --text-dim:      #4f4866;
    --text-faint:    #554e6d;
    --accent:        #297a9e;
    --accent-2:      #1f6a8c;
    --green:         #2f7d5a;
    --lime:          #4e6a1c;
    --yellow:        #86601a;
    --orange:        #a5561c;
    --red:           #b03a5c;
    --shadow:        0 8px 28px rgba(110, 70, 95, .14);
    --bg-soft:       #f7ebf2;
    --bg-card:       #ffffff;

    --t-strong:      #322c48;
    --t-strong-2:    #453e5e;
    --t-mute:        #5f5875;
    /* ★ 表头 / 统计块 / 主按钮都改成**很淡的渐变**：斜着来一点方向感，别平得像贴纸 */
    --t-head-bg:     linear-gradient(180deg, #fbeef6, #f4e2ee);
    --t-head-fg:     #645a78;
    --t-panel:       #fdf3f8;
    --t-panel-2:     #f8e9f2;
    --t-code-bg:     #f9eef5;
    --t-code-fg:     #463f5e;
    --t-track:       #eddbe7;
    --t-logo-bg:     linear-gradient(145deg, #f6dfec, #fdf4f8);
    --t-logo-fg:     #1f6a8c;
    --t-logo-bd:     #e7cfe0;
    --t-stat-bg:     linear-gradient(160deg, #ffffff 0%, #fdf4f8 56%, #f4f0fa 100%);
    --t-stat-bg-h:   linear-gradient(160deg, #fff8fb 0%, #f9ecf5 56%, #efeaf8 100%);
    --t-btn-bg:      linear-gradient(180deg, #ffffff, #fbf0f6);
    --t-btn-bd:      #e7cfe0;
    --t-btn-bg-h:    linear-gradient(180deg, #fff7fb, #f5e3ee);
    --t-btn-bd-h:    #d3aac6;
    /* ★ 主按钮：改成 135° 斜向青蓝渐变（最浅那一档仍卡在 #2a7c9c，白字 4.71:1 打底） */
    --t-primary-bg:  linear-gradient(135deg, #2a7c9c 0%, #236d89 50%, #1b5b74 100%);
    --t-primary-bd:  #297a9e;
    --t-primary-bg-h:linear-gradient(135deg, #26738f 0%, #1f6480 50%, #17536b 100%);
    --t-danger-bg:   linear-gradient(180deg, #b8405f, #92304a);
    --t-danger-bd:   #b03a5c;
    --t-danger-fg:   #ffffff;
    --t-danger-bg-h: linear-gradient(180deg, #c24a68, #9a3450);
    --t-mini-bg:     #fbeaf3;
    --t-mini-fg:     #524a68;
    --t-mini-bd:     #ecd2e2;
    --t-mini-bg-h:   #f7dcea;
    --t-mini-fg-h:   #3a3450;
    --t-mini-bd-h:   #d5aac4;
    --t-ok-bg:       #e6f6ee;
    --t-ok-bg-2:     #d2edde;
    --t-ok-fg:       #1b6042;
    --t-ok-bd:       #a9d6bb;
    --t-info-bg:     #e6f2f8;
    --t-info-bg-2:   #d3e9f3;
    --t-info-fg:     #1c5a78;
    --t-info-bd:     #b3d5e6;
    --t-warn-bg:     #fdf3dd;
    --t-warn-bg-2:   #f8e8c4;
    --t-warn-fg:     #74521a;
    --t-warn-bd:     #e6d09c;
    --t-bad-bg:      #fde9f0;
    --t-bad-bg-2:    #f9d5e2;
    --t-bad-fg:      #9c2f4c;
    --t-bad-bd:      #efc0d2;
    --t-purple-bg:   #f1ebfb;
    --t-purple-bg-2: #e3d8f6;
    --t-purple-fg:   #553a8b;
    --t-purple-bd:   #d3c3ef;
    --t-mute-bg:     #f8eef4;
    --t-mute-fg:     #5a526e;
    --t-mute-bd:     #e8d6e2;
    /* ★ 页面底：两团柔光压在一个**对角渐变**上（左上粉白 → 右下极浅青），
       是 body 的最底层；上面还有 .fx 那层会动的流光（见下面 ④ D~F）。
       ★ 对角渐变每一档的相对亮度都不低于 --bg，所以它自己一点对比度都不吃。 */
    --t-bg-image:    radial-gradient(1200px 500px at 15% -10%, rgba(74, 159, 196, .12), transparent 70%),
                     radial-gradient(900px 420px at 95% 0%, rgba(224, 138, 180, .13), transparent 70%),
                     linear-gradient(158deg, #fdf4f7 0%, #fcf4fa 30%, #f6f6fd 62%, #eff8fd 100%);
    --t-spinner:     rgba(74, 159, 196, .30);
}

/* ---------------- 普拉娜：同一套配色的深色版（墨紫底 + 提亮过的青蓝） ----------------
 * ★ 色相和「阿罗娜」完全一致（青蓝 / 粉 / 蓝紫），只是把明度翻过来：
 *     粉白底 #fdf4f7      → 墨紫底 #1a1622（保留一点粉调，不是死黑）
 *     深蓝紫字 #3a3450    → 浅粉白字 #ece6f2
 *     青蓝强调 #297a9e    → 提亮成 #6fc4e8（深底上原色只有 2.6:1，看不清）
 * ★ 主按钮例外：它上面是**白字**，所以按钮底色必须留在深色区间
 *   （#2a6f92→#1b4d68，白字 5.6:1 起）—— 提亮的是"强调色"，不是"按钮底"。
 * ★ --text-dim / --text-faint 这一版**又提亮了一档**（#ded5e8→#e4ddf0、
 *   #c9bfd8→#ded7e8）：深色底上的流光只会把底**提亮**，这两行字就是它的上限；
 *   提亮之后页面底可以多亮 40% 还保持 ≥4.7:1 —— 深色主题的流光因此能开得更浓。
 * ★ 变量名和「阿罗娜」逐字一致（各 76 个），补丁层对两套都成立。 */
html[data-theme="plana"] {
    --bg:            #1a1622;
    --bg-2:          #221d2c;
    --bg-3:          #2a2438;
    --bg-hover:      #2f2840;
    --border:        #3d3450;
    --border-soft:   #332b45;
    --text:          #ece6f2;
    /* ★ 这两行是"流光的余量"，深色主题里它们是**往上**提的：
       页面底上的流光只会把深底**提亮**，压在最亮那层光上的就是这两行字。
       这一版把它们提到接近白（#ded5e8→#efe9f9、#c9bfd8→#e9e3f4），
       页面底最亮到 L≈0.12 时仍有 4.8:1 以上 —— 深色主题的光因此能比上一版更浓。 */
    --text-dim:      #efe9f9;
    --text-faint:    #e9e3f4;
    --accent:        #6fc4e8;
    --accent-2:      #86d3f2;
    --green:         #5fd39a;
    --lime:          #bcd964;
    --yellow:        #e9c25e;
    --orange:        #f0a566;
    --red:           #f2789a;
    --shadow:        0 8px 28px rgba(0, 0, 0, .55);
    --bg-soft:       #221d2c;
    --bg-card:       #221d2c;

    --t-strong:      #f5f0fa;
    --t-strong-2:    #e6ddf0;
    --t-mute:        #c9bfd8;
    --t-head-bg:     linear-gradient(180deg, #2d2539, #251f30);
    --t-head-fg:     #c8bed6;
    --t-panel:       #241f2e;
    --t-panel-2:     #2b2438;
    --t-code-bg:     #241e30;
    --t-code-fg:     #ded5ea;
    --t-track:       #3a3148;
    --t-logo-bg:     linear-gradient(145deg, #263a49, #221d2c);
    --t-logo-fg:     #86d3f2;
    --t-logo-bd:     #3a4b5c;
    --t-stat-bg:     linear-gradient(160deg, #272133 0%, #221d2c 56%, #241f30 100%);
    --t-stat-bg-h:   linear-gradient(160deg, #2d2539 0%, #272133 56%, #2a2438 100%);
    --t-btn-bg:      linear-gradient(180deg, #2b2438, #241f2e);
    --t-btn-bd:      #3d3450;
    --t-btn-bg-h:    linear-gradient(180deg, #332b42, #2a2436);
    --t-btn-bd-h:    #52456b;
    /* 白字压在深青蓝渐变上：最浅那一档 #2a6f92 也有 5.6:1 */
    --t-primary-bg:  linear-gradient(135deg, #2a6f92 0%, #23607f 50%, #1b4d68 100%);
    --t-primary-bd:  #31789c;
    --t-primary-bg-h:linear-gradient(135deg, #2f7ba1 0%, #27688a 50%, #1e5674 100%);
    --t-danger-bg:   linear-gradient(180deg, #8e3350, #6e2740);
    --t-danger-bd:   #a03c5b;
    --t-danger-fg:   #ffeef4;
    --t-danger-bg-h: linear-gradient(180deg, #9c3a59, #7a2c47);
    --t-mini-bg:     #2b2438;
    --t-mini-fg:     #cec4dc;
    --t-mini-bd:     #3d3450;
    --t-mini-bg-h:   #352c46;
    --t-mini-fg-h:   #f5f0fa;
    --t-mini-bd-h:   #52456b;
    --t-ok-bg:       #1e3a2e;
    --t-ok-bg-2:     #254838;
    --t-ok-fg:       #86dcb2;
    --t-ok-bd:       #2c5741;
    --t-info-bg:     #1d3245;
    --t-info-bg-2:   #24425a;
    --t-info-fg:     #96d1ec;
    --t-info-bd:     #2b4c66;
    --t-warn-bg:     #3a2f1a;
    --t-warn-bg-2:   #4a3c21;
    --t-warn-fg:     #e9c87e;
    --t-warn-bd:     #5c4a28;
    --t-bad-bg:      #3b1f2c;
    --t-bad-bg-2:    #4c2838;
    --t-bad-fg:      #f5a2ba;
    --t-bad-bd:      #5e3040;
    --t-purple-bg:   #2e2544;
    --t-purple-bg-2: #3a2f55;
    --t-purple-fg:   #c9b6f2;
    --t-purple-bd:   #463a66;
    --t-mute-bg:     #2a2436;
    --t-mute-fg:     #bcb2ce;
    --t-mute-bd:     #3a3148;
    /* ★ 页面底：和「档案」同一条对角渐变（左上 → 右下），只是换成深色档 ——
       每一档的相对亮度都不高于 --bg，所以它自己一点对比度都不吃。 */
    --t-bg-image:    radial-gradient(1200px 500px at 15% -10%, rgba(111, 196, 232, .10), transparent 70%),
                     radial-gradient(900px 420px at 95% 0%, rgba(224, 138, 180, .08), transparent 70%),
                     linear-gradient(158deg, #1a1622 0%, #1b1726 30%, #1c1a2b 62%, #1b2030 100%);
    --t-spinner:     rgba(111, 196, 232, .30);
}
/* ==================================================================
 * ② 补丁层：只对非夜晚主题生效（夜晚一个字节都不碰）
 * ================================================================== */

/* ---------------- 主题下拉框（标题右边那个） ---------------- */

/* 标题 + 下拉框排一行；窄屏放不下就整体换行，不会把标题挤扁 */
.title-row {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 10px;
    min-width: 0;          /* 长服务器名时允许整块收缩，标题照旧在 .brand-text 里 */
}

.theme-pick {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    flex: none;
    font-size: 12px;
    color: var(--text-dim);
    white-space: nowrap;
}

.theme-pick .theme-sel {
    height: 28px;
    padding: 0 6px;
    font-size: 12.5px;
}

/* ---------------- 页面底色上的柔光 ---------------- */
html[data-theme]:not([data-theme="night"]) body { background-image: var(--t-bg-image); }

/* ---------------- 顶部：logo / 统计块 ---------------- */
html[data-theme]:not([data-theme="night"]) .brand-logo {
    background: var(--t-logo-bg);
    border-color: var(--t-logo-bd);
    color: var(--t-logo-fg);
    box-shadow: inset 0 1px 0 rgba(255, 255, 255, .55);
}
html[data-theme]:not([data-theme="night"]) .stat { background: var(--t-stat-bg); }
html[data-theme]:not([data-theme="night"]) .stat-peak:hover { background: var(--t-stat-bg-h); }

/* ---------------- 按钮 ---------------- */
html[data-theme]:not([data-theme="night"]) .btn { background: var(--t-btn-bg); border-color: var(--t-btn-bd); }
html[data-theme]:not([data-theme="night"]) .btn:hover { background: var(--t-btn-bg-h); border-color: var(--t-btn-bd-h); }
html[data-theme]:not([data-theme="night"]) .btn-primary { background: var(--t-primary-bg); border-color: var(--t-primary-bd); color: #fff; }
html[data-theme]:not([data-theme="night"]) .btn-primary:hover { background: var(--t-primary-bg-h); border-color: var(--t-primary-bd); }
html[data-theme]:not([data-theme="night"]) .btn-danger { background: var(--t-danger-bg); border-color: var(--t-danger-bd); color: var(--t-danger-fg); }
html[data-theme]:not([data-theme="night"]) .btn-danger:hover { background: var(--t-danger-bg-h); border-color: var(--t-danger-bd); }
html[data-theme]:not([data-theme="night"]) .btn-danger:disabled,
html[data-theme]:not([data-theme="night"]) .btn-danger:disabled:hover,
html[data-theme]:not([data-theme="night"]) .btn-danger:disabled:active {
    background: var(--t-mini-bg);
    border-color: var(--t-mini-bd);
    color: var(--t-mini-fg);
}
html[data-theme]:not([data-theme="night"]) .btn-mini { background: var(--t-mini-bg); border-color: var(--t-mini-bd); color: var(--t-mini-fg); }
html[data-theme]:not([data-theme="night"]) .btn-mini:hover { background: var(--t-mini-bg-h); border-color: var(--t-mini-bd-h); color: var(--t-mini-fg-h); }
html[data-theme]:not([data-theme="night"]) .btn-mini:disabled:hover { background: var(--t-mini-bg); border-color: var(--t-mini-bd); color: var(--t-mini-fg); }
html[data-theme]:not([data-theme="night"]) .btn-mini.is-connect:hover { background: var(--t-primary-bg); border-color: var(--t-primary-bd); color: #fff; }
html[data-theme]:not([data-theme="night"]) .btn-mini.is-here { background: var(--t-ok-bg); border-color: var(--t-ok-bd); color: var(--t-ok-fg); }
html[data-theme]:not([data-theme="night"]) .btn-mini.is-here:hover { background: var(--t-ok-bg-2); border-color: var(--t-ok-bd); color: var(--t-ok-fg); }
html[data-theme]:not([data-theme="night"]) .btn-mini.is-sm { background: var(--t-purple-bg); border-color: var(--t-purple-bd); color: var(--t-purple-fg); }
html[data-theme]:not([data-theme="night"]) .btn-mini.is-sm:hover { background: var(--t-purple-bg-2); border-color: var(--t-purple-bd); color: var(--t-purple-fg); }
html[data-theme]:not([data-theme="night"]) .btn-cancel,
html[data-theme]:not([data-theme="night"]) .btn-cancel-del { background: var(--t-warn-bg); border-color: var(--t-warn-bd); color: var(--t-warn-fg); }
html[data-theme]:not([data-theme="night"]) .btn-cancel:hover,
html[data-theme]:not([data-theme="night"]) .btn-cancel-del:hover { background: var(--t-warn-bg-2); border-color: var(--t-warn-bd); color: var(--t-warn-fg); }
html[data-theme]:not([data-theme="night"]) .btn-direct { background: var(--t-info-bg); border-color: var(--t-info-bd); color: var(--t-info-fg); }
html[data-theme]:not([data-theme="night"]) .btn-direct:hover { background: var(--t-info-bg-2); border-color: var(--t-info-bd); color: var(--t-info-fg); }

/* ---------------- 表头 / 卡片 / 面板 ---------------- */
html[data-theme]:not([data-theme="night"]) .server-table thead th,
html[data-theme]:not([data-theme="night"]) .ck th,
html[data-theme]:not([data-theme="night"]) .modal-head { background: var(--t-head-bg); color: var(--t-head-fg); }
html[data-theme]:not([data-theme="night"]) .ck { background: var(--bg-2); border-color: var(--border); }
html[data-theme]:not([data-theme="night"]) .box { background: var(--bg-2); border-color: var(--border); }
html[data-theme]:not([data-theme="night"]) .now-row { background: var(--t-panel); }
html[data-theme]:not([data-theme="night"]) .modal-close:hover { color: var(--text); }
html[data-theme]:not([data-theme="night"]) code.mono { background: var(--t-code-bg); color: var(--t-code-fg); }
html[data-theme]:not([data-theme="night"]) pre { background: var(--t-code-bg); border-color: var(--border-soft); color: var(--t-code-fg); }
html[data-theme]:not([data-theme="night"]) .form-row input { background: var(--bg-2); border-color: var(--border); color: var(--text); }
html[data-theme]:not([data-theme="night"]) .qq-qr-miss { background: var(--t-panel); }
html[data-theme]:not([data-theme="night"]) .qq-num:hover { background: var(--t-panel-2); }

/* 原本写死的浅色正文（深色底上是亮的，浅色底上必须翻过来） */
html[data-theme]:not([data-theme="night"]) .srv-title,
html[data-theme]:not([data-theme="night"]) .players-num,
html[data-theme]:not([data-theme="night"]) .srv-map .map-campaign,
html[data-theme]:not([data-theme="night"]) .kv b,
html[data-theme]:not([data-theme="night"]) .op-box h3,
html[data-theme]:not([data-theme="night"]) .file-list li b,
html[data-theme]:not([data-theme="night"]) .plist .p-name,
html[data-theme]:not([data-theme="night"]) .now-row .now-value,
html[data-theme]:not([data-theme="night"]) .cf-title,
html[data-theme]:not([data-theme="night"]) #opLock .ol-title,
html[data-theme]:not([data-theme="night"]) .qq-name { color: var(--t-strong); }

html[data-theme]:not([data-theme="night"]) .srv-map,
html[data-theme]:not([data-theme="night"]) .ban-row code { color: var(--t-strong-2); }

html[data-theme]:not([data-theme="night"]) .srv-mode,
html[data-theme]:not([data-theme="night"]) .srv-map .map-unknown-code { color: var(--t-mute); }

html[data-theme]:not([data-theme="night"]) .ban-note,
html[data-theme]:not([data-theme="night"]) .audit-sub,
html[data-theme]:not([data-theme="night"]) .audit-time i,
html[data-theme]:not([data-theme="night"]) .here-cap,
html[data-theme]:not([data-theme="night"]) .here-who i,
html[data-theme]:not([data-theme="night"]) .hint { color: var(--t-mute); }

/*
 * ★ 只有这几条用 !important：assets/app.js 生成的表格内容带着**内联 style**
 *   （写死的深色主题灰 #61717f / #8b9bab 和红 #d9534f），内联样式优先级最高，
 *   不 !important 盖不住 —— 在浅色底上它们分别是 4.1~5.0、2.6~2.9、3.6~4.0:1，
 *   有两处不达标。选择器里的 [style] 保证只打这些带内联色的节点。
 */
html[data-theme]:not([data-theme="night"]) .srv-mode[style],
html[data-theme]:not([data-theme="night"]) .players-num[style],
html[data-theme]:not([data-theme="night"]) .srv-map[style] { color: var(--t-mute) !important; }
html[data-theme]:not([data-theme="night"]) .loading[style] { color: var(--red) !important; }
html[data-theme]:not([data-theme="night"]) .loading[style] span[style] { color: var(--t-mute) !important; }

/* ---------------- 列表页：进度条 / 状态 / 徽章 ---------------- */
html[data-theme]:not([data-theme="night"]) .players-bar { background: var(--t-track); }
html[data-theme]:not([data-theme="night"]) .players-bar.is-busy span { background: linear-gradient(90deg, var(--orange), var(--yellow)); }
html[data-theme]:not([data-theme="night"]) .players-bar.is-full span { background: linear-gradient(90deg, var(--red), var(--red)); }
html[data-theme]:not([data-theme="night"]) .spinner { border-color: var(--t-spinner); border-top-color: var(--accent-2); }

html[data-theme]:not([data-theme="night"]) .ok,
html[data-theme]:not([data-theme="night"]) .ping-good,
html[data-theme]:not([data-theme="night"]) .status-online { color: var(--green); }
html[data-theme]:not([data-theme="night"]) .bad,
html[data-theme]:not([data-theme="night"]) .ping-bad { color: var(--red); }
html[data-theme]:not([data-theme="night"]) .warn,
html[data-theme]:not([data-theme="night"]) .ping-mid,
html[data-theme]:not([data-theme="night"]) .status-slow { color: var(--yellow); }
html[data-theme]:not([data-theme="night"]) .ping-ok { color: var(--lime); }
html[data-theme]:not([data-theme="night"]) .status-online::before { background: var(--green); box-shadow: 0 0 7px var(--t-ok-bd); }
html[data-theme]:not([data-theme="night"]) .status-slow::before { background: var(--yellow); }
html[data-theme]:not([data-theme="night"]) .status-querying { color: var(--t-info-fg); }
html[data-theme]:not([data-theme="night"]) .status-querying::before { background: var(--t-info-fg); }

/* 标签 / 模式徽章：一组语义底色，「档案」浅色/深色各给一份值 */
html[data-theme]:not([data-theme="night"]) .tag-group,
html[data-theme]:not([data-theme="night"]) .mode-unknown,
html[data-theme]:not([data-theme="night"]) .sm-state.is-off,
html[data-theme]:not([data-theme="night"]) .sm-state.is-unknown,
html[data-theme]:not([data-theme="night"]) .sm-tag.is-bot { background: var(--t-mute-bg); color: var(--t-mute-fg); border-color: var(--t-mute-bd); }

html[data-theme]:not([data-theme="night"]) .tag-region,
html[data-theme]:not([data-theme="night"]) .map-tag-custom,
html[data-theme]:not([data-theme="night"]) .mode-coop,
html[data-theme]:not([data-theme="night"]) .sm-tag.is-team { background: var(--t-info-bg); color: var(--t-info-fg); border-color: var(--t-info-bd); }

html[data-theme]:not([data-theme="night"]) .tag-vac,
html[data-theme]:not([data-theme="night"]) .map-tag-official,
html[data-theme]:not([data-theme="night"]) .mode-survival,
html[data-theme]:not([data-theme="night"]) .tag-here,
html[data-theme]:not([data-theme="night"]) .sm-state.is-on,
html[data-theme]:not([data-theme="night"]) .sm-tag.is-on,
html[data-theme]:not([data-theme="night"]) .sm-srv-state.is-on { background: var(--t-ok-bg); color: var(--t-ok-fg); border-color: var(--t-ok-bd); }

html[data-theme]:not([data-theme="night"]) .tag-bot,
html[data-theme]:not([data-theme="night"]) .map-tag-unknown,
html[data-theme]:not([data-theme="night"]) .mode-scavenge,
html[data-theme]:not([data-theme="night"]) .sm-tag.is-hp { background: var(--t-warn-bg); color: var(--t-warn-fg); border-color: var(--t-warn-bd); }

html[data-theme]:not([data-theme="night"]) .mode-versus { background: var(--t-warn-bg); color: var(--t-warn-fg); border-color: var(--t-warn-bd); }
html[data-theme]:not([data-theme="night"]) .mode-realism,
html[data-theme]:not([data-theme="night"]) .mode-mutation,
html[data-theme]:not([data-theme="night"]) .sm-tag.is-idle { background: var(--t-purple-bg); color: var(--t-purple-fg); border-color: var(--t-purple-bd); }
html[data-theme]:not([data-theme="night"]) .mode-realism-versus,
html[data-theme]:not([data-theme="night"]) .sm-tag.is-dead,
html[data-theme]:not([data-theme="night"]) .sm-srv-state.is-off { background: var(--t-bad-bg); color: var(--t-bad-fg); border-color: var(--t-bad-bd); }

/* ---------------- 提示条 / 身份横幅 ---------------- */
html[data-theme]:not([data-theme="night"]) .alert-ok,
html[data-theme]:not([data-theme="night"]) .alert-here { background: var(--t-ok-bg); border-color: var(--t-ok-bd); color: var(--t-ok-fg); }
html[data-theme]:not([data-theme="night"]) .alert-warn,
html[data-theme]:not([data-theme="night"]) .lock-banner { background: var(--t-warn-bg); border-color: var(--t-warn-bd); color: var(--t-warn-fg); }
html[data-theme]:not([data-theme="night"]) .lock-banner b { color: var(--t-warn-fg); }
html[data-theme]:not([data-theme="night"]) .lock-banner-verify { background: var(--t-info-bg); border-color: var(--t-info-bd); color: var(--t-info-fg); }
html[data-theme]:not([data-theme="night"]) .lock-banner-verify b { color: var(--t-info-fg); }
html[data-theme]:not([data-theme="night"]) .alert-here b,
html[data-theme]:not([data-theme="night"]) .here-who { color: var(--t-ok-fg); }
html[data-theme]:not([data-theme="night"]) .here-dot { background: var(--t-ok-fg); }
html[data-theme]:not([data-theme="night"]) .here-srv,
html[data-theme]:not([data-theme="night"]) .here-who b { color: var(--t-strong); }
html[data-theme]:not([data-theme="night"]) .toast-bad { border-color: var(--t-bad-bd); border-left-color: var(--t-bad-fg); color: var(--t-bad-fg); }
html[data-theme]:not([data-theme="night"]) #netOffline .ol-box { border-color: var(--t-bad-bd); }
html[data-theme]:not([data-theme="night"]) #netOffline .ol-title { color: var(--t-bad-fg); }

html[data-theme]:not([data-theme="night"]) .badge-master,
html[data-theme]:not([data-theme="night"]) .master-strip { background: var(--t-warn-bg); border-color: var(--t-warn-bd); color: var(--t-warn-fg); }
html[data-theme]:not([data-theme="night"]) .master-strip b,
html[data-theme]:not([data-theme="night"]) .master-key,
html[data-theme]:not([data-theme="night"]) .master-key b { color: var(--t-warn-fg); }
html[data-theme]:not([data-theme="night"]) .master-strip .btn-mini,
html[data-theme]:not([data-theme="night"]) .master-key .btn-mini { background: var(--t-warn-bg-2); border-color: var(--t-warn-bd); color: var(--t-warn-fg); }
html[data-theme]:not([data-theme="night"]) .master-strip .btn-mini:hover,
html[data-theme]:not([data-theme="night"]) .master-key .btn-mini:hover { background: var(--t-warn-bd); border-color: var(--t-warn-fg); color: var(--t-warn-fg); }
html[data-theme]:not([data-theme="night"]) .master-key b:hover { background: var(--t-warn-bg-2); color: var(--t-warn-fg); }
html[data-theme]:not([data-theme="night"]) .master-key b.is-copied { background: var(--t-ok-bg); color: var(--t-ok-fg); }

html[data-theme]:not([data-theme="night"]) .badge-group,
html[data-theme]:not([data-theme="night"]) .master-strip.is-group { background: var(--t-info-bg); border-color: var(--t-info-bd); color: var(--t-info-fg); }
html[data-theme]:not([data-theme="night"]) .master-strip.is-group b { color: var(--t-info-fg); }
html[data-theme]:not([data-theme="night"]) .master-strip.is-group .btn-mini { background: var(--t-info-bg-2); border-color: var(--t-info-bd); color: var(--t-info-fg); }
html[data-theme]:not([data-theme="night"]) .master-strip.is-group .btn-mini:hover { background: var(--t-info-bd); border-color: var(--t-info-fg); color: var(--t-info-fg); }

html[data-theme]:not([data-theme="night"]) .badge-player,
html[data-theme]:not([data-theme="night"]) .master-strip.is-player { background: var(--t-ok-bg); border-color: var(--t-ok-bd); color: var(--t-ok-fg); }
html[data-theme]:not([data-theme="night"]) .master-strip.is-player b { color: var(--t-ok-fg); }
html[data-theme]:not([data-theme="night"]) .master-strip.is-player .btn-mini { background: var(--t-ok-bg-2); border-color: var(--t-ok-bd); color: var(--t-ok-fg); }
html[data-theme]:not([data-theme="night"]) .master-strip.is-player .btn-mini:hover { background: var(--t-ok-bd); border-color: var(--t-ok-fg); color: var(--t-ok-fg); }
html[data-theme]:not([data-theme="night"]) .foot-logout:hover { color: var(--red); }

/* ---------------- 上传区 ---------------- */
html[data-theme]:not([data-theme="night"]) .up-drop { background: var(--t-panel-2); }
html[data-theme]:not([data-theme="night"]) .up-drop.is-over { background: var(--t-info-bg); }
html[data-theme]:not([data-theme="night"]) .up-bar i { background: linear-gradient(90deg, var(--accent), var(--accent-2)); }
html[data-theme]:not([data-theme="night"]) .up-row.is-done .up-state,
html[data-theme]:not([data-theme="night"]) .up-log-row.is-ok,
html[data-theme]:not([data-theme="night"]) .up-mode.is-sw,
html[data-theme]:not([data-theme="night"]) .up-mode.is-direct { color: var(--green); }
html[data-theme]:not([data-theme="night"]) .up-row.is-done .up-bar i { background: var(--green); }
html[data-theme]:not([data-theme="night"]) .up-row.is-bad .up-state,
html[data-theme]:not([data-theme="night"]) .up-log-row.is-bad,
html[data-theme]:not([data-theme="night"]) .sm-log-row.is-bad { color: var(--red); }
html[data-theme]:not([data-theme="night"]) .up-row.is-bad .up-bar i { background: var(--red); }
html[data-theme]:not([data-theme="night"]) .up-note-relay-off { background: var(--t-warn-bg); border-color: var(--t-warn-bd); color: var(--t-warn-fg); }
html[data-theme]:not([data-theme="night"]) .up-note-relay-off b { color: var(--t-warn-fg); }
html[data-theme]:not([data-theme="night"]) .up-note-relay-off code { background: var(--t-code-bg); }
html[data-theme]:not([data-theme="night"]) .upstrip { background: var(--t-info-bg); border-color: var(--t-info-bd); color: var(--t-info-fg); }
html[data-theme]:not([data-theme="night"]) .upstrip b,
html[data-theme]:not([data-theme="night"]) .upstrip-pct { color: var(--t-info-fg); }
html[data-theme]:not([data-theme="night"]) .upstrip-name { color: var(--t-strong-2); }
html[data-theme]:not([data-theme="night"]) .upstrip-bar { background: var(--t-track); }
html[data-theme]:not([data-theme="night"]) .upstrip-bar i { background: linear-gradient(90deg, var(--accent), var(--accent-2)); }

/* ---------------- 管理页：服务器信息 / 强制重启 / 封禁 ---------------- */
html[data-theme]:not([data-theme="night"]) .force-card { border-color: var(--t-bad-bd); }
html[data-theme]:not([data-theme="night"]) .force-card h2 { color: var(--t-bad-fg); }
html[data-theme]:not([data-theme="night"]) .force-path code { color: var(--t-warn-fg); }
html[data-theme]:not([data-theme="night"]) .force-sample { background: var(--t-code-bg); color: var(--t-code-fg); }
html[data-theme]:not([data-theme="night"]) .ban-mine { background: var(--t-bad-bg); border-color: var(--t-bad-bd); color: var(--t-bad-fg); }
html[data-theme]:not([data-theme="night"]) .boot-splash { background: var(--bg); }
html[data-theme]:not([data-theme="night"]) .boot-title { color: var(--accent-2); }
html[data-theme]:not([data-theme="night"]) .boot-bar i { background: linear-gradient(90deg, var(--accent), var(--accent-2)); }

/* ---------------- 审计日志 ---------------- */
html[data-theme]:not([data-theme="night"]) .audit-card.tone-good { border-color: var(--t-ok-bd); }
html[data-theme]:not([data-theme="night"]) .audit-card.tone-good .audit-num,
html[data-theme]:not([data-theme="night"]) .audit-kind.tone-good { color: var(--t-ok-fg); border-color: var(--t-ok-bd); }
html[data-theme]:not([data-theme="night"]) .audit-card.tone-bad { border-color: var(--t-bad-bd); }
html[data-theme]:not([data-theme="night"]) .audit-card.tone-bad .audit-num,
html[data-theme]:not([data-theme="night"]) .audit-kind.tone-bad { color: var(--t-bad-fg); border-color: var(--t-bad-bd); }
html[data-theme]:not([data-theme="night"]) .audit-card.tone-master { border-color: var(--t-warn-bd); }
html[data-theme]:not([data-theme="night"]) .audit-card.tone-master .audit-num,
html[data-theme]:not([data-theme="night"]) .audit-kind.tone-master,
html[data-theme]:not([data-theme="night"]) .audit-tab.is-on,
html[data-theme]:not([data-theme="night"]) .audit-ip b { color: var(--t-warn-fg); border-color: var(--t-warn-bd); }
html[data-theme]:not([data-theme="night"]) .audit-table tr.tone-master td { background: var(--t-warn-bg); }
html[data-theme]:not([data-theme="night"]) .audit-table tr.tone-bad td { background: var(--t-bad-bg); }

/* ---------------- SM 控制台 ---------------- */
html[data-theme]:not([data-theme="night"]) .sm-btn.is-switch-on { background: var(--t-ok-bg); border-color: var(--t-ok-bd); color: var(--t-ok-fg); }
html[data-theme]:not([data-theme="night"]) .sm-btn.is-switch-on:hover { background: var(--t-ok-bg-2); border-color: var(--t-ok-fg); }
html[data-theme]:not([data-theme="night"]) .sm-head-info b.is-human,
html[data-theme]:not([data-theme="night"]) .sm-who-group.is-human .g-count,
html[data-theme]:not([data-theme="night"]) .sm-who-group.is-human .sm-who-name { color: var(--t-ok-fg); }
html[data-theme]:not([data-theme="night"]) .sm-who-group.is-human .sm-who-name { background: var(--t-ok-bg); border-color: var(--t-ok-bd); }
html[data-theme]:not([data-theme="night"]) .sm-head-info b.is-bot,
html[data-theme]:not([data-theme="night"]) .sm-who-group.is-bot .g-count,
html[data-theme]:not([data-theme="night"]) .sm-who-group.is-bot .sm-who-name { color: var(--t-info-fg); }
html[data-theme]:not([data-theme="night"]) .sm-who-group.is-bot .sm-who-name { background: var(--t-info-bg); border-color: var(--t-info-bd); }
html[data-theme]:not([data-theme="night"]) .sm-who-group.is-si .g-count,
html[data-theme]:not([data-theme="night"]) .sm-who-group.is-si .sm-who-name { color: var(--t-bad-fg); }
html[data-theme]:not([data-theme="night"]) .sm-who-group.is-si .sm-who-name { background: var(--t-bad-bg); border-color: var(--t-bad-bd); }
html[data-theme]:not([data-theme="night"]) .sm-target-card { border-color: var(--t-info-bd); }
html[data-theme]:not([data-theme="night"]) .sm-blocked { border-color: var(--t-bad-bd); background: var(--t-bad-bg); }
html[data-theme]:not([data-theme="night"]) .sm-blocked h2 { color: var(--t-bad-fg); }
html[data-theme]:not([data-theme="night"]) .sm-enter-box { border-color: var(--t-warn-bd); }
html[data-theme]:not([data-theme="night"]) .sm-enter-box h3 { color: var(--t-warn-fg); }
html[data-theme]:not([data-theme="night"]) .sm-enter-box ul b { color: var(--t-bad-fg); }

/* ==================================================================
 * ③ 手机：下拉框不许把标题挤坏
 * ================================================================== */

@media (max-width: 720px) {
    /* .title-row 是 flex + wrap：放不下就把下拉框整块换到下一行，标题不缩字 */
    .title-row { gap: 6px 8px; }
    .theme-pick { font-size: 11.5px; }
    .theme-pick .theme-sel { height: 26px; font-size: 12px; }
}

@media (max-width: 420px) {
    /* 很窄的手机：下拉框占满一行，点起来也好点 */
    .theme-pick { width: 100%; }
    .theme-pick .theme-sel { flex: 1 1 auto; }
}

/* ==================================================================
 * ④ 两个主题专属装饰：层叠修正 / 流光图层 / 渐变 / 纸飞机鼠标
 * ==================================================================
 * ★ 这一整段的**规则**都挂在 html[data-theme]:not([data-theme="night"]) 下 ——
 *   名单里只剩 alona / plana 两个主题，两个都吃这一套：
 *   **同一套 DOM、同一套规则、同一套动画**，只有颜色和浓度不同，
 *   而浓度差别全部收在下面 E0 那两组 --fx-* 变量里。
 *   （★ 变量块本身写成 html[data-theme="alona"] / html[data-theme="plana"]：
 *     :not() 会多带 1 个属性权重，浅色块要是也带守卫，
 *     权重就比后面的深色块高，深色的 --fx-* 会被浅色永远压住。）
 * ★ 别的路线（JS 被禁、没有 data-theme）的光标、渐变、动画**一点不变**：
 *   下面每条规则的选择器都以 html[data-theme 开头，那种情况一个字节都碰不到。
 * ★ 全是装饰：不挡点击（pointer-events: none）、不动布局、
 *   动画只碰 transform / opacity（合成器就能画完，不重排不重绘正文）。
 * ================================================================== */

/* ---------------------------------------------------------------
 * D. ★ 先修一个层叠顺序的坑 —— 原来「流光看不见」的根因
 * ---------------------------------------------------------------
 * style.css 的 `html, body { background: var(--bg) }` 给 html 和 body **都**刷了
 * 不透明背景。于是 body 的背景不会上交给画布，而是自己画一遍；而 z-index:-1 的
 * 伪元素属于**根**层叠上下文的负层，绘制顺序是：
 *     ① html 背景 → ② 负 z 层（那条光带就在这）→ ③ body 自己的背景 …
 * 第 ③ 步整片盖住第 ② 步 —— 光带动画跑得再欢也一像素都看不见
 * （实测：transform 每 3.5 秒移动 792px，但前后两帧的全图像素差 = 0.000%）。
 * 让 body 自己成为层叠上下文（isolation: isolate：不改布局、不改背景、
 * 不改 position:fixed 的包含块），负 z 层就落到 body 背景**之上**、正文**之下** ——
 * 既看得见，又永远压不到字上。顺带把 .brand::before 那圈呼吸光晕也救回来了
 * （它原来是同一个毛病）。 */
html[data-theme]:not([data-theme="night"]) body { isolation: isolate; }

/* ---------------------------------------------------------------
 * E0. ★ 流光的浓度与配色 —— 一套规则，两份数值（阿罗娜 / 普拉娜）
 * ---------------------------------------------------------------
 * 先把"加强"的边界说清楚，这一版的参数全是按它反推的：
 *   · 流光画在**正文之下**（见 D 段），只会改"字后面那层底"的亮度；
 *   · 卡片 / 表格 / 内嵌块全是**不透明的**（--bg-2 / --bg-3 / --t-* 都是纯色或纯色渐变），
 *     光根本扫不进卡片 —— 卡片里的字实测 11~15:1，和流光浓不浓一点关系都没有；
 *   · 真正会被光影响的，只有**直接坐在页面底上的那几行字**：
 *     页头标题 / 副标题、「主题」标签、页脚两行。
 *     → 所以"更明显"的正确做法是：**留白处的光可以开到很浓，正文那几行字留出余量**。
 *
 * 两份数值为什么差这么多：
 *   · 阿罗娜的底接近白（L≈0.92）：**有色的光都是"压深"**，白/极浅冷色才是"提亮"。
 *     所以浅色这一侧的 5 条光带**整条都是白系**（最浅的档 rgba(232,247,255) 自己
 *     L≈0.88，压在流光上只会把底提亮）—— 光带越多越浓，对比度**不降反升**，
 *     5 条全叠在一个像素上也是最白（实测见报告）。
 *     柔光（青/粉/紫）反过来只能压深，它的上限由 --text-faint / --text-dim 反推：
 *     这一版把这两行字各压深一档（见 ① 段），页面底最暗压到 L≈0.62 仍 ≥4.8:1。
 *   · 普拉娜的底接近黑（L≈0.009）：**任何亮色光都是"提亮"**，上限由 --text-faint 反推。
 *     这一版把 --text-faint 提到 #ded7e8（L≈0.70，比上一版亮 28%），
 *     页面底最亮到 L≈0.105 仍 ≥4.7:1 —— 深色主题的光因此可以开得比上一版浓 1.7 倍。
 *   · 实测数字（静态逐对 + 真实渲染像素，含最差动画时刻）见报告。
 * ★ 名字统一 --fx-*，不跟 --t-* 混：--t-* 是补丁层的语义色，两套主题必须同名同数。
 * --------------------------------------------------------------- */
html[data-theme="alona"] {
    /* 三团柔光：青蓝 / 粉 / 紫（就是主题那三个色相）。
     * ★ 浓度是"峰值 + 肩部"两档给的，不是单纯抬峰值：
     *   `radial-gradient(closest-side, A, B 58%, 0)` —— A 是圆心那一点，
     *   B 是**半径 58% 以内都在用**的那一档，也就是画面上真正大面积看到的那层。
     *   只写 A（老写法）时，圆心大多落在视口边缘外，画面上只剩衰减尾巴，
     *   峰值堆到 .4 也还是"淡淡的"。这一版把 B 抬起来：整片留白都染上色，
     *   白色光带扫过去才有对比 —— 这是"流光更明显"的主要来源。
     * ★ B 同时是对比度的上限：它就是"页面底最多被压到多暗"，
     *   由 --text-faint(#554e6d) / --text-dim(#4f4866) 反推（实测数字见报告）。 */
    --fx-a1: radial-gradient(closest-side, rgba(74, 159, 196, .34), rgba(74, 159, 196, .21) 58%, rgba(74, 159, 196, 0));
    --fx-a2: radial-gradient(closest-side, rgba(224, 138, 180, .42), rgba(224, 138, 180, .25) 58%, rgba(224, 138, 180, 0));
    --fx-a3: radial-gradient(closest-side, rgba(130, 110, 190, .34), rgba(130, 110, 190, .21) 58%, rgba(130, 110, 190, 0));
    --fx-a1-dur: 20s;
    --fx-a2-dur: 25s;
    --fx-a3-dur: 30s;

    /* 五条光带，**整条都是白系**（浅色底上只有白是"提亮"，不会吃对比度）：
     * s1/s2/s3 一组（13s，负 delay 错开 1/3 周期）、s4/s5 一组（21s，错开 1/2 周期）
     * —— 每组自己的周期里"哪条在屏幕上"是错开的，任何时刻都至少有一条在扫。
     * ★ 最亮那一档刻意压在 .93 而不是 1.0：纯白会把刷过去的底**顶到饱和**，
     *   饱和之后就分不出"光带在动"了（实测：顶到 1.0 时 t=0 vs t=9s 的变动像素反而少）。
     *   留一点余量，光带扫过时底下的颜色还在变，动感更清楚。 */
    --fx-s1: linear-gradient(102deg,
                 rgba(255, 255, 255, 0) 22%,
                 rgba(232, 247, 255, .52) 30%,
                 rgba(255, 255, 255, .86) 41%,
                 rgba(255, 255, 255, .93) 52%,
                 rgba(238, 250, 255, .56) 62%,
                 rgba(255, 255, 255, 0) 74%);
    --fx-s2: linear-gradient(76deg,
                 rgba(255, 255, 255, 0) 30%,
                 rgba(226, 246, 255, .46) 39%,
                 rgba(255, 255, 255, .82) 47%,
                 rgba(255, 255, 255, .90) 56%,
                 rgba(226, 246, 255, .44) 64%,
                 rgba(255, 255, 255, 0) 74%);
    --fx-s3: linear-gradient(88deg,
                 rgba(255, 255, 255, 0) 26%,
                 rgba(236, 249, 255, .42) 36%,
                 rgba(255, 255, 255, .78) 46%,
                 rgba(255, 255, 255, .88) 54%,
                 rgba(236, 249, 255, .40) 63%,
                 rgba(255, 255, 255, 0) 72%);
    /* s4：窄而亮的"光刃" —— 最像一道扫过去的流光，靠窄来出对比 */
    --fx-s4: linear-gradient(116deg,
                 rgba(255, 255, 255, 0) 36%,
                 rgba(255, 255, 255, .52) 44%,
                 rgba(255, 255, 255, .94) 49%,
                 rgba(255, 255, 255, .96) 51%,
                 rgba(255, 255, 255, .52) 56%,
                 rgba(255, 255, 255, 0) 64%);
    /* s5：很宽的一层柔白 —— 大面积提亮，和窄光刃互补 */
    --fx-s5: linear-gradient(68deg,
                 rgba(255, 255, 255, 0) 14%,
                 rgba(255, 255, 255, .34) 30%,
                 rgba(255, 255, 255, .58) 50%,
                 rgba(255, 255, 255, .34) 70%,
                 rgba(255, 255, 255, 0) 86%);

    --fx-spot: radial-gradient(closest-side, rgba(74, 159, 196, .17), rgba(74, 159, 196, 0));
    /* 页头呼吸光晕：**渐变峰值 × 不透明度峰值** 就是压在标题底下的那层底，
       直接决定标题那几个字还剩多少对比度（两个主题的峰值都是实测反推的）。
       加强的办法是"面积变大 + 最暗那档抬高"（一直在亮），不是一味抬峰值。 */
    --fx-brand: radial-gradient(closest-side, rgba(74, 159, 196, .46), rgba(74, 159, 196, 0) 100%);
    --fx-brand-lo: .26;
    --fx-brand-hi: .38;
    --fx-brand-dur: 5.5s;

    /* 渐变装饰（F 段用）：卡片 / 卡片小标题 / 标题渐变字 / 滚动条 / 选中文字 */
    --fx-card-bg:
        linear-gradient(90deg,
            rgba(41, 122, 158, 0) 0%,
            rgba(41, 122, 158, .50) 18%,
            rgba(224, 138, 180, .46) 62%,
            rgba(41, 122, 158, 0) 100%) top left / 100% 2px no-repeat,
        linear-gradient(180deg, #ffffff 0%, #fffafc 58%, #fdf2f8 100%);
    --fx-h2-line: linear-gradient(90deg,
            rgba(41, 122, 158, .60) 0%,
            rgba(224, 138, 180, .52) 46%,
            rgba(41, 122, 158, 0) 100%);
    /* ★ 标题渐变字整体又深一档：页头光晕 + 青蓝柔光 + 鼠标柔光会一起压在标题上
       （#1a5a79 → #114d68，L 0.0891 → 0.0655，三样全叠的最坏处仍有 5.4:1） */
    --fx-h1: linear-gradient(120deg, #114d68 0%, #1b5070 30%, #4a3480 68%, #7d3359 100%);
    --fx-sb-track: linear-gradient(180deg, #f9eef5, #f1e3ee);
    --fx-sb-thumb: linear-gradient(180deg, #7cb8d3 0%, #297a9e 55%, #1f6a8c 100%);
    --fx-sb-thumb-h: linear-gradient(180deg, #8bc4dc 0%, #23809f 55%, #1b5b74 100%);
    --fx-sb-edge: #fdf4f7;
    --fx-sb-corner: #f7ebf2;
    --fx-sel-bg: #cfe8f5;
    --fx-sel-fg: #26304a;

    /* 光带时长 / 相位：5 条分两组，组内**均匀错开**（负 delay = 页面一打开就已经错开）
     * 13s 那一组错开 1/3 周期、21s 那一组错开 1/2 周期 ——
     * 单条光带一个周期里有 ~18% 的时间整条在屏幕外（那是"无缝循环"必须付出的），
     * 错开之后这些空档彼此不重叠 → 任何时刻画面上都至少有 2 条在扫。 */
    --fx-s1-dur: 13s;  --fx-s1-delay: 0s;
    --fx-s2-dur: 13s;  --fx-s2-delay: -4.333s;
    --fx-s3-dur: 13s;  --fx-s3-delay: -8.667s;
    --fx-s4-dur: 21s;  --fx-s4-delay: 0s;
    --fx-s5-dur: 21s;  --fx-s5-delay: -10.5s;
}

/* 普拉娜：同一套装饰，换成深色档 ——
 * ★ 柔光浓度：青蓝 .30 / 粉 .40 / 紫 .36（阿罗娜是 .30 / .38 / .30）：
 *   深色底上同样的 α 观感强得多，但"最淡的字"也被提亮了一档，所以两边都能再加。
 * ★ 光带主色还是青蓝（同样的亮度提升，青蓝的 α 可以开到白光的 1.6 倍），
 *   核心那一档从 .082 提到 .16 —— 深色这一侧这版是**实打实翻倍**。 */
html[data-theme="plana"] {
    /* 和阿罗娜同一套"峰值 + 肩部"写法。★ 深色这一侧的余量比浅色小得多：
       深底被亮光抬起来是**成倍**的（L 从 0.0096 抬到 0.12 是 12 倍），
       而这些数值是拿真实渲染像素反复量出来的 —— 再加就破 4.5:1。 */
    --fx-a1: radial-gradient(closest-side, rgba(111, 196, 232, .26), rgba(111, 196, 232, .13) 58%, rgba(111, 196, 232, 0));
    --fx-a2: radial-gradient(closest-side, rgba(224, 138, 180, .32), rgba(224, 138, 180, .17) 58%, rgba(224, 138, 180, 0));
    --fx-a3: radial-gradient(closest-side, rgba(150, 130, 220, .30), rgba(150, 130, 220, .16) 58%, rgba(150, 130, 220, 0));
    --fx-a1-dur: 18s;
    --fx-a2-dur: 23s;
    --fx-a3-dur: 28s;

    --fx-s1: linear-gradient(102deg,
                 rgba(111, 196, 232, 0) 22%,
                 rgba(111, 196, 232, .075) 30%,
                 rgba(206, 238, 252, .105) 41%,
                 rgba(214, 242, 255, .110) 52%,
                 rgba(111, 196, 232, .080) 62%,
                 rgba(111, 196, 232, 0) 74%);
    --fx-s2: linear-gradient(76deg,
                 rgba(134, 211, 242, 0) 30%,
                 rgba(134, 211, 242, .070) 39%,
                 rgba(214, 240, 252, .105) 47%,
                 rgba(222, 246, 255, .110) 56%,
                 rgba(134, 211, 242, .070) 64%,
                 rgba(134, 211, 242, 0) 74%);
    --fx-s3: linear-gradient(88deg,
                 rgba(150, 130, 220, 0) 26%,
                 rgba(150, 130, 220, .062) 36%,
                 rgba(200, 186, 245, .095) 46%,
                 rgba(210, 198, 250, .100) 54%,
                 rgba(150, 130, 220, .062) 63%,
                 rgba(150, 130, 220, 0) 72%);
    --fx-s4: linear-gradient(116deg,
                 rgba(111, 196, 232, 0) 36%,
                 rgba(158, 216, 244, .070) 44%,
                 rgba(226, 246, 255, .130) 49%,
                 rgba(226, 246, 255, .130) 51%,
                 rgba(158, 216, 244, .070) 56%,
                 rgba(111, 196, 232, 0) 64%);
    --fx-s5: linear-gradient(68deg,
                 rgba(111, 196, 232, 0) 14%,
                 rgba(111, 196, 232, .060) 30%,
                 rgba(150, 214, 242, .100) 50%,
                 rgba(111, 196, 232, .060) 70%,
                 rgba(111, 196, 232, 0) 86%);

    --fx-spot: radial-gradient(closest-side, rgba(111, 196, 232, .06), rgba(111, 196, 232, 0));
    --fx-brand: radial-gradient(closest-side, rgba(111, 196, 232, .26), rgba(111, 196, 232, 0) 100%);
    --fx-brand-lo: .17;
    --fx-brand-hi: .24;
    --fx-brand-dur: 5.5s;

    /* 渐变也跟着翻深色：方向不变（90° 顶边细线 / 120° 标题字 / 180° 卡片和滚动条），
       颜色换成深色系 —— ★ 标题渐变字每一档都提亮到 L≥0.87：
       页头那一块叠着青蓝柔光 + 呼吸光晕，鼠标柔光再停上去时页面底最亮能到 L≈0.145，
       这一档是拿真实像素反推出来的（最坏 4.7:1 以上），不能往下调。 */
    --fx-card-bg:
        linear-gradient(90deg,
            rgba(111, 196, 232, 0) 0%,
            rgba(111, 196, 232, .60) 18%,
            rgba(224, 138, 180, .50) 62%,
            rgba(111, 196, 232, 0) 100%) top left / 100% 2px no-repeat,
        linear-gradient(180deg, #241f2f 0%, #221d2c 58%, #251f33 100%);
    --fx-h2-line: linear-gradient(90deg,
            rgba(111, 196, 232, .45) 0%,
            rgba(224, 138, 180, .38) 46%,
            rgba(111, 196, 232, 0) 100%);
    --fx-h1: linear-gradient(120deg, #dcf5ff 0%, #e8f8ff 30%, #f2ecff 68%, #fff0f6 100%);
    --fx-sb-track: linear-gradient(180deg, #241f2f, #1d1928);
    --fx-sb-thumb: linear-gradient(180deg, #6fc4e8 0%, #2f7ba1 55%, #235f7d 100%);
    --fx-sb-thumb-h: linear-gradient(180deg, #86d3f2 0%, #3a8cb4 55%, #2a6d8e 100%);
    --fx-sb-edge: #1a1622;
    --fx-sb-corner: #221d2c;
    --fx-sel-bg: #2f5d75;
    --fx-sel-fg: #eaf6fd;

    /* 和浅色同一套排布，只是快一点（深色底上亮光本来就更抢眼） */
    --fx-s1-dur: 12s;  --fx-s1-delay: 0s;
    --fx-s2-dur: 12s;  --fx-s2-delay: -4s;
    --fx-s3-dur: 12s;  --fx-s3-delay: -8s;
    --fx-s4-dur: 19s;  --fx-s4-delay: 0s;
    --fx-s5-dur: 19s;  --fx-s5-delay: -9.5s;
}

/* ---------------------------------------------------------------
 * E. 「流光」图层 —— 由 assets/theme-fx.js 在 <body> 末尾建出来
 * ---------------------------------------------------------------
 * 层叠（从下往上）：body 背景 → .fx（z-index:-1）→ 正文。
 * 所以流光**只从正文的缝隙和页面留白里透出来**，一个字都不会被它罩住，
 * 对比度也就不会被它拉低（浅底只会被压深一点、深底只会被提亮一点）。 */
html[data-theme]:not([data-theme="night"]) .fx {
    position: fixed;
    inset: 0;
    z-index: -1;
    overflow: hidden;
    pointer-events: none;      /* ★ 绝不挡任何点击 */
    contain: layout paint;     /* 里面的漂移不会引起外面重排、也不会溢出视口 */
}

/* E1：三团慢慢绕圈的柔光（青蓝 / 粉 / 紫，就是主题那三个色）
 * ★ 浓度是**算出来**的、不是拍脑袋：极限就是"页面底上最淡的那行字"，
 *   浅色按 --text-faint(#554e6d) 反推、深色按 --text-faint(#ded7e8) 反推，
 *   具体数字和真实像素实测都在报告里。这里只是把 --fx-a* 拿出来用。
 * ★★ 这里原来是 `fx-drift 30s ease-in-out infinite alternate`：
 *   **alternate + ease-in-out 的两端速度趋近 0** —— 实测每秒位移从 22.2px 掉到 1.1px
 *   （深色那两团是 0.75 / 0.50px），也就是每往返一次就在两端"停一拍"，
 *   用户看到的就是"播放一段会卡住"。
 *   现在改成**一条闭合回路**（0% 和 100% 完全重合）+ linear：
 *   位置首尾相接、没有跳变，每一秒的位移都不为 0（实测见报告）。 */
html[data-theme]:not([data-theme="night"]) .fx-aurora {
    position: absolute;
    display: block;
    border-radius: 50%;
    pointer-events: none;
    will-change: transform;
    animation: fx-drift 24s linear infinite;
}
/* ★ 三团的**圆心**都往视口里挪了一截（老写法圆心在视口外，画面上只剩衰减尾巴）：
   青蓝压页头左边、粉压页头右边、紫压页脚那一带 —— 正好是页面留白最多、
   卡片又盖不住的三块地方；加上 18vw/14vh 的漂移，整片留白都会被扫到。 */
html[data-theme]:not([data-theme="night"]) .fx-a1 {
    left: -8%; top: -14%; width: 50vw; height: 50vw;
    background: var(--fx-a1);
    animation-duration: var(--fx-a1-dur);
}
html[data-theme]:not([data-theme="night"]) .fx-a2 {
    right: -6%; top: -12%; width: 46vw; height: 46vw;
    background: var(--fx-a2);
    animation-duration: var(--fx-a2-dur);
    animation-direction: reverse;      /* 闭环里 reverse 也是无缝的（0% ≡ 100%） */
}
html[data-theme]:not([data-theme="night"]) .fx-a3 {
    left: 20%; bottom: -22%; width: 58vw; height: 58vw;
    background: var(--fx-a3);
    animation-duration: var(--fx-a3-dur);
}
/* ★ 闭合回路：0% = 100%，中间绕一圈（右 → 下 → 左 → 回原点），全程 linear。
   路程 ~675px / 周期 20~30s ≈ 23~34px 每秒，比原来"两端 1px、中间 22px"的忽快忽慢更快也更匀。 */
@keyframes fx-drift {
    0%   { transform: translate3d(0, 0, 0) scale(1); }
    25%  { transform: translate3d(9vw, -4vh, 0) scale(1.10); }
    50%  { transform: translate3d(18vw, 0, 0) scale(1.24); }
    75%  { transform: translate3d(9vw, 14vh, 0) scale(1.12); }
    100% { transform: translate3d(0, 0, 0) scale(1); }
}

/* E2：五条斜着扫过去的光带（分两组：13s ×3 + 21s ×2，组内相位均匀错开）
 * ★ 五条都是**整屏**铺开（inset 把上下左右都探出视口一点）—— 斜光带的"两端"必须
 *   落在屏幕外，否则会在画面中间切出一条硬边，看着像脏印子。
 * ★★ 扫距从 ±48% 扩到 ±85%：这是"无缝循环"的关键。
 *   光带盒宽 = 1.08 屏，渐变有色的那一段占 22%~74%（=52% 盒宽 ≈ 0.56 屏）。
 *   原来 ±48% 的行程**不够长**：到头的时候光带还有约 1/4 屏留在屏幕上，
 *   循环的一瞬间它就**从右边缘瞬移到左边缘**（实测 1567.6px 的跳变、1 秒里走了 10 倍路程）
 *   —— 用户说的"流光动画不衔接"就是这个。
 *   现在 ±85% 的行程让光带在两端都**整条扫出屏幕**：循环点前后一帧的画面完全一样，
 *   接得上、看不见跳。
 * ★ 代价是单条光带一个周期里有约 18% 的时间整条在屏幕外，所以：
 *   · 5 条光带分两组（13s 三条错开 1/3 周期、21s 两条错开 1/2 周期），
 *     组内空档彼此不重叠 → **任何时刻画面上都至少有 2 条光带在扫**，没有空窗期；
 *   · 错开用的是**负 animation-delay**（页面一打开就已经错开，不是先齐步走）。
 * ★ 浅色底：整条都是白系（白只会把浅底提亮）→ 五条全叠也只会更白，对比度不降反升。
 * ★ 深色底：主色改成青蓝、白只留核心那一档 —— 近黑的底被白光抬起来最狠。 */
html[data-theme]:not([data-theme="night"]) .fx-sheen {
    position: absolute;
    inset: -6% -4%;
    display: block;
    pointer-events: none;
    will-change: transform;
    animation: fx-sweep 16s linear infinite;
}
html[data-theme]:not([data-theme="night"]) .fx-s1 {
    background: var(--fx-s1);
    animation-duration: var(--fx-s1-dur); animation-delay: var(--fx-s1-delay);
}
html[data-theme]:not([data-theme="night"]) .fx-s2 {
    background: var(--fx-s2);
    animation-duration: var(--fx-s2-dur); animation-delay: var(--fx-s2-delay);
    animation-direction: reverse;      /* 一正一反，扫过去的方向不一样，不像机器 */
}
html[data-theme]:not([data-theme="night"]) .fx-s3 {
    background: var(--fx-s3);
    animation-duration: var(--fx-s3-dur); animation-delay: var(--fx-s3-delay);
}
html[data-theme]:not([data-theme="night"]) .fx-s4 {
    background: var(--fx-s4);
    animation-duration: var(--fx-s4-dur); animation-delay: var(--fx-s4-delay);
    animation-direction: reverse;
}
html[data-theme]:not([data-theme="night"]) .fx-s5 {
    background: var(--fx-s5);
    animation-duration: var(--fx-s5-dur); animation-delay: var(--fx-s5-delay);
}
@keyframes fx-sweep {
    from { transform: translate3d(-85%, 0, 0); }
    to   { transform: translate3d(85%, 0, 0); }
}

/* E3：跟着鼠标走的一团柔光 —— 和「纸飞机」鼠标呼应，像它拖出来的尾迹。
       位置由 theme-fx.js 用 transform 写，只在指针真的动了才写一次。 */
html[data-theme]:not([data-theme="night"]) .fx-spot {
    position: absolute;
    left: 0; top: 0;
    width: 620px; height: 620px;
    margin: -310px 0 0 -310px;          /* 让柔光中心正好落在指针上 */
    display: block;
    border-radius: 50%;
    pointer-events: none;
    background: var(--fx-spot);
    will-change: transform;
}

/* E4：页头标题后面那层青蓝柔光，慢慢「呼吸」（原来就有，D 段修好之后才真的看得见）
 * ★ 峰值压着"标题那几个字还剩多少对比度"这条线：两个主题的峰值都是实测反推的。
 *   这一版面积从 460×150 放到 720×260、最暗那档 .20→.26 / .16→.24 ——
 *   页头一大片都在亮，是"一眼就看得见"的那一档加强。 */
html[data-theme]:not([data-theme="night"]) .brand { position: relative; }

html[data-theme]:not([data-theme="night"]) .brand::before {
    content: '';
    position: absolute;
    left: -28px;
    top: -44px;
    width: 720px;
    height: 260px;
    z-index: -1;
    pointer-events: none;
    border-radius: 50%;
    background: var(--fx-brand);
    opacity: .30;
    animation: fx-brand-glow var(--fx-brand-dur) ease-in-out infinite alternate;
}

/* ★ 呼吸光晕是**唯一**保留 alternate 的：它本来就是"一亮一暗"的呼吸，
   两端停一下是呼吸该有的样子（而且它只改 opacity、只占页头那一小块）。 */
@keyframes fx-brand-glow {
    from { opacity: var(--fx-brand-lo); }
    to   { opacity: var(--fx-brand-hi); }
}

/* ---------------------------------------------------------------
 * F. 渐变（浅色 / 深色两套值都收在 E0 的 --fx-* 里，这里只管怎么用）
 * ---------------------------------------------------------------
 * 页面底那条对角渐变在变量层的 --t-bg-image 里，这里补剩下的几处：
 *   F1 卡片：极淡的竖向渐变 + 顶边一条青→粉细线
 *   F2 卡片小标题下面那条渐变细线（替掉原来那条纯色 1px）
 *   F3 标题 / 统计数字：渐变文字（background-clip: text）
 *   F4 主按钮：补一层内高光，让 135° 渐变看起来是"立体的"
 *   F5 滚动条 / 选中文字
 *   F6 表格头（--t-head-bg 已改成渐变，这里只管圆角那点细节）
 * ★ 渐变文字一律包在 @supports 里：万一有浏览器不认 background-clip:text，
 *   就退回原来的实色，绝不会出现"字变成透明、看不见"的情况。 */

/* F1：卡片 —— 极淡的竖向渐变，顶边一条青蓝→粉的细线 */
html[data-theme]:not([data-theme="night"]) .card { background: var(--fx-card-bg); }

/* F2：卡片小标题的渐变下划线（原边框留着，不动布局） */
html[data-theme]:not([data-theme="night"]) .card h2 {
    background-image: var(--fx-h2-line);
    background-repeat: no-repeat;
    background-position: 0 100%;
    background-size: 100% 2px;
}

/* F3：渐变文字 —— 站点标题 + 统计数字。
 * ★ 每一档都是**按"页面底最亮/最暗能到多少"反推**选的：
 *   浅色：标题底下压着流光，底的相对亮度最低约 0.70（等效灰阶 ≈218），
 *         所以最浅那一档必须 ≤0.117 —— 这里取 0.106（#256089），最坏 4.7:1；
 *   深色：底的相对亮度最高约 0.06，所以每一档都得 ≥0.65
 *         （#ffc6de 最暗 0.669），最坏 5:1 以上。 */
@supports ((background-clip: text) or (-webkit-background-clip: text)) {
    html[data-theme]:not([data-theme="night"]) .brand-text h1,
    html[data-theme]:not([data-theme="night"]) .stat-num {
        background-image: var(--fx-h1);
        -webkit-background-clip: text;
        background-clip: text;
        color: transparent;      /* ★ 只改 color：里面的 .badge 有自己的 color，不受影响 */
    }
}

/* F4：主按钮内高光（渐变本体在 --t-primary-bg 里） */
html[data-theme]:not([data-theme="night"]) .btn-primary {
    box-shadow: inset 0 1px 0 rgba(255, 255, 255, .22),
                0 2px 10px rgba(41, 122, 158, .20);
}

/* F5a：滚动条 —— 轨道竖向淡渐变，滑块青蓝渐变。
        ★ 只用 ::-webkit-scrollbar：一旦写 scrollbar-width/color，
          Chrome 会改走标准滚动条、把这套伪元素整段忽略掉。 */
html[data-theme]:not([data-theme="night"]) ::-webkit-scrollbar { width: 12px; height: 12px; }

html[data-theme]:not([data-theme="night"]) ::-webkit-scrollbar-track { background: var(--fx-sb-track); }
html[data-theme]:not([data-theme="night"]) ::-webkit-scrollbar-thumb {
    background: var(--fx-sb-thumb);
    border: 2px solid var(--fx-sb-edge);
    border-radius: 8px;
    background-clip: padding-box;
}
html[data-theme]:not([data-theme="night"]) ::-webkit-scrollbar-thumb:hover {
    background: var(--fx-sb-thumb-h);
    background-clip: padding-box;
}
html[data-theme]:not([data-theme="night"]) ::-webkit-scrollbar-corner { background: var(--fx-sb-corner); }

/* F5b：选中文字（::selection 只认纯色） */
html[data-theme]:not([data-theme="night"]) ::selection { background: var(--fx-sel-bg); color: var(--fx-sel-fg); }

/* F6：表头圆角那一点点收口（底色渐变在 --t-head-bg 里） */
html[data-theme]:not([data-theme="night"]) .server-table thead th { border-bottom-color: var(--border); }

/* ---------------------------------------------------------------
 * G. 手机 / 减弱动态效果
 * ---------------------------------------------------------------
 * ★ 手机：**流光要留着**（用户要求"手机上也要看得见"），只减量减速 —— 
 *   手机 GPU 弱，但我们的动画只碰 transform / opacity，合成器能画完，
 *   减到 2 条光带 + 3 团柔光完全跑得动。
 *   · 光带：5 条 → 只留 2 条（s1/s4），并把周期拉长（慢 = 更省电，观感也更柔）
 *   · 柔光：3 团全留，周期同样拉长
 *   · 鼠标柔光：触屏没有指针，藏掉（原来也是藏）
 *   · 页头光晕：保留，但慢一点、小一点
 * reduced-motion：**全停**（这条是辅助功能，不能动）。
 * JS 建的图层切后台时挂 .is-paused，同样是把动画按停。 */
@media (max-width: 720px) {
    /* 只留两条光带，其余三条藏掉 */
    html[data-theme]:not([data-theme="night"]) .fx-s2,
    html[data-theme]:not([data-theme="night"]) .fx-s3,
    html[data-theme]:not([data-theme="night"]) .fx-s5 { display: none; }

    html[data-theme]:not([data-theme="night"]) .fx-s1 { animation-duration: 22s; }
    html[data-theme]:not([data-theme="night"]) .fx-s4 { animation-duration: 34s; }

    /* 柔光：留着动，慢一档 */
    html[data-theme]:not([data-theme="night"]) .fx-a1 { animation-duration: 34s; }
    html[data-theme]:not([data-theme="night"]) .fx-a2 { animation-duration: 42s; }
    html[data-theme]:not([data-theme="night"]) .fx-a3 { animation-duration: 50s; }

    /* 触屏没指针，鼠标柔光没意义 */
    html[data-theme]:not([data-theme="night"]) .fx-spot { display: none; }

    /* 页头光晕：慢一点、小一点 */
    html[data-theme]:not([data-theme="night"]) .brand::before {
        width: 420px; height: 170px;
        animation-duration: 9s;
    }
}

@media (prefers-reduced-motion: reduce) {
    html[data-theme]:not([data-theme="night"]) .fx,
    html[data-theme]:not([data-theme="night"]) .fx *,
    html[data-theme]:not([data-theme="night"]) .brand::before { animation: none; }
    html[data-theme]:not([data-theme="night"]) .fx-sheen { display: none; }
    /* ★ 鼠标柔光也一起藏掉：它没有 CSS 动画，`animation: none` 管不到它，
       留着就还会跟着指针跑 —— "减弱动态效果"要的是**一帧都不动**。 */
    html[data-theme]:not([data-theme="night"]) .fx-spot { display: none; }
    html[data-theme]:not([data-theme="night"]) .brand::before { opacity: .45; }
}

/* 页面切到后台（document.hidden）时 theme-fx.js 挂上 .is-paused / <html>.fx-paused ——
   动画全部按停，回到前台再继续（省电；rAF 那一帧也已经取消） */
html[data-theme]:not([data-theme="night"]) .fx.is-paused,
html[data-theme]:not([data-theme="night"]) .fx.is-paused *,
html[data-theme]:not([data-theme="night"]).fx-paused .brand::before { animation-play-state: paused; }

/* ---------------------------------------------------------------
 * H. 鼠标指针：一架白纸 + 青蓝折痕的**纸飞机**（SVG data-URI，零文件零请求）
 * ---------------------------------------------------------------
 * ★ 机头必须朝**左上** —— 和系统箭头（标准 Windows 指针也是左上角那个尖）同一个方向。
 *   上一版画成了朝右上，方向是反的："热点在机头、机身往右下铺开"，
 *   看上去像飞机在往右下飞、和指针的方向拧着。
 *   改法就是把两条 path 的 x 全部镜像（x → 32 − x，viewBox 是 32×32）：
 *     M29 3 2.5 12.5 14.5 17.5 20 29.5Z  →  M3 3 29.5 12.5 17.5 17.5 12 29.5Z
 *     M29 3 14.5 17.5 20 29.5Z           →  M3 3 17.5 17.5 12 29.5Z
 *   y 一个都没动，所以机身形状、折痕、描边粗细和上一版完全一样，只是照了镜子。
 * ★ 热点 3 3 = 镜像之后的机头那个尖（原点在左上，和箭头热点同一个角）。
 *   逗号后面那个 auto 是兜底：浏览器不认 data-URI 光标（或者系统禁掉自定义光标）时
 *   退回系统箭头，绝不会出现"没有光标"的情况。
 * ★ 浅色 / 深色**同一个光标**（白机身 + 青蓝折痕在两种底上都清楚）。
 * ★ 可访问性：只换"长得好看"的那个箭头，其它语义光标一律显式写回原样 ——
 *   输入框/文本域必须是 text（不然没法正常编辑），禁用态 not-allowed，
 *   链接 / 按钮 / 下拉 pointer；resize / 拖拽 / cursor:help 那些是页面自己
 *   声明的（style.css 里直接写在元素上，权重高于"继承"，这里一概盖不掉也不该盖）。 */
html[data-theme]:not([data-theme="night"]) {
    cursor: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='32' height='32' viewBox='0 0 32 32'%3E%3Cpath d='M3 3 29.5 12.5 17.5 17.5 12 29.5Z' fill='%23ffffff' stroke='%23297a9e' stroke-width='1.5' stroke-linejoin='round'/%3E%3Cpath d='M3 3 17.5 17.5 12 29.5Z' fill='%23e6f3fa' stroke='%23297a9e' stroke-width='1.2' stroke-linejoin='round'/%3E%3C/svg%3E") 3 3, auto;
}

/* 能点的东西：手型（<button> 在浏览器默认样式里是箭头，所以这里显式补上） */
html[data-theme]:not([data-theme="night"]) a,
html[data-theme]:not([data-theme="night"]) button,
html[data-theme]:not([data-theme="night"]) select,
html[data-theme]:not([data-theme="night"]) summary,
html[data-theme]:not([data-theme="night"]) label[for],
html[data-theme]:not([data-theme="night"]) [role="button"] { cursor: pointer; }

/* ★ 文本框：还是 I 型光标（排除掉按钮/勾选/文件/滑块那些非文本的 input） */
html[data-theme]:not([data-theme="night"]) textarea,
html[data-theme]:not([data-theme="night"]) [contenteditable="true"],
html[data-theme]:not([data-theme="night"]) input:not([type="button"]):not([type="submit"]):not([type="reset"]):not([type="checkbox"]):not([type="radio"]):not([type="file"]):not([type="range"]):not([type="color"]) {
    cursor: text;
}

/* 禁用态：浏览器自带的"圆圈加斜杠"最清楚，别拿自定义光标糊过去
   （:disabled 的选择器权重比上面 button 那条高，写在前后都生效） */
html[data-theme]:not([data-theme="night"]) :disabled,
html[data-theme]:not([data-theme="night"]) [aria-disabled="true"] { cursor: not-allowed; }
