/* =========================================================================
 * 音悦声 · 设计系统底座
 *  - 六套全局主题（CSS 变量驱动）
 *  - 应用四区布局（顶部导航 / 左侧菜单 / 主内容区 / 底部播放条）
 *  - 响应式：PC / 平板 / 手机 / 折叠屏
 * ========================================================================= */

/* ------------------------------ 主题变量 ------------------------------ */
:root {
  /* ★★ 顶栏高度：68 → 76（v1.2.11）→ 86（v1.2.12）。
     v1.2.11：用户反馈「站点图标太贴近左边和下边」→ 76px 后 logo 上下各 19px。
     v1.2.12：用户再反馈「站点LOGO和边缘太贴近了」—— 19px 仍显挤；平板/手机断点更是
     只有 12px（62px 栏高 - 38px 图标 ⇒ (62-38)/2）。.brand 依旧**居中**在 --top-h 里
     （v1.2.11 已论证），正解仍是加高顶栏：86px ⇒ 桌面端上下各 24px，与左侧 26px 的
     --nav-gap 同拍；平板 70 / 手机 66 / 横屏 58 同步加高（见下方各断点）。
     全部引用（.app 网格行、.topbar 高度、管理菜单 sticky、抽屉顶距）都走变量，一处改全局自适应。
     v1.2.14：手机端左右留白另立 --page-pad-x（见 ≤767 段）。 */
  --top-h: 86px;
  --player-h: 88px;
  --nav-w: 86px;
  --nav-w-wide: 238px;
  /* ★ 导航轨右边缘 → 内容区左边界 的期望间隙。
     原来这个 18px 是**五处硬编码**的魔数（base.css ×3 + player.css ×2），
     改一次要全找出来，漏一处就会出现「导航和内容挤压」那种老问题。
     收成一个变量后，间距只在这里改。
     v1.2.11：18px → 26px（用户反馈 logo/内容贴着左边导航太紧）。
     v1.2.13：26px → 34px（用户再发截图反馈「太贴近左边边缘，稍微有点距离」——
     26px 仍嫌近，整体 +8；平板/折叠屏两档同步 +8，避免窄窗口回头再犯同样的毛病）。
     v1.2.17：34px → 44px（用户第 4 次反馈 LOGO 位置：「太靠顶部菜单左侧……
     顶部菜单右侧有很大空间，将图标稍微向右侧移动点，PC 端看着就好看了」）。
       ★ 先量后改（无头浏览器实测，vw=1264 / 桌面档）：
           .sidenav  右边缘 x=92 ｜ .brand 左边缘 x=126  ⇒ 实际间隙 34px
           .brand-mark 精确 38×38 @ y=24..61，顶栏 86 ⇒ 上下各 24px（**已经严格居中**）
         所以"太靠左侧"是**水平**问题、"上下已无处可调"——只动水平，不碰 --top-h。
       ★ 为什么把量加在 --nav-gap 上，而不是只给 .brand 加 margin-left：
         只推 .brand 会把它和搜索框的间距从 14px 压到 4px（两者是相邻 flex 项），
         而且会让 LOGO 与下方页面内容的左边界错开 —— 那种"差几像素"的错位
         比"整体偏左"更扎眼。加在 --nav-gap 上，LOGO、搜索框、内容区、播放条
         **一起右移相同的量**，相对关系一根都不动。
       ★ 手机端（≤767）不受影响：那一段 .app 改用 --page-pad-x，根本不读 --nav-gap。 */
  --nav-gap: 44px;
  /* 平板竖向（≤1023）用的窄间隙：v1.2.13 20 → 28px；v1.2.17 28 → 38px（与桌面同步 +10） */
  --nav-gap-sm: 38px;
  /* 折叠屏展开态（双视口分段）用更宽的让位，避开折痕：v1.2.13 30 → 38px；v1.2.17 38 → 48px */
  --nav-gap-fold: 48px;
  /* ★ 导航条的左侧外偏移（与 .sidenav 的 left 保持一致）。
     内容区与底部播放条的左边界必须把它算进去 —— 否则在 --nav-w 变窄的断点（1023 以下）
     会出现「导航条右边缘 == 内容区左边界」，两者严丝合缝贴在一起（实测间隙 0px），
     看起来就是「导航和右侧挤压在一起」。 */
  --nav-left: 14px;
  /* ★ 导航条圆角（四个导航风格统一走这两个变量，见 nav.css）：
       --nav-r       左上 / 左下 半径
       --nav-r-right 右上 / 右下 半径  ←「右侧两角直角」试验开关
     ★★ 一键还原：把 --nav-r-right 的值改回 var(--nav-r)，
        导航条立刻恢复成原本的四角全圆，其余什么都不用动。 */
  --nav-r: var(--r-xl);
  --nav-r-right: 0px;
  --r-xs: 8px;
  --r-sm: 12px;
  --r-md: 18px;
  --r-lg: 26px;
  --r-xl: 34px;
  /* ★ 窄屏「整页圆角玻璃边框」的圆角半径（2026-10-18）。只被 base.css 末尾
     那段 @media (max-width:1023px) 里的 html::before / html::after 读取。 */
  --frame-r: 22px;
  --dur: 0.28s;
  --ease: cubic-bezier(0.22, 0.68, 0.32, 1);
  --ease-out: cubic-bezier(0.16, 1, 0.3, 1);
  --tint: #f5c451;          /* 随封面主色动态更新的强调色 */
  --tint-2: #ff7a59;
  --font: "PingFang SC", "HarmonyOS Sans SC", "Microsoft YaHei UI", "Microsoft YaHei",
    system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  --font-num: "SF Mono", "JetBrains Mono", ui-monospace, "Cascadia Mono", Consolas, monospace;
}

/* 经典黑：深色 + 金色点缀 */
html[data-theme="classic-dark"] {
  --bg-0: #07070b;
  --bg-1: #0d0d14;
  --bg-2: #16161f;
  --panel: color-mix(in srgb, var(--brand) 9%, rgba(255, 255, 255, 0.052));
  --panel-2: color-mix(in srgb, var(--brand) 12%, rgba(255, 255, 255, 0.082));
  --panel-3: color-mix(in srgb, var(--brand) 16%, rgba(255, 255, 255, 0.12));
  --text: #f2f0ea;
  --dim: rgba(242, 240, 234, 0.66);
  --mute: rgba(242, 240, 234, 0.42);
  --line: color-mix(in srgb, var(--brand) 16%, rgba(255, 255, 255, 0.09));
  --line-2: color-mix(in srgb, var(--brand) 28%, rgba(255, 255, 255, 0.16));
  --brand: #f5c451;
  --brand-2: #e0964a;
  --accent: #ff7a59;
  --on-brand: #1a1206;
  --glow: color-mix(in srgb, var(--brand) 34%, transparent);
  --shadow-1: 0 4px 16px rgba(0, 0, 0, 0.4);
  --shadow-2: 0 16px 44px rgba(0, 0, 0, 0.56);
  --shadow-3: 0 30px 80px rgba(0, 0, 0, 0.66);
  --glass: color-mix(in srgb, var(--brand) 8%, rgba(16, 16, 24, 0.66));
  --glass-2: color-mix(in srgb, var(--brand) 10%, rgba(20, 20, 30, 0.84));
  --hair: color-mix(in srgb, var(--brand) 22%, rgba(255, 255, 255, 0.14));
  --scheme: dark;
  --wave-1: #f5c451;
  --wave-2: #ff7a59;
  /* 氛围与质感签名（决定"第一眼"的区别，见 body::before/::after） */
  --amb-1: color-mix(in srgb, var(--brand) 30%, transparent);
  --amb-2: color-mix(in srgb, var(--brand-2) 26%, transparent);
  --sig: radial-gradient(58% 42% at 14% 0%, color-mix(in srgb, var(--brand) 13%, transparent), transparent 62%);
  --sig-size: 100% 100%;
  --sig-op: 1;
}

/* 纯净白：浅色 + 蓝色主调 */
html[data-theme="pure-white"] {
  --bg-0: #eff3fa;
  --bg-1: #ffffff;
  --bg-2: #e4ebf7;
  --panel: color-mix(in srgb, var(--brand) 6%, rgba(255, 255, 255, 0.88));
  --panel-2: color-mix(in srgb, var(--brand) 4%, rgba(255, 255, 255, 0.97));
  --panel-3: color-mix(in srgb, var(--brand) 10%, rgba(238, 242, 250, 0.96));
  --text: #131722;
  --dim: rgba(19, 23, 34, 0.66);
  --mute: rgba(19, 23, 34, 0.42);
  --line: color-mix(in srgb, var(--brand) 18%, rgba(19, 23, 34, 0.09));
  --line-2: color-mix(in srgb, var(--brand) 32%, rgba(19, 23, 34, 0.16));
  --brand: #2563eb;
  --brand-2: #4f8bf7;
  --accent: #0ea5e9;
  --on-brand: #ffffff;
  --glow: color-mix(in srgb, var(--brand) 28%, transparent);
  --shadow-1: 0 4px 14px rgba(24, 40, 80, 0.09);
  --shadow-2: 0 14px 38px rgba(24, 40, 80, 0.14);
  --shadow-3: 0 28px 70px rgba(24, 40, 80, 0.18);
  --glass: color-mix(in srgb, var(--brand) 6%, rgba(255, 255, 255, 0.74));
  --glass-2: color-mix(in srgb, var(--brand) 5%, rgba(255, 255, 255, 0.92));
  --hair: color-mix(in srgb, var(--brand) 24%, rgba(19, 23, 34, 0.1));
  --scheme: light;
  --wave-1: #2563eb;
  --wave-2: #0ea5e9;
  --amb-1: color-mix(in srgb, var(--brand) 24%, transparent);
  --amb-2: color-mix(in srgb, var(--brand-2) 22%, transparent);
  --sig: repeating-linear-gradient(90deg, color-mix(in srgb, var(--brand) 7%, transparent) 0 1px, transparent 1px 44px), repeating-linear-gradient(0deg, color-mix(in srgb, var(--brand) 6%, transparent) 0 1px, transparent 1px 44px);
  --sig-size: 100% 100%;
  --sig-op: 0.85;
}

/* 霓虹紫：赛博朋克 */
html[data-theme="neon-purple"] {
  --bg-0: #08040f;
  --bg-1: #120a24;
  --bg-2: #1f1140;
  --panel: color-mix(in srgb, var(--brand) 16%, rgba(168, 85, 247, 0.1));
  --panel-2: color-mix(in srgb, var(--brand) 20%, rgba(168, 85, 247, 0.16));
  --panel-3: color-mix(in srgb, var(--brand) 26%, rgba(236, 72, 153, 0.2));
  --text: #f4ecff;
  --dim: rgba(244, 236, 255, 0.68);
  --mute: rgba(244, 236, 255, 0.42);
  --line: color-mix(in srgb, var(--brand) 30%, rgba(196, 132, 252, 0.18));
  --line-2: color-mix(in srgb, var(--brand-2) 44%, rgba(236, 72, 153, 0.34));
  --brand: #c084fc;
  --brand-2: #f472b6;
  --accent: #22d3ee;
  --on-brand: #1a0730;
  --glow: color-mix(in srgb, var(--brand) 40%, transparent);
  --shadow-1: 0 4px 18px rgba(88, 28, 135, 0.5);
  --shadow-2: 0 16px 46px rgba(88, 28, 135, 0.6);
  --shadow-3: 0 30px 84px rgba(59, 7, 100, 0.7);
  --glass: color-mix(in srgb, var(--brand) 12%, rgba(26, 12, 48, 0.66));
  --glass-2: color-mix(in srgb, var(--brand) 14%, rgba(32, 14, 58, 0.86));
  --hair: color-mix(in srgb, var(--brand) 34%, rgba(196, 132, 252, 0.24));
  --scheme: dark;
  --wave-1: #c084fc;
  --wave-2: #f472b6;
  --amb-1: color-mix(in srgb, var(--brand) 34%, transparent);
  --amb-2: color-mix(in srgb, var(--brand-2) 32%, transparent);
  --sig: repeating-linear-gradient(0deg, color-mix(in srgb, var(--brand-2) 12%, transparent) 0 1px, transparent 1px 38px), repeating-linear-gradient(90deg, color-mix(in srgb, var(--brand) 12%, transparent) 0 1px, transparent 1px 38px);
  --sig-size: 100% 100%;
  --sig-op: 1;
}

/* 森林绿：自然清新 */
html[data-theme="forest-green"] {
  --bg-0: #e8f3ea;
  --bg-1: #ffffff;
  --bg-2: #d8ebdc;
  --panel: color-mix(in srgb, var(--brand) 7%, rgba(255, 255, 255, 0.9));
  --panel-2: color-mix(in srgb, var(--brand) 5%, rgba(255, 255, 255, 0.97));
  --panel-3: color-mix(in srgb, var(--brand) 12%, rgba(232, 241, 233, 0.96));
  --text: #14231a;
  --dim: rgba(20, 35, 26, 0.66);
  --mute: rgba(20, 35, 26, 0.42);
  --line: color-mix(in srgb, var(--brand) 20%, rgba(20, 35, 26, 0.1));
  --line-2: color-mix(in srgb, var(--brand) 34%, rgba(22, 101, 52, 0.22));
  --brand: #15803d;
  --brand-2: #2f9e5f;
  --accent: #65a30d;
  --on-brand: #ffffff;
  --glow: color-mix(in srgb, var(--brand) 28%, transparent);
  --shadow-1: 0 4px 14px rgba(20, 60, 35, 0.09);
  --shadow-2: 0 14px 38px rgba(20, 60, 35, 0.14);
  --shadow-3: 0 28px 70px rgba(20, 60, 35, 0.18);
  --glass: color-mix(in srgb, var(--brand) 7%, rgba(246, 251, 246, 0.74));
  --glass-2: color-mix(in srgb, var(--brand) 6%, rgba(255, 255, 255, 0.92));
  --hair: color-mix(in srgb, var(--brand) 26%, rgba(20, 35, 26, 0.12));
  --scheme: light;
  --wave-1: #15803d;
  --wave-2: #65a30d;
  --amb-1: color-mix(in srgb, var(--brand) 26%, transparent);
  --amb-2: color-mix(in srgb, var(--accent) 24%, transparent);
  --sig: repeating-linear-gradient(118deg, color-mix(in srgb, var(--brand) 9%, transparent) 0 1px, transparent 1px 30px);
  --sig-size: 100% 100%;
  --sig-op: 0.9;
}

/* 暖阳橙：活力温暖 */
html[data-theme="warm-orange"] {
  --bg-0: #180c05;
  --bg-1: #26160c;
  --bg-2: #3d2212;
  --panel: color-mix(in srgb, var(--brand) 15%, rgba(251, 146, 60, 0.1));
  --panel-2: color-mix(in srgb, var(--brand) 20%, rgba(251, 146, 60, 0.16));
  --panel-3: color-mix(in srgb, var(--brand-2) 24%, rgba(250, 204, 21, 0.18));
  --text: #fff4e6;
  --dim: rgba(255, 244, 230, 0.68);
  --mute: rgba(255, 244, 230, 0.42);
  --line: color-mix(in srgb, var(--brand) 30%, rgba(251, 146, 60, 0.2));
  --line-2: color-mix(in srgb, var(--brand-2) 42%, rgba(250, 204, 21, 0.34));
  --brand: #fb923c;
  --brand-2: #facc15;
  --accent: #ef4444;
  --on-brand: #2a1405;
  --glow: color-mix(in srgb, var(--brand) 38%, transparent);
  --shadow-1: 0 4px 18px rgba(120, 53, 15, 0.46);
  --shadow-2: 0 16px 46px rgba(120, 53, 15, 0.58);
  --shadow-3: 0 30px 84px rgba(69, 26, 3, 0.7);
  --glass: color-mix(in srgb, var(--brand) 12%, rgba(38, 22, 12, 0.66));
  --glass-2: color-mix(in srgb, var(--brand) 14%, rgba(46, 26, 14, 0.86));
  --hair: color-mix(in srgb, var(--brand) 34%, rgba(251, 146, 60, 0.26));
  --scheme: dark;
  --wave-1: #fb923c;
  --wave-2: #facc15;
  --amb-1: color-mix(in srgb, var(--brand) 36%, transparent);
  --amb-2: color-mix(in srgb, var(--brand-2) 30%, transparent);
  --sig: radial-gradient(56% 46% at 88% 4%, color-mix(in srgb, var(--brand) 22%, transparent), transparent 64%);
  --sig-size: 100% 100%;
  --sig-op: 1;
}

/* =========================================================================
 * 情绪配色主题（9 套）
 *   ★ 每条都必须给齐全部 token —— 少一个就会退回 :root 的深色默认值，
 *     表现为「切到浅色主题后某处还是黑的」，是这套体系里最容易出的错。
 *   ★ --on-brand 必须与 --brand 形成 ≥4.5:1 ——
 *     它是叠在 --brand 上的文字色（徽标、选中胶囊、按钮），
 *     浅色主题一律给近白、深色主题一律给近黑，brand 的明度按此反推着选。
 *   命名前缀沿用现有的英文 id，中文名在 server.js /api/meta 与 ui.js 色卡里配。
 *   ★★ v1.2.11 起，每套主题不再只给「底色 + 主色」，而是给满三件事：
 *      ① 色相化的表面：--panel / --line / --glass / --hair 一律用 color-mix 从 --brand 派生
 *         （否则所有浅色主题的卡片都是同一张白纸 —— 实测 pure-white 与 forest-green
 *          的全页签名差只有 8.1 / 765，肉眼等同"没换"）。
 *      ② 氛围色 --amb-1/--amb-2：喂给 body::before 的弥散光，决定"第一眼"的色调。
 *      ③ 质感签名 --sig/--sig-size/--sig-op：叠在 body::after 上的专属纹理
 *         （奶咖的涟漪、深海的圆环、樱花的瓣点、国风的宣纸斜纹…）。
 * ========================================================================= */

/* 治愈奶咖：米棕暖调 + 拿铁奶油
 * ★ v1.2.11：原来 --bg-0 是 #f6ecdc，与 ink 的 #f2ecdd 只差 (4,0,1) ——
 *   全页签名 L1 只有 4.2（量程 765），用户看到的"两套主题几乎一样"就是这么来的。
 *   现在往"焦糖拿铁"方向压低明度、提高黄铜色相饱和度，与 ink 的"灰白宣纸"明确拉开。 */
html[data-theme="cream"] {
  --bg-0: #f7e7d0;
  --bg-1: #fffcf3;
  --bg-2: #eed5ab;
  /* ★★ v1.2.11：卡片也要参与"两套纸感主题"的区分。
     原来 cream 的 --panel 与 ink 的 --panel 算出来只差 (3,3,1)——几乎同色，
     而卡片占了整页面积的一大半，于是"全页签名"里最大的那块面积压根没差别。
     现在奶咖的卡片明确偏暖（琥珀调），ink 的卡片明确偏中灰（宣纸调），见 ink 块注释。 */
  --panel: color-mix(in srgb, var(--brand) 12%, rgba(255, 249, 238, 0.92));
  --panel-2: color-mix(in srgb, var(--brand) 9%, rgba(255, 251, 242, 0.97));
  --panel-3: color-mix(in srgb, var(--brand) 18%, rgba(243, 232, 214, 0.96));
  --text: #2b2118;
  --dim: rgba(43, 33, 24, 0.68);
  --mute: rgba(43, 33, 24, 0.46);
  --line: color-mix(in srgb, var(--brand) 22%, rgba(43, 33, 24, 0.09));
  --line-2: color-mix(in srgb, var(--brand) 36%, rgba(43, 33, 24, 0.16));
  --brand: #8f5c2c;
  --brand-2: #b98047;
  --accent: #d97706;
  --on-brand: #fffaf2;
  --glow: color-mix(in srgb, var(--brand) 32%, transparent);
  --shadow-1: 0 4px 14px rgba(74, 50, 25, 0.09);
  --shadow-2: 0 14px 38px rgba(74, 50, 25, 0.14);
  --shadow-3: 0 28px 70px rgba(74, 50, 25, 0.18);
  --glass: color-mix(in srgb, var(--brand) 10%, rgba(255, 249, 238, 0.76));
  --glass-2: color-mix(in srgb, var(--brand) 8%, rgba(255, 251, 242, 0.93));
  --hair: color-mix(in srgb, var(--brand) 32%, rgba(43, 33, 24, 0.12));
  --scheme: light;
  --wave-1: #8f5c2c;
  --wave-2: #d97706;
  --amb-1: color-mix(in srgb, var(--brand) 40%, transparent);
  --amb-2: color-mix(in srgb, var(--brand-2) 36%, transparent);
  /* 第一层是**整页暖色薄纱**（奶咖的"拿铁"底色），后两层是涟漪与高光 */
  --sig: linear-gradient(180deg, color-mix(in srgb, var(--brand) 10%, transparent), color-mix(in srgb, var(--brand-2) 13%, transparent)),
    repeating-radial-gradient(circle at 84% 12%, color-mix(in srgb, var(--brand) 16%, transparent) 0 2px, transparent 2px 34px),
    radial-gradient(48% 42% at 88% 6%, color-mix(in srgb, var(--brand-2) 24%, transparent), transparent 70%);
  --sig-size: 100% 100%;
  --sig-op: 0.95;
}

/* 深海静谧：幽蓝水光 + 薄荷气泡 */
html[data-theme="ocean"] {
  --bg-0: #040b13;
  --bg-1: #08131f;
  --bg-2: #0d2136;
  --panel: color-mix(in srgb, var(--brand) 14%, rgba(76, 201, 240, 0.09));
  --panel-2: color-mix(in srgb, var(--brand) 18%, rgba(76, 201, 240, 0.14));
  --panel-3: color-mix(in srgb, var(--brand-2) 24%, rgba(99, 230, 213, 0.18));
  --text: #e6f2fb;
  --dim: rgba(230, 242, 251, 0.68);
  --mute: rgba(230, 242, 251, 0.42);
  --line: color-mix(in srgb, var(--brand) 26%, rgba(140, 200, 255, 0.14));
  --line-2: color-mix(in srgb, var(--brand) 38%, rgba(76, 201, 240, 0.3));
  --brand: #4cc9f0;
  --brand-2: #63e6d5;
  --accent: #ffd166;
  --on-brand: #04141c;
  --glow: color-mix(in srgb, var(--brand) 36%, transparent);
  --shadow-1: 0 4px 18px rgba(2, 12, 24, 0.5);
  --shadow-2: 0 16px 46px rgba(2, 12, 24, 0.6);
  --shadow-3: 0 30px 84px rgba(1, 8, 18, 0.7);
  --glass: color-mix(in srgb, var(--brand) 11%, rgba(9, 21, 34, 0.66));
  --glass-2: color-mix(in srgb, var(--brand) 13%, rgba(12, 26, 42, 0.86));
  --hair: color-mix(in srgb, var(--brand) 30%, rgba(76, 201, 240, 0.2));
  --scheme: dark;
  --wave-1: #4cc9f0;
  --wave-2: #63e6d5;
  --amb-1: color-mix(in srgb, var(--brand) 32%, transparent);
  --amb-2: color-mix(in srgb, var(--brand-2) 30%, transparent);
  --sig: repeating-radial-gradient(circle at 50% 118%, color-mix(in srgb, var(--brand) 13%, transparent) 0 1.5px, transparent 1.5px 72px);
  --sig-size: 100% 100%;
  --sig-op: 1;
}

/* 樱粉甜心：樱花粉 + 奶油白 */
html[data-theme="sakura"] {
  --bg-0: #fceef3;
  --bg-1: #fffbfc;
  --bg-2: #f7dde6;
  --panel: color-mix(in srgb, var(--brand) 7%, rgba(255, 251, 252, 0.9));
  --panel-2: color-mix(in srgb, var(--brand) 5%, rgba(255, 251, 252, 0.97));
  --panel-3: color-mix(in srgb, var(--brand) 12%, rgba(250, 233, 238, 0.96));
  --text: #3a1f2b;
  --dim: rgba(58, 31, 43, 0.68);
  --mute: rgba(58, 31, 43, 0.46);
  --line: color-mix(in srgb, var(--brand) 20%, rgba(58, 31, 43, 0.09));
  --line-2: color-mix(in srgb, var(--brand) 32%, rgba(58, 31, 43, 0.16));
  --brand: #b8145a;
  --brand-2: #e2568f;
  --accent: #ff8fab;
  --on-brand: #fff9fb;
  --glow: color-mix(in srgb, var(--brand) 30%, transparent);
  --shadow-1: 0 4px 14px rgba(96, 24, 56, 0.09);
  --shadow-2: 0 14px 38px rgba(96, 24, 56, 0.14);
  --shadow-3: 0 28px 70px rgba(96, 24, 56, 0.18);
  --glass: color-mix(in srgb, var(--brand) 7%, rgba(255, 251, 252, 0.74));
  --glass-2: color-mix(in srgb, var(--brand) 5%, rgba(255, 251, 252, 0.92));
  --hair: color-mix(in srgb, var(--brand) 26%, rgba(58, 31, 43, 0.1));
  --scheme: light;
  --wave-1: #b8145a;
  --wave-2: #f472b6;
  --amb-1: color-mix(in srgb, var(--brand) 26%, transparent);
  --amb-2: color-mix(in srgb, var(--accent) 28%, transparent);
  --sig: radial-gradient(52% 34% at 18% 16%, color-mix(in srgb, var(--accent) 16%, transparent), transparent 66%), radial-gradient(40% 28% at 78% 6%, color-mix(in srgb, var(--brand) 13%, transparent), transparent 62%);
  --sig-size: 100% 100%;
  --sig-op: 0.95;
}

/* 墨韵国风：宣纸底 + 朱砂 + 描金
 * ★ v1.2.11：纸色从"暖米黄"改成"偏冷的灰白宣纸"，把黄铜色相让给 cream，
 *   同时加深墨色、加一层斜纹 + 朱砂/描金双晕，让"国风"一眼可辨。 */
html[data-theme="ink"] {
  --bg-0: #ebe9dd;
  --bg-1: #fbfaf6;
  --bg-2: #dbd7c8;
  /* ★★ v1.2.11：卡片色调**去朱砂化**，改成"墨 + 中性宣纸"。
     原来的 --panel 是 `--brand(朱砂) 6%` 混暖白 ⇒ 算出来 (243,237,232)，
     与 cream 的 --panel (246,240,232) 只差 (3,3,0) —— 两套主题的卡片几乎同色，
     而卡片是整页面积最大的一块，"切换主题看不出来"有一半是这里造成的。
     宣纸本来就是中性的，颜色应该由朱砂/描金这些**小面积**元素承担，
     所以卡片改用 --text（墨）做极低比例的灰化：得到确定的中性纸白。 */
  --panel: color-mix(in srgb, var(--text) 5%, rgba(250, 250, 246, 0.94));
  --panel-2: color-mix(in srgb, var(--text) 3%, rgba(252, 252, 249, 0.97));
  --panel-3: color-mix(in srgb, var(--accent) 14%, rgba(236, 234, 228, 0.96));
  --text: #15130f;
  --dim: rgba(21, 19, 15, 0.7);
  --mute: rgba(21, 19, 15, 0.48);
  --line: color-mix(in srgb, var(--brand) 20%, rgba(28, 26, 23, 0.1));
  --line-2: color-mix(in srgb, var(--accent) 40%, rgba(28, 26, 23, 0.18));
  --brand: #9c2b1f;
  --brand-2: #b8432f;
  --accent: #c8a04a;
  --on-brand: #fdf7ee;
  --glow: color-mix(in srgb, var(--brand) 28%, transparent);
  --shadow-1: 0 4px 14px rgba(44, 34, 22, 0.09);
  --shadow-2: 0 14px 38px rgba(44, 34, 22, 0.15);
  --shadow-3: 0 28px 70px rgba(44, 34, 22, 0.19);
  --glass: color-mix(in srgb, var(--text) 5%, rgba(251, 250, 246, 0.78));
  --glass-2: color-mix(in srgb, var(--text) 3%, rgba(252, 252, 249, 0.94));
  --hair: color-mix(in srgb, var(--accent) 34%, rgba(28, 26, 23, 0.12));
  --scheme: light;
  --wave-1: #9c2b1f;
  --wave-2: #c8a04a;
  --amb-1: color-mix(in srgb, var(--brand) 26%, transparent);
  --amb-2: color-mix(in srgb, var(--accent) 28%, transparent);
  /* 整页"陈年宣纸"灰纱（墨 + 沉纸色）+ 宣纸斜纹 + 右上描金晕 + 左下朱砂晕
     —— 四层叠加。第一层是**方向性**的关键：cream 的薄纱是暖琥珀、ink 的是中性灰墨，
     两套主题于是从"底纸"这一步就分开，而不是只靠几个小面积的强调色。 */
  --sig: linear-gradient(200deg, color-mix(in srgb, var(--text) 6%, transparent), color-mix(in srgb, var(--bg-2) 30%, transparent)),
    repeating-linear-gradient(48deg, color-mix(in srgb, var(--text) 7%, transparent) 0 1px, transparent 1px 12px),
    radial-gradient(38% 34% at 87% 7%, color-mix(in srgb, var(--accent) 20%, transparent), transparent 66%),
    radial-gradient(32% 28% at 6% 96%, color-mix(in srgb, var(--brand) 15%, transparent), transparent 70%);
  --sig-size: 100% 100%;
  --sig-op: 1;
}

/* 极光幻境：北境紫 + 极光青 */
html[data-theme="aurora"] {
  --bg-0: #04081a;
  --bg-1: #0a1022;
  --bg-2: #14224a;
  --panel: color-mix(in srgb, var(--brand) 16%, rgba(155, 134, 255, 0.1));
  --panel-2: color-mix(in srgb, var(--brand) 20%, rgba(155, 134, 255, 0.16));
  --panel-3: color-mix(in srgb, var(--brand-2) 24%, rgba(74, 217, 196, 0.18));
  --text: #e8ecff;
  --dim: rgba(232, 236, 255, 0.68);
  --mute: rgba(232, 236, 255, 0.42);
  --line: color-mix(in srgb, var(--brand) 28%, rgba(155, 134, 255, 0.18));
  --line-2: color-mix(in srgb, var(--brand-2) 42%, rgba(74, 217, 196, 0.3));
  --brand: #9b86ff;
  --brand-2: #4ad9c4;
  --accent: #ff7ac6;
  --on-brand: #0b0a1f;
  --glow: color-mix(in srgb, var(--brand) 40%, transparent);
  --shadow-1: 0 4px 18px rgba(8, 6, 30, 0.5);
  --shadow-2: 0 16px 46px rgba(8, 6, 30, 0.62);
  --shadow-3: 0 30px 84px rgba(5, 4, 20, 0.72);
  --glass: color-mix(in srgb, var(--brand) 13%, rgba(12, 14, 38, 0.66));
  --glass-2: color-mix(in srgb, var(--brand) 15%, rgba(18, 20, 48, 0.86));
  --hair: color-mix(in srgb, var(--brand) 34%, rgba(155, 134, 255, 0.24));
  --scheme: dark;
  --wave-1: #9b86ff;
  --wave-2: #4ad9c4;
  --amb-1: color-mix(in srgb, var(--brand) 38%, transparent);
  --amb-2: color-mix(in srgb, var(--brand-2) 34%, transparent);
  --sig: conic-gradient(from 190deg at 50% -8%, color-mix(in srgb, var(--brand) 20%, transparent), transparent 26%, color-mix(in srgb, var(--brand-2) 17%, transparent) 48%, transparent 72%, color-mix(in srgb, var(--accent) 13%, transparent));
  --sig-size: 100% 100%;
  --sig-op: 0.9;
}

/* 石墨灰：中性专业，无彩干扰 */
html[data-theme="graphite"] {
  --bg-0: #090a0c;
  --bg-1: #121417;
  --bg-2: #1d2126;
  --panel: rgba(233, 236, 239, 0.062);
  --panel-2: rgba(233, 236, 239, 0.1);
  --panel-3: rgba(233, 236, 239, 0.145);
  --text: #e9ecef;
  --dim: rgba(233, 236, 239, 0.66);
  --mute: rgba(233, 236, 239, 0.4);
  --line: rgba(233, 236, 239, 0.11);
  --line-2: rgba(233, 236, 239, 0.2);
  --brand: #9aa6b2;
  --brand-2: #c3cdd8;
  --accent: #6ee7b7;
  --on-brand: #0c1013;
  --glow: rgba(154, 166, 178, 0.3);
  --shadow-1: 0 4px 16px rgba(0, 0, 0, 0.42);
  --shadow-2: 0 16px 44px rgba(0, 0, 0, 0.56);
  --shadow-3: 0 30px 80px rgba(0, 0, 0, 0.66);
  --glass: rgba(16, 18, 21, 0.7);
  --glass-2: rgba(22, 25, 29, 0.88);
  --hair: rgba(233, 236, 239, 0.16);
  --scheme: dark;
  --wave-1: #9aa6b2;
  --wave-2: #6ee7b7;
  /* 石墨灰刻意保持无彩：氛围压到最低，靠"网格 + 极简"立住性格 */
  --amb-1: rgba(154, 166, 178, 0.16);
  --amb-2: rgba(110, 231, 183, 0.1);
  --sig: repeating-linear-gradient(90deg, rgba(233, 236, 239, 0.05) 0 1px, transparent 1px 32px), repeating-linear-gradient(0deg, rgba(233, 236, 239, 0.045) 0 1px, transparent 1px 32px);
  --sig-size: 100% 100%;
  --sig-op: 1;
}

/* 落日蜜桃：晚霞橙粉 */
html[data-theme="sunset"] {
  --bg-0: #150710;
  --bg-1: #211016;
  --bg-2: #38182a;
  --panel: color-mix(in srgb, var(--brand) 15%, rgba(255, 158, 122, 0.1));
  --panel-2: color-mix(in srgb, var(--brand) 20%, rgba(255, 158, 122, 0.16));
  --panel-3: color-mix(in srgb, var(--brand-2) 24%, rgba(255, 107, 157, 0.18));
  --text: #fff0ec;
  --dim: rgba(255, 240, 236, 0.68);
  --mute: rgba(255, 240, 236, 0.42);
  --line: color-mix(in srgb, var(--brand) 30%, rgba(255, 158, 122, 0.2));
  --line-2: color-mix(in srgb, var(--brand-2) 40%, rgba(255, 107, 157, 0.32));
  --brand: #ff9e7a;
  --brand-2: #ff6b9d;
  --accent: #ffd166;
  --on-brand: #2b0f16;
  --glow: color-mix(in srgb, var(--brand) 38%, transparent);
  --shadow-1: 0 4px 18px rgba(60, 12, 28, 0.48);
  --shadow-2: 0 16px 46px rgba(60, 12, 28, 0.6);
  --shadow-3: 0 30px 84px rgba(42, 8, 20, 0.7);
  --glass: color-mix(in srgb, var(--brand) 12%, rgba(33, 16, 22, 0.66));
  --glass-2: color-mix(in srgb, var(--brand) 14%, rgba(43, 20, 28, 0.86));
  --hair: color-mix(in srgb, var(--brand) 32%, rgba(255, 158, 122, 0.24));
  --scheme: dark;
  --wave-1: #ff9e7a;
  --wave-2: #ff6b9d;
  --amb-1: color-mix(in srgb, var(--brand) 36%, transparent);
  --amb-2: color-mix(in srgb, var(--brand-2) 34%, transparent);
  --sig: linear-gradient(178deg, color-mix(in srgb, var(--brand) 20%, transparent), transparent 42%), radial-gradient(60% 40% at 20% 96%, color-mix(in srgb, var(--brand-2) 20%, transparent), transparent 66%);
  --sig-size: 100% 100%;
  --sig-op: 1;
}

/* 薄荷清氧：薄荷绿 + 冷白 */
html[data-theme="mint"] {
  --bg-0: #e6f6ef;
  --bg-1: #fbfffd;
  --bg-2: #d3efe3;
  --panel: color-mix(in srgb, var(--brand) 7%, rgba(251, 255, 253, 0.9));
  --panel-2: color-mix(in srgb, var(--brand) 5%, rgba(251, 255, 253, 0.97));
  --panel-3: color-mix(in srgb, var(--brand) 12%, rgba(226, 244, 236, 0.96));
  --text: #10251d;
  --dim: rgba(16, 37, 29, 0.68);
  --mute: rgba(16, 37, 29, 0.46);
  --line: color-mix(in srgb, var(--brand) 20%, rgba(16, 37, 29, 0.09));
  --line-2: color-mix(in srgb, var(--brand) 34%, rgba(16, 37, 29, 0.16));
  --brand: #0f7a63;
  --brand-2: #16a085;
  --accent: #34d399;
  --on-brand: #f2fffb;
  --glow: color-mix(in srgb, var(--brand) 28%, transparent);
  --shadow-1: 0 4px 14px rgba(12, 56, 44, 0.09);
  --shadow-2: 0 14px 38px rgba(12, 56, 44, 0.14);
  --shadow-3: 0 28px 70px rgba(12, 56, 44, 0.18);
  --glass: color-mix(in srgb, var(--brand) 7%, rgba(251, 255, 253, 0.74));
  --glass-2: color-mix(in srgb, var(--brand) 5%, rgba(251, 255, 253, 0.92));
  --hair: color-mix(in srgb, var(--brand) 26%, rgba(16, 37, 29, 0.11));
  --scheme: light;
  --wave-1: #0f7a63;
  --wave-2: #34d399;
  --amb-1: color-mix(in srgb, var(--brand) 26%, transparent);
  --amb-2: color-mix(in srgb, var(--accent) 26%, transparent);
  --sig: radial-gradient(38% 30% at 12% 20%, color-mix(in srgb, var(--accent) 15%, transparent), transparent 62%), radial-gradient(30% 24% at 72% 4%, color-mix(in srgb, var(--brand) 12%, transparent), transparent 64%);
  --sig-size: 100% 100%;
  --sig-op: 0.95;
}

/* 暗夜酒红：酒窖红 + 香槟金 */
html[data-theme="wine"] {
  --bg-0: #120406;
  --bg-1: #1e0a0e;
  --bg-2: #35121c;
  --panel: color-mix(in srgb, var(--brand) 14%, rgba(224, 177, 85, 0.09));
  --panel-2: color-mix(in srgb, var(--brand) 18%, rgba(224, 177, 85, 0.15));
  --panel-3: color-mix(in srgb, var(--brand-2) 22%, rgba(240, 90, 106, 0.18));
  --text: #fbeef0;
  --dim: rgba(251, 238, 240, 0.68);
  --mute: rgba(251, 238, 240, 0.42);
  --line: color-mix(in srgb, var(--brand) 28%, rgba(224, 177, 85, 0.18));
  --line-2: color-mix(in srgb, var(--brand-2) 40%, rgba(240, 90, 106, 0.3));
  --brand: #e0b155;
  --brand-2: #f05a6a;
  --accent: #ff8fa3;
  --on-brand: #241008;
  --glow: color-mix(in srgb, var(--brand) 36%, transparent);
  --shadow-1: 0 4px 18px rgba(38, 4, 10, 0.5);
  --shadow-2: 0 16px 46px rgba(38, 4, 10, 0.62);
  --shadow-3: 0 30px 84px rgba(26, 2, 7, 0.72);
  --glass: color-mix(in srgb, var(--brand) 12%, rgba(30, 10, 14, 0.68));
  --glass-2: color-mix(in srgb, var(--brand) 14%, rgba(40, 14, 20, 0.87));
  --hair: color-mix(in srgb, var(--brand) 30%, rgba(224, 177, 85, 0.22));
  --scheme: dark;
  --wave-1: #e0b155;
  --wave-2: #c8102e;
  --amb-1: color-mix(in srgb, var(--brand) 32%, transparent);
  --amb-2: color-mix(in srgb, var(--brand-2) 28%, transparent);
  --sig: radial-gradient(120% 62% at 50% 108%, color-mix(in srgb, var(--brand) 18%, transparent), transparent 64%), radial-gradient(50% 34% at 88% 0%, color-mix(in srgb, var(--brand-2) 14%, transparent), transparent 68%);
  --sig-size: 100% 100%;
  --sig-op: 1;
}

/* =========================================================================
 * 深色调色板（4 套）—— v1.3.1
 *   用户反馈：「全局主题缺少深绿色、中国红等色调」。
 *   对照现有 14 套，缺的是「**深**且**饱和**的正统色」这一档：
 *   现有绿只有 forest-green（浅色 + 黄绿 #65a30d，是"橄榄/嫩芽"不是"深绿"）、
 *   现有红只有 warm-orange 的 --accent 与 wine 的酒红（偏粉紫），
 *   现有蓝只有 ocean 的青蓝（#4cc9f0）与纯浅色的 pure-white，
 *   棕色系整个空缺。
 *   ⇒ 补 deep-green / china-red / navy / mocha，四套都是**深底 + 高饱和主色**，
 *     且色相两两拉开（绿 / 红 / 蓝 / 棕），互相之间以及与原有 14 套都不会"切了像没切"。
 *
 *   ★ 「切了像没切」是本项目踩过的坑（pure-white 与 forest-green 的全页签名差只有
 *     8.1 / 765）。所以这四套除了主色不同，--bg-0 也各自压到不同的暗部色相上：
 *     松林的冷绿、朱红的暖黑、藏青的冷蓝黑、摩卡的暖棕黑 —— 第一眼就能区分。
 *   ★ --on-brand 已逐一核算与 --brand 的对比度（均 ≥ 4.8:1）：
 *     前三套 brand 较亮 ⇒ 近黑字；china-red 的 #d6203a 偏深 ⇒ 近白字。
 * ========================================================================= */

/* 苍翠松林：深墨绿 + 竹青 */
html[data-theme="deep-green"] {
  --bg-0: #04120b;
  --bg-1: #081c12;
  --bg-2: #0f2c1c;
  --panel: color-mix(in srgb, var(--brand) 14%, rgba(60, 200, 140, 0.08));
  --panel-2: color-mix(in srgb, var(--brand) 18%, rgba(60, 200, 140, 0.13));
  --panel-3: color-mix(in srgb, var(--brand-2) 22%, rgba(150, 224, 130, 0.16));
  --text: #e6f7ec;
  --dim: rgba(230, 247, 236, 0.68);
  --mute: rgba(230, 247, 236, 0.42);
  --line: color-mix(in srgb, var(--brand) 28%, rgba(90, 220, 160, 0.16));
  --line-2: color-mix(in srgb, var(--brand-2) 40%, rgba(120, 230, 170, 0.28));
  --brand: #37c98a;
  --brand-2: #199e66;
  --accent: #b6e05a;
  --on-brand: #04170e;
  --glow: color-mix(in srgb, var(--brand) 36%, transparent);
  --shadow-1: 0 4px 18px rgba(2, 22, 12, 0.5);
  --shadow-2: 0 16px 46px rgba(2, 22, 12, 0.62);
  --shadow-3: 0 30px 84px rgba(1, 14, 8, 0.72);
  --glass: color-mix(in srgb, var(--brand) 12%, rgba(8, 26, 16, 0.66));
  --glass-2: color-mix(in srgb, var(--brand) 14%, rgba(11, 34, 21, 0.86));
  --hair: color-mix(in srgb, var(--brand) 30%, rgba(90, 220, 160, 0.22));
  --scheme: dark;
  --wave-1: #37c98a;
  --wave-2: #b6e05a;
  --amb-1: color-mix(in srgb, var(--brand) 32%, transparent);
  --amb-2: color-mix(in srgb, var(--brand-2) 30%, transparent);
  /* 纹理：细密的斜向竹叶纹 + 右上角一抹苔绿光 */
  --sig: repeating-linear-gradient(112deg, color-mix(in srgb, var(--brand) 12%, transparent) 0 1px, transparent 1px 26px),
    radial-gradient(54% 40% at 84% 4%, color-mix(in srgb, var(--accent) 14%, transparent), transparent 66%);
  --sig-size: 100% 100%;
  --sig-op: 1;
}

/* 中国红：正红描金 */
html[data-theme="china-red"] {
  --bg-0: #140305;
  --bg-1: #220609;
  --bg-2: #3a0c12;
  --panel: color-mix(in srgb, var(--brand) 16%, rgba(232, 177, 85, 0.07));
  --panel-2: color-mix(in srgb, var(--brand) 20%, rgba(232, 177, 85, 0.12));
  --panel-3: color-mix(in srgb, var(--brand) 26%, rgba(232, 177, 85, 0.18));
  --text: #fdeef0;
  --dim: rgba(253, 238, 240, 0.68);
  --mute: rgba(253, 238, 240, 0.42);
  --line: color-mix(in srgb, var(--brand) 32%, rgba(232, 177, 85, 0.16));
  --line-2: color-mix(in srgb, var(--brand) 46%, rgba(232, 177, 85, 0.3));
  --brand: #d6203a;
  --brand-2: #e8b155;
  --accent: #ff8a5c;
  --on-brand: #fff6f4;
  --glow: color-mix(in srgb, var(--brand) 42%, transparent);
  --shadow-1: 0 4px 18px rgba(40, 4, 10, 0.5);
  --shadow-2: 0 16px 46px rgba(40, 4, 10, 0.62);
  --shadow-3: 0 30px 84px rgba(26, 2, 6, 0.72);
  --glass: color-mix(in srgb, var(--brand) 14%, rgba(34, 6, 9, 0.68));
  --glass-2: color-mix(in srgb, var(--brand) 16%, rgba(44, 8, 12, 0.87));
  --hair: color-mix(in srgb, var(--brand) 34%, rgba(232, 177, 85, 0.22));
  --scheme: dark;
  --wave-1: #d6203a;
  --wave-2: #e8b155;
  --amb-1: color-mix(in srgb, var(--brand) 36%, transparent);
  --amb-2: color-mix(in srgb, var(--brand-2) 26%, transparent);
  /* 纹理：宫墙竖向朱柱纹 + 顶部描金横带 + 底部红色弥散 */
  --sig: repeating-linear-gradient(90deg, color-mix(in srgb, var(--brand) 14%, transparent) 0 2px, transparent 2px 52px),
    linear-gradient(180deg, color-mix(in srgb, var(--brand-2) 16%, transparent), transparent 22%),
    radial-gradient(64% 44% at 50% 104%, color-mix(in srgb, var(--brand) 20%, transparent), transparent 66%);
  --sig-size: 100% 100%;
  --sig-op: 1;
}

/* 藏青靛蓝：深靛 + 月白
 * ★ 底色刻意往**靛紫**方向压（#05071a 而不是偏青的 #040b13）：
 *   ocean 的底色也是"近黑蓝"，只按 --bg-0 量两者只差 8（量程 765）——
 *   真正拉开它们的是主色（青 #4cc9f0 ↔ 靛蓝 #5b8def，差 76）。
 *   但底色太近会让第一眼仍然像"同一个深蓝，只是高光换了色"，
 *   所以这里把 bg-0 的蓝相往紫侧推，配合主色的靛蓝，整体读起来是"藏青"而非"深海"。 */
html[data-theme="navy"] {
  --bg-0: #05071a;
  --bg-1: #0a0d28;
  --bg-2: #131b46;
  --panel: color-mix(in srgb, var(--brand) 15%, rgba(125, 211, 252, 0.07));
  --panel-2: color-mix(in srgb, var(--brand) 19%, rgba(125, 211, 252, 0.12));
  --panel-3: color-mix(in srgb, var(--brand-2) 24%, rgba(125, 211, 252, 0.16));
  --text: #e8edfb;
  --dim: rgba(232, 237, 251, 0.68);
  --mute: rgba(232, 237, 251, 0.42);
  --line: color-mix(in srgb, var(--brand) 30%, rgba(125, 211, 252, 0.16));
  --line-2: color-mix(in srgb, var(--brand-2) 42%, rgba(125, 211, 252, 0.28));
  --brand: #5b8def;
  --brand-2: #7c6df2;
  --accent: #7dd3fc;
  --on-brand: #050e22;
  --glow: color-mix(in srgb, var(--brand) 38%, transparent);
  --shadow-1: 0 4px 18px rgba(4, 6, 30, 0.5);
  --shadow-2: 0 16px 46px rgba(4, 6, 30, 0.62);
  --shadow-3: 0 30px 84px rgba(3, 4, 22, 0.72);
  --glass: color-mix(in srgb, var(--brand) 13%, rgba(10, 13, 40, 0.68));
  --glass-2: color-mix(in srgb, var(--brand) 15%, rgba(13, 17, 52, 0.87));
  --hair: color-mix(in srgb, var(--brand) 32%, rgba(125, 211, 252, 0.2));
  --scheme: dark;
  --wave-1: #5b8def;
  --wave-2: #7dd3fc;
  --amb-1: color-mix(in srgb, var(--brand) 34%, transparent);
  --amb-2: color-mix(in srgb, var(--brand-2) 30%, transparent);
  /* 纹理：藏青织物般的细密十字纹 + 左上月白光晕 */
  --sig: repeating-linear-gradient(0deg, color-mix(in srgb, var(--brand) 11%, transparent) 0 1px, transparent 1px 30px),
    repeating-linear-gradient(90deg, color-mix(in srgb, var(--brand) 11%, transparent) 0 1px, transparent 1px 30px),
    radial-gradient(52% 40% at 12% 2%, color-mix(in srgb, var(--accent) 14%, transparent), transparent 64%);
  --sig-size: 100% 100%;
  --sig-op: 1;
}

/* 摩卡醇棕：焦糖摩卡 + 奶油 */
html[data-theme="mocha"] {
  --bg-0: #0f0a06;
  --bg-1: #19110a;
  --bg-2: #2a1d13;
  --panel: color-mix(in srgb, var(--brand) 15%, rgba(217, 180, 143, 0.07));
  --panel-2: color-mix(in srgb, var(--brand) 19%, rgba(217, 180, 143, 0.12));
  --panel-3: color-mix(in srgb, var(--brand-2) 24%, rgba(217, 180, 143, 0.16));
  --text: #f7efe6;
  --dim: rgba(247, 239, 230, 0.68);
  --mute: rgba(247, 239, 230, 0.42);
  --line: color-mix(in srgb, var(--brand) 30%, rgba(217, 180, 143, 0.16));
  --line-2: color-mix(in srgb, var(--brand-2) 42%, rgba(217, 180, 143, 0.28));
  --brand: #b98a63;
  --brand-2: #8a6247;
  --accent: #d9b48f;
  --on-brand: #1a100a;
  --glow: color-mix(in srgb, var(--brand) 34%, transparent);
  --shadow-1: 0 4px 18px rgba(22, 14, 8, 0.5);
  --shadow-2: 0 16px 46px rgba(22, 14, 8, 0.62);
  --shadow-3: 0 30px 84px rgba(14, 9, 5, 0.72);
  --glass: color-mix(in srgb, var(--brand) 12%, rgba(25, 17, 10, 0.68));
  --glass-2: color-mix(in srgb, var(--brand) 14%, rgba(32, 22, 13, 0.87));
  --hair: color-mix(in srgb, var(--brand) 32%, rgba(217, 180, 143, 0.2));
  --scheme: dark;
  --wave-1: #b98a63;
  --wave-2: #d9b48f;
  --amb-1: color-mix(in srgb, var(--brand) 34%, transparent);
  --amb-2: color-mix(in srgb, var(--brand-2) 30%, transparent);
  /* 纹理：咖啡拉花般的同心弧（右下起） + 上方奶油薄光 */
  --sig: linear-gradient(180deg, color-mix(in srgb, var(--accent) 11%, transparent), transparent 34%),
    repeating-radial-gradient(circle at 78% 96%, color-mix(in srgb, var(--brand) 13%, transparent) 0 1.5px, transparent 1.5px 46px);
  --sig-size: 100% 100%;
  --sig-op: 1;
}

/* 藕荷夜色：深紫夜幕 + 藕荷粉光
 * ★ 这一套是**用数据选出来的**，不是拍脑袋挑个好看的颜色：
 *   把现有 18 套主题的主色两两量距离（`.deploy/probe/probe-theme-gap.py`），
 *   14 个候选色相里最大的一处空档是**洋红 / 玫红**这一档 ——
 *   候选 #d9559f 与最近的一套（mocha #b98a63）主色差 145（量程 765），
 *   第二名「橄榄」才 88，差距非常明显。
 *   现有带"粉"的只有浅色的 sakura（#b8145a 深玫红压浅底）和 sunset 的蜜桃橙粉，
 *   **深色底 + 洋红主色**这一格整个是空的 —— 补的就是它。
 *
 * ★★ --on-brand 不能"深色主题就无脑给白字"，它取决于 --brand 的**实际亮度**。
 *   玫红 / 洋红是**中间明度**色：压近白字实测只有 3.0~4.1:1（全部不达标，
 *   见 probe 输出的「白字对比」列）。解法不是把主色压暗 ——
 *   压暗后会发浑，而且会朝 sakura 靠拢、把刚量出来的空档又填回去。
 *   正确做法是学 deep-green / navy / mocha，给**近黑**的 --on-brand（#1a0614）：
 *   实测 5.32:1，同时按钮呈现"亮粉底 + 墨字"，正是这一档该有的观感。
 *   ⇒ 一句话判据：**--on-brand 由 --brand 的亮度决定，不由主题的深浅决定。**
 */
html[data-theme="lotus"] {
  --bg-0: #150714;
  --bg-1: #1f0a1c;
  --bg-2: #33142e;
  --panel: color-mix(in srgb, var(--brand) 15%, rgba(226, 150, 240, 0.07));
  --panel-2: color-mix(in srgb, var(--brand) 19%, rgba(226, 150, 240, 0.12));
  --panel-3: color-mix(in srgb, var(--brand-2) 24%, rgba(226, 150, 240, 0.16));
  --text: #fbeaf5;
  --dim: rgba(251, 234, 245, 0.68);
  --mute: rgba(251, 234, 245, 0.42);
  --line: color-mix(in srgb, var(--brand) 30%, rgba(226, 150, 240, 0.16));
  --line-2: color-mix(in srgb, var(--brand-2) 42%, rgba(226, 150, 240, 0.28));
  --brand: #d9559f;
  --brand-2: #9b5cf0;
  --accent: #f5a8d0;
  --on-brand: #1a0614;
  --glow: color-mix(in srgb, var(--brand) 38%, transparent);
  --shadow-1: 0 4px 18px rgba(26, 6, 22, 0.5);
  --shadow-2: 0 16px 46px rgba(26, 6, 22, 0.62);
  --shadow-3: 0 30px 84px rgba(16, 3, 14, 0.72);
  --glass: color-mix(in srgb, var(--brand) 13%, rgba(31, 10, 28, 0.68));
  --glass-2: color-mix(in srgb, var(--brand) 15%, rgba(40, 13, 36, 0.87));
  --hair: color-mix(in srgb, var(--brand) 32%, rgba(226, 150, 240, 0.2));
  --scheme: dark;
  --wave-1: #d9559f;
  --wave-2: #9b5cf0;
  --amb-1: color-mix(in srgb, var(--brand) 34%, transparent);
  --amb-2: color-mix(in srgb, var(--brand-2) 30%, transparent);
  /* 纹理：顶部一抹紫藤薄光 + 左下起、藕荷花瓣般的同心弧 */
  --sig: linear-gradient(180deg, color-mix(in srgb, var(--brand-2) 13%, transparent), transparent 32%),
    repeating-radial-gradient(circle at 22% 88%, color-mix(in srgb, var(--brand) 13%, transparent) 0 1.5px, transparent 1.5px 42px);
  --sig-size: 100% 100%;
  --sig-op: 1;
}

/* 跟随系统：默认走经典黑，系统浅色时切换为纯净白 */
html[data-theme="auto"] { color-scheme: light dark; }
@media (prefers-color-scheme: light) {
  html[data-theme="auto"] {
    --bg-0: #f4f6fb; --bg-1: #ffffff; --bg-2: #eef2fa;
    --panel: rgba(255, 255, 255, 0.86); --panel-2: rgba(255, 255, 255, 0.96); --panel-3: rgba(238, 242, 250, 0.96);
    --text: #131722; --dim: rgba(19, 23, 34, 0.66); --mute: rgba(19, 23, 34, 0.42);
    --line: rgba(19, 23, 34, 0.09); --line-2: rgba(19, 23, 34, 0.16);
    --brand: #2563eb; --brand-2: #4f8bf7; --accent: #0ea5e9; --on-brand: #fff;
    --glow: rgba(37, 99, 235, 0.22);
    --shadow-1: 0 4px 14px rgba(24, 40, 80, 0.08); --shadow-2: 0 14px 38px rgba(24, 40, 80, 0.12);
    --shadow-3: 0 28px 70px rgba(24, 40, 80, 0.16);
    --glass: rgba(255, 255, 255, 0.72); --glass-2: rgba(255, 255, 255, 0.9); --hair: rgba(19, 23, 34, 0.1);
    --scheme: light; --wave-1: #2563eb; --wave-2: #0ea5e9;
    /* ★ auto 也必须给 --amb-*：它是一条独立分支，不给就会退回 --glow 的 0.22 alpha，
       表现是"跟随系统"看起来比"纯净白"淡一档（同一套配色却不同观感）。 */
    --amb-1: rgba(37, 99, 235, 0.24); --amb-2: rgba(79, 139, 247, 0.22);
    --sig: repeating-linear-gradient(90deg, rgba(37, 99, 235, 0.07) 0 1px, transparent 1px 44px),
           repeating-linear-gradient(0deg, rgba(37, 99, 235, 0.06) 0 1px, transparent 1px 44px);
    --sig-size: 100% 100%; --sig-op: 0.85;
  }
}
@media (prefers-color-scheme: dark) {
  html[data-theme="auto"] {
    --bg-0: #08080c; --bg-1: #0d0d14; --bg-2: #12121c;
    --panel: rgba(255, 255, 255, 0.052); --panel-2: rgba(255, 255, 255, 0.082); --panel-3: rgba(255, 255, 255, 0.12);
    --text: #f2f0ea; --dim: rgba(242, 240, 234, 0.66); --mute: rgba(242, 240, 234, 0.4);
    --line: rgba(255, 255, 255, 0.09); --line-2: rgba(255, 255, 255, 0.16);
    --brand: #f5c451; --brand-2: #e0964a; --accent: #ff7a59; --on-brand: #1a1206;
    --glow: rgba(245, 196, 81, 0.28);
    --shadow-1: 0 4px 16px rgba(0, 0, 0, 0.4); --shadow-2: 0 16px 44px rgba(0, 0, 0, 0.56);
    --shadow-3: 0 30px 80px rgba(0, 0, 0, 0.66);
    --glass: rgba(16, 16, 24, 0.66); --glass-2: rgba(20, 20, 30, 0.84); --hair: rgba(255, 255, 255, 0.14);
    --scheme: dark; --wave-1: #f5c451; --wave-2: #ff7a59;
    --amb-1: rgba(245, 196, 81, 0.3); --amb-2: rgba(224, 150, 74, 0.26);
    --sig: radial-gradient(58% 42% at 14% 0%, rgba(245, 196, 81, 0.13), transparent 62%);
    --sig-size: 100% 100%; --sig-op: 1;
  }
}

/* ------------------------------- 基础重置 ------------------------------- */
*, *::before, *::after { box-sizing: border-box; }
html, body { margin: 0; padding: 0; }
html { color-scheme: var(--scheme); -webkit-text-size-adjust: 100%; }
body {
  font-family: var(--font);
  background: var(--bg-0);
  color: var(--text);
  font-size: 14px;
  line-height: 1.6;
  min-height: 100vh;
  min-height: 100dvh;
  overflow-x: hidden;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  transition: background var(--dur) var(--ease), color var(--dur) var(--ease);
}
/* 背景氛围光：随主题 + 当前封面染色
   ★★ v1.2.11：改用每套主题专属的 --amb-1 / --amb-2。
   原来只用 --glow（各主题 0.20~0.28 的 alpha）叠一层 26% 的 --brand-2，
   在浅色主题上几乎看不见 —— 实测 pure-white 与 forest-green 的**全页签名差只有 8.1**
   （L1 量程 0~765），也就是"换主题等于没换"。现在三件事一起变：
     ① 氛围色来自主题自己的 --amb-*（浓一档）
     ② 覆盖高度 68vh → 82vh，底部再补一条同色弥散
     ③ body::after 叠上该主题的质感纹理 --sig
   z-index 仍是 0，.app 是 z-index:1，所以只在内容之下；两层都 pointer-events:none。 */
body::before {
  content: "";
  position: fixed;
  /* ★★ 2026-10-17：不再用负偏移（原来是 top:-20% / left:-10%）。
     用户反馈「页面左侧顶部有条阴影」—— 负偏移会让这层氛围光**被视口左边缘硬切**，
     在状态栏下方那一段（≈顶栏高度）留下一条 10px 宽的亮带，看起来像一道脏阴影。
     现在贴齐视口、把第一个光斑从 16% 收到 20%，左边缘只留极淡的过渡，不再有硬边。 */
  top: 0; right: 0; bottom: auto; left: 0;
  height: 80vh;
  background:
    radial-gradient(44% 54% at 20% 8%, var(--amb-1, var(--glow)), transparent 70%),
    radial-gradient(38% 50% at 84% 2%, var(--amb-2, color-mix(in srgb, var(--brand-2) 26%, transparent)), transparent 70%),
    radial-gradient(60% 34% at 50% 104%, var(--amb-2, transparent), transparent 74%);
  filter: blur(30px);
  opacity: 1;
  pointer-events: none;
  z-index: 0;
  transition: background 1.2s var(--ease);
}
/* 主题质感签名层（v1.2.11 新增）
   ★ 为什么用 body::after 而不是给 .app 加背景：
     背景要铺满整屏又不能被滚动带走，且不能盖住内容 —— fixed + z-index:0 + pointer-events:none
     三件事同时满足，只有伪元素最省事（不用加任何 DOM）。
   ★ 每套主题在 base.css 顶部定义自己的 --sig / --sig-size / --sig-op。
     没定义 --sig 的主题（或被 auto 跟随的主题）自动退化成 none，不会报错。 */
body::after {
  content: "";
  position: fixed;
  top: 0; right: 0; bottom: 0; left: 0;
  background-image: var(--sig, none);
  background-size: var(--sig-size, 100% 100%);
  background-repeat: repeat;
  opacity: var(--sig-op, 0.9);
  pointer-events: none;
  z-index: 0;
  transition: opacity 0.5s var(--ease);
}
h1, h2, h3, h4, h5 { margin: 0; font-weight: 700; letter-spacing: -0.01em; }
p { margin: 0; }
a { color: inherit; text-decoration: none; }
button, input, select, textarea { font: inherit; color: inherit; }
button { background: none; border: 0; cursor: pointer; padding: 0; }
input, select, textarea { outline: none; }
img { display: block; max-width: 100%; }
ul, ol { margin: 0; padding: 0; list-style: none; }
::selection { background: var(--brand); color: var(--on-brand); }

.sprite { position: absolute; width: 0; height: 0; overflow: hidden; }
.ic { width: 20px; height: 20px; flex: none; fill: none; stroke: currentColor; stroke-width: 1.7; stroke-linecap: round; stroke-linejoin: round; }
.ic-sm { width: 16px; height: 16px; }
.ic-lg { width: 26px; height: 26px; }
.muted { color: var(--mute); }
.dim { color: var(--dim); }
.nowrap { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.hidden { display: none !important; }
[hidden] { display: none !important; }

/* 滚动条 */
* { scrollbar-width: thin; scrollbar-color: var(--line-2) transparent; }
*::-webkit-scrollbar { width: 10px; height: 10px; }
*::-webkit-scrollbar-track { background: transparent; }
*::-webkit-scrollbar-thumb { background: var(--line-2); border-radius: 99px; border: 3px solid transparent; background-clip: content-box; }
*::-webkit-scrollbar-thumb:hover { background: var(--brand); background-clip: content-box; }

/* 焦点可见（无障碍） */
/* ★★ 注意这条规则的两个坑（用户反馈「点击搜索框出现一个框」的根因）：
 *
 *   坑 1：**文本输入类元素「无论怎么聚焦」都会命中 :focus-visible**。
 *     这不是 bug 而是规范行为 —— UA 认为"用户聚焦文本框就是要打字"，
 *     所以鼠标点进去也算键盘聚焦。于是 `<input id="searchInput">` 一点就吃到
 *     这条 outline，在 999px 圆角的搜索胶囊**内部**画出一个 2px 圆角矩形，
 *     看起来就是"胶囊里又多了一个方框"。
 *     而 `input { outline: none }`（见上方 684 行）**压不住它** ——
 *     `input` 是元素选择器（0,0,1），`:focus-visible` 是伪类（0,1,0），后者胜。
 *     下面把"容器已经表达了聚焦"的输入框显式豁免掉。
 *
 *   坑 2：`border-radius: 6px` 写在全局焦点规则里 —— 这会让**任何**被键盘聚焦的
 *     元素被强行改成 6px 圆角：`.btn` 的 999px 胶囊、`.brand-mark` 的 12px 方块
 *     都会瞬间变方。焦点样式只该"描一圈"，不该改元素自身的形状，故删掉。
 *     （键盘 Tab 到按钮时的高亮仍然保留，无障碍不受影响。） */
/**
 * ★★★ 焦点环只在**键盘导航**时出现（2026-10-17 用户反馈）。
 *
 * 用户原话：「音乐播放界面播放暂停按钮，点击时有个方框阴影一闪而过，去掉方框阴影」。
 * 根因是两个叠加：
 *   ① 这条全局 `:focus-visible` 是 2px 实色描边 + 2px 偏移。
 *      Android WebView 里**手指点按钮也会命中 :focus-visible**（不像桌面 Chrome
 *      只给键盘），于是每点一下播放键就闪一圈方框；
 *   ② 而且 Chromium 66 的 outline **不跟随 border-radius**，圆按钮外面画的
 *      是**方框** —— 这就是用户说的"方框阴影"。
 *
 * 修法不是简单删掉（那会牺牲键盘用户的无障碍），而是**按交互方式分流**：
 *   `html.kb-nav` 由 ui.js 的 bindShell() 维护 —— 按下 Tab / 方向键时加上，
 *   任何 pointerdown（触摸 / 鼠标按下）时移除。
 *   ⇒ 手指点击完全不出焦点环；键盘 Tab 依然有 2px 品牌色描边。
 * ★ 选择器写成 `html:not(.kb-nav)` 而不是给每条规则加 !important：
 *   权重 (0,2,1) 已经压过原来的 `:focus-visible`(0,1,0)。
 */
:focus-visible { outline: 2px solid var(--brand); outline-offset: 2px; }
html:not(.kb-nav) :focus-visible { outline: none; }
/* 容器自带聚焦态的元素：内部再描一圈就是"多了一个框" */
.search input:focus-visible,
.input:focus-visible,
.textarea:focus-visible { outline: none; }

/**
 * 触摸端的默认点按高亮（Android 上是一块半透明矩形）。
 * 本站所有可点元素都有自己的 :active / 变色反馈，这层高亮纯属噪音 ——
 * 播放页按钮多、点按频繁，尤其明显。
 *
 * ★★★ 2026-10-19 用户反馈「手机版点底部迷你播放条的播放键，也有个方框一闪而过」。
 *   根因不是焦点环（那条上一轮已用 html.kb-nav 分流干掉），而是**这条选择器写错了名字**：
 *   原来只列了 `.playerbar`（桌面播放条）、`.mobile-tabs` 与 `#mbMini` —— 后两个
 *   在代码里**根本不存在**（底部容器是 `.mobilebottom > .mb-mini`，底栏是 `.mb-tabs`），
 *   于是桌面那颗 `#pbPlay` 正常，手机那颗 `#mbPlay` 一直吃系统默认的点按高亮：
 *   40×40 圆按钮被一块**矩形**半透明色盖住，四角超出圆弧 ⇒ 看起来就是「方框一闪」。
 *
 * ⇒ 不再用清单（清单一定漏，本轮就是漏的）：`-webkit-tap-highlight-color` 是**继承属性**，
 *   挂在 `html` 上一处生效、全站覆盖，新加的按钮/链接不用再登记。
 *   下面那条清单保留并补全，只作为「这些地方确实刻意关掉」的显式声明（冗余但无害）。
 */
html { -webkit-tap-highlight-color: transparent; }
.stage, .stage *, .playerbar, .playerbar *, .mobilebottom, .mobilebottom *,
.mobiletabs, .mobiletabs *, .mb-mini, .mb-mini *, .mb-tabs, .mb-tabs *,
.mobile-tabs, .mobile-tabs *, #mbMini, #mbMini *, .chip, .chip * {
  -webkit-tap-highlight-color: transparent;
}
.sr-only { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }
/* 窄屏下可省的文字（保留图标，避免按钮撑破标题栏） */
@media (max-width: 767px) { .hide-sm { display: none; } }

/* ------------------------------- 应用布局 ------------------------------- */
.app {
  position: relative;
  z-index: 1;
  min-height: 100dvh;
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  grid-template-rows: var(--top-h) minmax(0, 1fr);
  grid-template-areas: "top" "main";
  /* ★ 左内边距 = 导航条左偏移 + 导航条宽度 + 期望间隙。
     必须把 --nav-left 一起算进去：导航条是 `position: fixed; left: var(--nav-left); width: var(--nav-w)`，
     右边缘 = nav-left + nav-w。只按 nav-w 算会让内容区左边界正好落在导航条右边缘上（实测间隙 0px）。 */
  padding-left: calc(var(--nav-left) + var(--nav-w) + var(--nav-gap));
  padding-right: 18px;
  padding-bottom: calc(var(--player-h) + 22px);
  transition: padding-left var(--dur) var(--ease);
}
.topbar { grid-area: top; }
.content { grid-area: main; min-width: 0; }

/* 桌面端导航「展开」态（鼠标悬停自动展开 / 点按钮固定展开，JS 会给 body 加 .nav-wide）
   ★ 这里原本缺了相应规则 —— 结果是：标签文字淡入了，导航条宽度却仍是 --nav-w（86px），
   而 .sidenav / .nav-list 都是 overflow: hidden，于是标签被切掉一大半。
   实测（1440）：导航条 86px、面板右端 100px，标签 x=80 宽 28 → 右端 108px，
   最后 8px 被裁；.nav-list 内容区只到 88px，可见部分不足 30%。
   --nav-w-wide 这个变量原本在 4 个断点都定义了却从没被引用，显然就是留给这里用的。 */
@media (min-width: 1024px) {
  body.nav-wide .sidenav { width: var(--nav-w-wide); }
  /* 导航条变宽 → 内容区与底部播放条必须同步右移相同的量，间隙保持 18px 不变。 */
  body.nav-wide .app { padding-left: calc(var(--nav-left) + var(--nav-w-wide) + var(--nav-gap)); }
  body.nav-wide .playerbar { left: calc(var(--nav-left) + var(--nav-w-wide) + var(--nav-gap)); }
}

/* ------------------------------- 顶栏 ------------------------------- */
.topbar {
  display: flex;
  align-items: center;
  gap: 14px;
  height: var(--top-h);
  position: sticky;
  top: 0;
  z-index: 40;
  background: linear-gradient(to bottom, color-mix(in srgb, var(--bg-0) 92%, transparent), transparent);
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
}
.brand { display: flex; align-items: center; gap: 10px; flex: none; }
.brand-mark {
  width: 38px; height: 38px; flex: none;
  display: grid; place-items: center;
  border-radius: 12px;
  background: linear-gradient(135deg, var(--brand), var(--brand-2));
  color: var(--on-brand);
  box-shadow: 0 6px 18px var(--glow);
}
.brand-mark .ic { width: 22px; height: 22px; stroke-width: 2.1; }
.brand-text { display: flex; flex-direction: column; line-height: 1.1; }
.brand-text b { font-size: 17px; letter-spacing: 0.02em; }
.brand-text i { font-style: normal; font-size: 11px; color: var(--mute); }

.search {
  flex: 1 1 auto;
  min-width: 0;            /* ★ 必须：否则内容最小宽度(≈203px)会锁死搜索框，窄屏把顶栏顶出视口 */
  max-width: 560px;
  height: 42px;
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 0 6px 0 14px;
  border-radius: 999px;
  background: var(--panel);
  border: 1px solid var(--line);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
  transition: border-color var(--dur), box-shadow var(--dur), background var(--dur);
}
/* ★ 激活态：只做「描边换色 + 向下弥散光晕」，**不再叠 box-shadow 描边环**。
   历史：最初是 `0 0 0 4px` 的硬环（读成"外面套了个方框"）→ 改成 `0 0 0 1px`
   （环窄了但依然是一圈**额外的**轮廓，紧贴胶囊外沿 = 双层描边感）。
   叠加 2026-09 那条全局 :focus-visible 在**内部**画的方框，用户看到的就是纯粹的"两个框"。
   现在：内部方框已豁免（见上方 :focus-visible 注释），外部只留 1px 描边换色 + 光晕。 */
.search:focus-within {
  border-color: color-mix(in srgb, var(--brand) 62%, transparent);
  box-shadow: 0 14px 34px -18px var(--glow);
  background: var(--panel-2);
}
.search-ic { color: var(--mute); }
.search input {
  flex: 1; min-width: 0; height: 100%;
  background: none; border: 0; color: var(--text);
  font-size: 13.5px;
}
.search input::placeholder { color: var(--mute); }
.search input::-webkit-search-cancel-button { -webkit-appearance: none; }
/* 搜索范围：站内浮层（替代原生 select）。定位基准是 .search，故给 .search 加 relative。 */
.search { position: relative; }
.search-scope-btn {
  flex: none; height: 30px; padding: 0 8px 0 11px;
  display: inline-flex; align-items: center; gap: 3px;
  border-radius: 999px; border: 1px solid var(--line);
  background: var(--panel-2); color: var(--dim);
  font-size: 12px; cursor: pointer;
  transition: border-color var(--dur), color var(--dur);
}
.search-scope-btn:hover { color: var(--text); border-color: var(--line-2); }
.search-scope-btn .ic-sm { width: 13px; height: 13px; opacity: 0.75; }
.search-scope-menu {
  position: absolute; top: calc(100% + 8px); right: 76px; z-index: 64;
  min-width: 104px; padding: 5px;
  display: flex; flex-direction: column; gap: 2px;
  border-radius: 14px; border: 1px solid var(--line);
  background: var(--glass-2); color: var(--text);
  backdrop-filter: blur(20px) saturate(1.5); -webkit-backdrop-filter: blur(20px) saturate(1.5);
  box-shadow: var(--shadow-2);
  animation: fadeUp 0.18s var(--ease-out) both;
}
.search-scope-menu[hidden] { display: none; }
.search-scope-menu button {
  height: 30px; padding: 0 10px; border-radius: 9px; text-align: left;
  font-size: 12.5px; color: var(--dim); cursor: pointer;
}
.search-scope-menu button:hover { background: var(--panel-2); color: var(--text); }
.search-scope-menu button[aria-selected="true"] {
  background: color-mix(in srgb, var(--brand) 16%, transparent);
  color: var(--brand); font-weight: 650;
}

/* ---------------------------------------------------------------- 搜索建议
 * ★ 存在的意义：取证显示"点进搜索栏"过去什么自绘内容都不出现
 *   （聚焦前后 DOM 节点数完全不变），用户看到的所有东西都是浏览器原生控件。
 *   这个面板把"点进搜索栏"变成一个有内容、有设计的动作。
 * 内容两块：最近搜索（localStorage，可一键清空）+ 热门搜索（固定词表，离线可用）。
 * 全部本地数据 —— 它必须在断网/上游抽风时也能立刻出现，否则输入时会出现"面板闪一下又没了"。
 */
.search-suggest {
  position: absolute; top: calc(100% + 8px); left: 0; right: 0; z-index: 64;
  max-height: min(62vh, 460px); overflow-y: auto;
  padding: 12px 12px 10px;
  border-radius: 20px; border: 1px solid var(--line);
  background: var(--glass-2); color: var(--text);
  backdrop-filter: blur(22px) saturate(1.5); -webkit-backdrop-filter: blur(22px) saturate(1.5);
  box-shadow: var(--shadow-2);
  animation: fadeUp 0.18s var(--ease-out) both;
}
.search-suggest[hidden] { display: none; }
.ss-head {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  margin: 2px 4px 8px; font-size: 11.5px; color: var(--mute);
}
.ss-head button { font-size: 11.5px; color: var(--mute); cursor: pointer; }
.ss-head button:hover { color: var(--brand); }
.ss-row {
  display: flex; align-items: center; gap: 9px; width: 100%;
  height: 34px; padding: 0 10px; border-radius: 11px;
  text-align: left; font-size: 13px; color: var(--text); cursor: pointer;
}
.ss-row:hover, .ss-row.on { background: color-mix(in srgb, var(--brand) 14%, transparent); color: var(--brand); }
.ss-row .ic-sm { width: 15px; height: 15px; opacity: 0.7; flex: none; }
.ss-row b { font-weight: 600; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ss-row span { margin-left: auto; flex: none; font-size: 11px; color: var(--mute); }
.ss-row:hover span, .ss-row.on span { color: color-mix(in srgb, var(--brand) 70%, var(--mute)); }
.ss-chips { display: flex; flex-wrap: wrap; gap: 7px; padding: 0 2px 2px; }
.ss-chip {
  height: 28px; padding: 0 12px; border-radius: 999px;
  border: 1px solid var(--line); background: var(--panel);
  font-size: 12px; color: var(--dim); cursor: pointer;
  transition: border-color var(--dur), color var(--dur), background var(--dur);
}
.ss-chip:hover { border-color: color-mix(in srgb, var(--brand) 50%, transparent); color: var(--brand); background: color-mix(in srgb, var(--brand) 10%, transparent); }
.ss-empty { margin: 0; padding: 6px 4px 8px; font-size: 12px; color: var(--mute); }
.search-go {
  flex: none; height: 32px; padding: 0 16px;
  border-radius: 999px;
  background: linear-gradient(135deg, var(--brand), var(--brand-2));
  color: var(--on-brand); font-size: 13px; font-weight: 600;
  transition: transform var(--dur), filter var(--dur);
}
.search-go:hover { transform: translateY(-1px); filter: brightness(1.06); }

.topbar-actions { margin-left: auto; display: flex; align-items: center; gap: 6px; flex: none; }
/* 合并式「风格」入口：只在超窄屏出现（见下方 max-width:400px 段），
   桌面/平板上仍用 #btnTheme + #btnNavStyle 两颗一键轮换，不必多绕一层弹窗。 */
#btnStyle { display: none; }
.icon-btn {
  position: relative;
  width: 38px; height: 38px; flex: none;
  display: grid; place-items: center;
  border-radius: 12px;
  color: var(--dim);
  transition: background var(--dur), color var(--dur), transform var(--dur);
}
.icon-btn:hover { background: var(--panel-2); color: var(--text); }
.icon-btn:active { transform: scale(0.94); }
.icon-btn.is-on { color: var(--brand); background: color-mix(in srgb, var(--brand) 14%, transparent); }
.icon-btn.txt-only { width: auto; padding: 0 10px; }
.txt-btn { font-size: 12px; font-weight: 600; letter-spacing: 0.02em; }
.icon-btn .dot {
  position: absolute; top: 8px; right: 8px;
  width: 7px; height: 7px; border-radius: 50%;
  background: var(--accent); box-shadow: 0 0 0 2px var(--bg-0);
}
.user-chip {
  display: flex; align-items: center; gap: 8px;
  height: 38px; padding: 0 12px 0 5px;
  border-radius: 999px; border: 1px solid var(--line);
  background: var(--panel);
  transition: border-color var(--dur), background var(--dur), transform var(--dur);
}
.user-chip:hover { border-color: var(--line-2); background: var(--panel-2); }
.user-chip:active { transform: scale(0.97); }
.avatar {
  width: 28px; height: 28px; flex: none;
  display: grid; place-items: center;
  border-radius: 50%;
  background: linear-gradient(135deg, var(--brand), var(--brand-2));
  color: var(--on-brand); font-size: 12px; font-weight: 700;
}
.user-chip-text { font-size: 13px; color: var(--dim); max-width: 90px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* 主内容区 */
.content { padding-top: 6px; padding-bottom: 30px; }
.content:focus { outline: none; }

/* 页面通用容器 */
.page { max-width: 1560px; margin: 0 auto; display: flex; flex-direction: column; gap: 30px; animation: fadeUp 0.44s var(--ease-out) both; }
@keyframes fadeUp { from { opacity: 0; transform: translateY(14px); } to { opacity: 1; transform: none; } }

.page-head { display: flex; align-items: flex-end; justify-content: space-between; gap: 16px; flex-wrap: wrap; }
.page-title { font-size: 30px; line-height: 1.2; letter-spacing: -0.02em; display: flex; align-items: center; gap: 12px; }
.page-title .ic { width: 28px; height: 28px; color: var(--brand); }
.page-desc { color: var(--mute); font-size: 13px; margin-top: 6px; }
.page-tools { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }

/* 通用分区 */
/* ★ .section 提供的是「区块内各元素的间距」—— 主要就是 .section-head 和它下面那排卡片之间的 16px。
   ★★ 踩过的坑（用户反馈「音乐页『播放全部』、MV 页『连续播放』与下面贴合太近」）：
     这些间距**完全依赖父级的 gap**，而 .section-head 自己没有 margin。
     于是凡是把 `<div class="section-head">…</div><div class="grid">…</div>`
     塞进一个**裸 div**（没有 .section/.stack 类）的地方，两块就严丝合缝贴上（实测 0px）。
     #musicBody / #mvBody / #searchBody 三个容器原来都是裸 div，正是这个原因。
     结论：**凡是承载 .section-head + 内容 的容器，都必须带 .section（或 .stack）类**；
     不要再给 .section-head 加 margin-bottom —— 那会和父级 gap 叠加，把正常页面顶开一倍。 */
.section { display: flex; flex-direction: column; gap: 16px; }
.section-head { display: flex; align-items: center; justify-content: space-between; gap: 14px; flex-wrap: wrap; }
.section-title { font-size: 19px; display: flex; align-items: center; gap: 10px; min-width: 0; }
.section-title small { font-size: 12px; font-weight: 400; color: var(--mute); margin-left: 2px; }
.section-sub { font-size: 12px; color: var(--mute); display: flex; align-items: center; gap: 6px; }
.section-actions { display: flex; align-items: center; gap: 8px; }

/* 响应式栅格
   ★ --fit-min = 卡片最小宽度，是「每行排满」算法的唯一输入（JS 见 util.js 的 fitGrids）。
     下面的 auto-fill 只作为无 JS 时的兜底；有 JS 时列数会被内联样式按条目数重新算，
     保证每行都排满而不是留一条空轨道。所有断点因此只需要改这一个变量。 */
.grid { display: grid; gap: 18px; }
.grid-auto { --fit-min: 168px; grid-template-columns: repeat(auto-fill, minmax(var(--fit-min), 1fr)); }
.grid-cards { --fit-min: 210px; grid-template-columns: repeat(auto-fill, minmax(var(--fit-min), 1fr)); }
.grid-mini { --fit-min: 150px; grid-template-columns: repeat(auto-fill, minmax(var(--fit-min), 1fr)); }

/* 横向滚动轨道 */
.rail { display: flex; gap: 16px; overflow-x: auto; padding: 4px 2px 14px; scroll-snap-type: x proximity; scroll-behavior: smooth; }
.rail > * { scroll-snap-align: start; flex: none; }
.rail::-webkit-scrollbar { height: 8px; }

/* =============================== 响应式 =============================== */

/* 平板横屏 / 小笔电 */
@media (max-width: 1279px) {
  :root { --nav-w: 78px; --nav-w-wide: 218px; }
  .page-title { font-size: 26px; }
  .brand-text i { display: none; }
}

/* 平板竖向 */
@media (max-width: 1023px) {
  :root { --top-h: 70px; --player-h: 78px; --nav-w: 72px; --nav-w-wide: 72px; } /* v1.2.12：62 → 70，logo 上下 12 → 16px */
  .app { padding-left: calc(var(--nav-left) + var(--nav-w) + var(--nav-gap-sm)); padding-right: 14px; }
  .grid-cards { --fit-min: 186px; }
  .grid-auto { --fit-min: 152px; }
}

/* 手机（含折叠屏外屏） */
@media (max-width: 767px) {
  /* ≤767 导航栏变成 off-canvas 抽屉（见 nav.css：left:0 + translateX(-104%)），
     已不占左侧空间，故 --nav-left 归零 —— 这样折叠屏展开态那条 calc() 不会在抽屉态下多留 14px 空白。 */
  :root { --top-h: 66px; --player-h: 66px; --nav-left: 0px; } /* v1.2.12：58 → 66，logo(34px) 上下 12 → 16px */
  /* ★★ v1.2.14：手机端 LOGO 贴左边（用户第 3 次反馈）。
     此时 .sidenav 是 display:none —— 截图左侧那条其实是屏幕边缘/系统控件，不是导航栏。
     所以 LOGO 到屏幕左缘的距离就是 .app 的 padding-left（原为 12px），确实太贴。
     改法：新增 --page-pad-x 统一控制手机端左右留白，12 → 18px（左右同步，保证视觉对称）。
     ★ 只动这个变量、不碰 .topbar 内部 gap：顶栏内部间距与页面外留白是两件事，
       混在一起改会让搜索框跟着缩，反而更难调。 */
  :root { --page-pad-x: 18px; }
  .app {
    padding-left: var(--page-pad-x);
    padding-right: var(--page-pad-x);
    /*
     * ★ 手机端底部留白 = 底栏 + 迷你条 + 呼吸。
     *   原来写死 `calc(var(--player-h) + 74px)` —— 74 是"碰巧凑出来的"：
     *   那会儿底栏 60 + 迷你条 56 = 116，而 --player-h 在 ≤767 是 66，
     *   66 + 74 = 140 ≈ 116 + 24 呼吸。但 .playerbar 在手机上根本是 display:none，
     *   拿它当基数纯属历史遗留 —— 一旦再动底部两条栏，这里必然脱节。
     *   改成直接引用栏高变量：语义自解释，也不会因为播放条样式变化而漂移。
     */
    padding-bottom: calc(var(--mtabs-h) + var(--mb-mini-h) + 24px);
  }
  .topbar { gap: 8px; min-width: 0; }
  .search { min-width: 0; flex: 1 1 60px; }
  .brand-text { display: none; }
  .brand-mark { width: 34px; height: 34px; }
  .search { height: 38px; padding-left: 11px; }
  .search-scope-btn { display: none; }
  /* ★★ 手机上建议面板要铺满整屏宽，但这里有个容易踩空的坑：
     .search 自己有 backdrop-filter，而**带 filter / backdrop-filter 的元素会成为
     position:fixed 后代的包含块**（规范如此）—— 于是 left/right 只能相对那颗小胶囊算，
     实测面板只剩 192px 宽（x=57 w=192），热词折成一长条，形同没改。
     去掉手机端胶囊自己的 backdrop-filter 后，包含块上移为 .topbar，
     面板的 left/right 相对顶栏铺开 → 实测 x=22 w=346，真正整屏宽。
     视觉代价可忽略：顶栏本身已经把背景糊过一遍，胶囊底色 --panel 依旧是玻璃感；
     手机上少一层 backdrop-filter 还是净收益。
     (top 用 100% —— 包含块高度就是顶栏高，且顶栏是 sticky，面板会跟着它一起吸顶。) */
  .search { backdrop-filter: none; -webkit-backdrop-filter: none; }
  .search-suggest {
    position: fixed; left: var(--page-pad-x, 12px); right: var(--page-pad-x, 12px);
    top: calc(100% + 6px);
    max-height: min(58vh, 420px);
  }
  .search-go { display: none; }
  .user-chip { padding: 0 6px; }
  .user-chip-text { display: none; }
  .icon-btn { width: 34px; height: 34px; }
  .page { gap: 22px; }
  .page-title { font-size: 21px; }
  .page-title .ic { width: 22px; height: 22px; }
  .grid { gap: 12px; }
  .grid-cards { --fit-min: 140px; }
  .grid-auto { --fit-min: 132px; }
  .rail { gap: 12px; }
  .section-title { font-size: 17px; }
}

/* 折叠屏外屏 / 超窄屏 */
@media (max-width: 400px) {
  /* v1.2.14：10 → 14px，超窄屏同样别贴边（比 767 档略小，给搜索框留宽度） */
  :root { --page-pad-x: 14px; }
  .app { padding-left: var(--page-pad-x); padding-right: var(--page-pad-x); }
  /* 超窄屏（折叠屏外屏）：顶栏只保留必要控件，把宽度让给搜索框 */
  .topbar { gap: 6px; }
  .icon-btn { width: 30px; height: 30px; }
  .brand-mark { width: 30px; height: 30px; }
  /* ★ 超窄屏不能只"藏"不"给"：#btnTheme / #btnNavStyle 一藏，手机就**完全找不到**切换风格。
     换成一颗合并入口（点开直达设置中心「外观风格」）。
     宽度上是"一换二"而不是"净加一颗"，280 档顶栏仍放得下（实测见验收记录）。 */
  #btnTheme, #btnNavStyle { display: none; }
  #btnStyle { display: inline-flex; }
  .search { flex: 1 1 72px; }
  .section-title small { display: none; }
  .grid-cards { --fit-min: 124px; }
  .grid-auto { --fit-min: 112px; }
  .page-title { font-size: 19px; }
}

/* 折叠屏展开态（双视口分段）：铰链把视口一分为二，主内容整体右移一档，避开折痕。
   ★ 必须带上 --nav-left（导航竖条仍以 left:14px 定位），否则又会出现「导航贴着内容」。
   ★★ 还必须限定 min-width:768px。原因（实测）：折叠屏展开后 innerWidth 常仍在 ≤767 区间
      （实测 673 / 717），此时 nav.css 的 ≤767 规则已把导航栏变成 off-canvas 抽屉
      （left:0 + translateX(-278.72px)，x=-279 完全在屏外），左侧根本没有导航栏；
      若这条规则仍无条件生效，就会给页面强行留出 94px（72+22）的**空左带**，
      右侧只剩 12px —— 内容整体偏右、左边一片空白。 */
@media (horizontal-viewport-segments: 2) and (min-width: 768px) {
  .app { padding-left: calc(var(--nav-left) + var(--nav-w) + var(--nav-gap-fold)); }
}

/* 横屏手机 */
@media (max-width: 900px) and (orientation: landscape) and (max-height: 500px) {
  :root { --top-h: 58px; --player-h: 58px; } /* v1.2.12：52 → 58，横屏也别贴顶 */
}

/* 大屏 */
@media (min-width: 1680px) {
  :root { --nav-w: 96px; --nav-w-wide: 252px; }
  .grid-cards { --fit-min: 232px; }
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation-duration: 0.001ms !important; animation-iteration-count: 1 !important; transition-duration: 0.001ms !important; }
}

/* ===================================================================
 * 窄屏「圆角玻璃边框」（2026-10-18 用户反馈）
 *
 * 用户原话：「手机、平板版页面四角改为圆角，有点玻璃质感的阴影」
 *
 * ★★ 为什么不用「给 .app 加 border-radius + overflow:hidden」——这是最直觉的写法，但**不行**：
 *    本站的滚动容器是 document（`body{min-height:100dvh}`，`.topbar` 是 `position:sticky`），
 *    `.app` 是一个**比视口高得多**的元素，它的圆角只存在于**页面最顶端**那一处；
 *    往下滚 200px 之后，视口四边仍然是直角 —— 用户看到的是"只有第一屏有圆角"。
 *    ⇒ 必须让圆角**固定在视口上**，所以用两层 `position:fixed` 的伪元素覆层：
 *        html::after  —— 四个角的遮罩：把圆角弧线**外侧**那块画成页面底色 var(--bg-0)
 *        html::before —— 一圈玻璃棱线 + 内侧柔光（box-shadow 的 inset）
 *    `body` 的底色就是 `background: var(--bg-0)`（纯色，不是渐变），所以角块画上去是**无缝**的，
 *    这点很关键：换成渐变底就会露出四个深色小方块。
 *
 * ★ 为什么挂在 `html` 上而不是 `.app` 上：`.app` 有 `position:relative; z-index:1`
 *   ⇒ 它自己是一个层叠上下文，里面的 fixed 子元素**全部**被压在这一层里，
 *   而 `.mobiletabs`(70) / `.mobilebottom`(69) / `.modal`(120) / `.stage`(110) / `.theater`(130)
 *   都是 body 的直接子节点、z-index 更大。挂在 .app 里的话，底部两条栏会盖住下方两个角，
 *   "四角圆角"只剩上面两个。挂 html 才是真正盖在全站之上。
 *
 * ★ 层级：180 / 181 —— 高于 theater(130) / modal(120) / queue(115) / stage(110)，
 *   低于 `.toasts`(200)。两层都是 `pointer-events:none`，不参与任何命中测试
 *   （.deploy/test-shell-polish.mjs 有反向断言，防止哪天被改成能点）。
 *
 * ★ 禁用清单遵守：不用 `backdrop-filter`（Chromium 66 不支持）、
 *   不用 `inset` 简写、不用 `min()/max()/clamp()`、不用 `aspect-ratio`。
 *   四个角块用 `radial-gradient` 的**颜色停止点**画弧线，老引擎完全支持。
 * =================================================================== */
@media (max-width: 1023px) {
  /* 玻璃棱 + 内侧柔光：只画"边"，本身不铺底色，所以不需要裁切 */
  html::before {
    content: "";
    position: fixed;
    top: 0;
    right: 0;
    bottom: 0;
    left: 0;
    z-index: 181;
    pointer-events: none;
    border-radius: var(--frame-r);
    /* ① 1px 棱线（跟随圆角）—— 深色主题下是白色高光，浅色主题下是发丝线，都由 --hair 决定；
       ② 内侧 24px 柔光 —— "玻璃压在手边"的那种厚度感，纯黑低透明度，两套主题都不脏；
       ③ 顶边再补 1px 亮线 —— 光从上方来，这条最像玻璃。 */
    box-shadow:
      inset 0 0 0 1px var(--hair),
      inset 0 0 24px rgba(0, 0, 0, 0.18),
      inset 0 1px 0 rgba(255, 255, 255, 0.1);
  }
  /* 四角：半径 --frame-r 的圆弧，弧线外侧填页面底色（把直角"切掉"）。
     ★★ 关键几何：**弧心内缩一个半径**，即左上角那颗的圆心在 (r, r)，不是 (0, 0)。
        写成 `at 0 0` 会得到完全相反的极性 —— 角上那一点点被"挖透明"、
        而整圈 21px 外圈全被涂成底色，看起来是四个发亮的缺口（第一版就是这么错的）。
      ⇒ 每颗图块的圆心都放在**朝向视口内部的那个角**上：
         left top → `at 100% 100%` ｜ right top → `at 0 100%`
         left bottom → `at 100% 0` ｜ right bottom → `at 0 0`
       `0/100%` 都是**图块自身**的百分比，所以贴到 right/bottom 后仍然对准视口角。
     ★ 20px→22px 留 2px 渐变带做抗锯齿（老引擎的 radial-gradient 边缘是硬的，不留会数出锯齿）。 */
  html::after {
    content: "";
    position: fixed;
    top: 0;
    right: 0;
    bottom: 0;
    left: 0;
    z-index: 180;
    pointer-events: none;
    background-image:
      radial-gradient(circle at 100% 100%, transparent 20px, var(--bg-0) 22px),
      radial-gradient(circle at 0 100%, transparent 20px, var(--bg-0) 22px),
      radial-gradient(circle at 100% 0, transparent 20px, var(--bg-0) 22px),
      radial-gradient(circle at 0 0, transparent 20px, var(--bg-0) 22px);
    background-size: var(--frame-r) var(--frame-r);
    background-position: left top, right top, left bottom, right bottom;
    background-repeat: no-repeat;
  }
}
