/**
 * 主题系统 (Theme System)
 *
 * 六套主题(英文 + 中文混搭):Dark 深色 / Night 极夜 / Light 浅色 /
 * Amber 琥珀 / Ocean 海蓝 / Forest 森绿。
 * - 默认主题 Dark 深色 由 [data-theme="dark"] 定义
 * - Light 浅色由各 CSS 文件的 :root 定义(不写 data-theme 时生效)
 * - 其余 5 套(Night / Amber / Ocean / Forest + 隐藏 sepia 兜底)各自 [data-theme="xxx"] 覆盖变量
 * - 必须加载在所有其他 CSS 之后,保证变量覆写优先级
 *
 * 触发方式:<html data-theme="dark|night|sepia|ocean|forest">
 * 不设置或为空 = Light 浅色(:root 默认值生效)
 *
 * 主题按钮 + 快捷键 T 见 theme.js / smusic.enhance.js
 */

/* ============== 深色主题 (Dark) ============== */

:root[data-theme="dark"] {
    color-scheme: dark;
    --bg:           #16161a;
    --bg-elevated:  #232328;
    --bg-hover:     #2a2a30;
    --bg-active:    #303036;
    --border:       #2e2e34;
    --border-strong:#3a3a42;
    --text:         #f0f0f4;
    --text-soft:    #c8c8d0;
    --text-mute:    #8e8e96;
    /* v54+: 暗色主题 --text-strong = 纯白,在 #16161a 上 17.78:1 ✓ AAA。
       用于 .app-sidebar-close:hover/focus-visible 等焦点态文字色。 */
    --text-strong:  #ffffff;
    --accent:       #a78bfa;
    --accent-soft:  rgba(167, 139, 250, 0.14);
    --accent-line:  rgba(167, 139, 250, 0.36);
    /* v54+: 暗色主题 --accent-hover 比 --accent (#a78bfa) 更亮一档,保证深色背景下
       hover 视觉反馈明显。c4b5fd 在 #16161a 上 8.46:1 ✓ AAA。 */
    --accent-hover: #c4b5fd;
    --shadow-card:        0 1px 3px rgba(0, 0, 0, 0.45);
    --shadow-card-hover:  0 6px 16px -4px rgba(167, 139, 250, 0.30);
    --shadow-popup:       0 10px 30px -8px rgba(0, 0, 0, 0.6);
    /* v38: dark 主题下用更亮的橘红,确保 13px 文字 ≥4.5:1。
       原 #c2410c(L=0.1306) 在 #16161a(L=0.00863) 上 3.22:1。
       #f97316(L=0.2969) → 5.71:1 ✓ */
    --danger:        #f97316;
    --danger-soft:   rgba(249, 115, 22, 0.12);
}

/* 选区颜色 */
:root[data-theme="dark"] ::selection {
    background: rgba(167, 139, 250, 0.36);
    color: var(--text);
}

/* 列表奇数行微底色 — 浅黑改浅白 */
:root[data-theme="dark"] .m-music-list-wrap li:nth-child(odd) {
    background: rgba(255, 255, 255, 0.025);
}

/* 卡片阴影 — 深色下用深紫微光代替黑色阴影 */
:root[data-theme="dark"] .card {
    box-shadow: var(--shadow-card);
}
:root[data-theme="dark"] .card:hover {
    box-shadow: var(--shadow-card-hover);
}

/* 全屏顶部进度条轨道 — 深色下背景加深以区分 */
:root[data-theme="dark"] .app-fullscreen-topbar::before {
    background: rgba(255, 255, 255, 0.10);
}

/* 全屏主播放按钮 inner glow — 浅色背景的白色高光在深色下过亮,降权 */
:root[data-theme="dark"] .fs-play::after {
    background:
        radial-gradient(circle at 30% 18%, rgba(255, 255, 255, 0.18) 0%, transparent 55%),
        radial-gradient(circle at 50% 110%, rgba(0, 0, 0, 0.30) 0%, transparent 60%);
}

/* 全屏封面播放按钮右上方按钮 — 阴影在深色下补底 */
:root[data-theme="dark"] .fs-ctrl,
:root[data-theme="dark"] .app-fullscreen-close {
    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.45);
}

/* 移动端抽屉投影加深 */
:root[data-theme="dark"] .app-sidebar {
    box-shadow: 4px 0 24px rgba(0, 0, 0, 0.6);
}

/* 底部封面 hover 遮罩 — 浅色下用半透黑,深色下也用半透黑,
   让白图标 stroke='white' 在深遮罩上保持高对比。原版 dark 用半透白
   与图标同色几乎不可见。 */
:root[data-theme="dark"] .app-player-bar .u-cover::after {
    background: rgba(0, 0, 0, 0.45);
}

/* cheat sheet backdrop — 深色下加沉 */
:root[data-theme="dark"] .m-cheatsheet::backdrop {
    background: rgba(0, 0, 0, 0.6);
}
:root[data-theme="dark"] .m-cheatsheet-card {
    box-shadow: 0 24px 60px -16px rgba(0, 0, 0, 0.7);
}

/* 返回首页按钮 (standalone) — 阴影 */
:root[data-theme="dark"] .back-home {
    box-shadow: 0 2px 6px rgba(0, 0, 0, 0.5);
}

/* standalone 播放器卡片阴影 */
:root[data-theme="dark"] .grid-music-container:not(.app-player-bar):not(.app-main) {
    box-shadow: 0 12px 40px -12px rgba(0, 0, 0, 0.6);
}


/* ============== 护眼主题 (Sepia) ============== */

:root[data-theme="sepia"] {
    color-scheme: light;
    --bg:           #f5ecd9;
    --bg-elevated:  #fbf6ed;
    --bg-hover:     #ede2cd;
    --bg-active:    #e5d8be;
    --border:       #e3d6bd;
    --border-strong:#d4c19e;
    --text:         #3a3225;
    --text-soft:    #5a4d39;
    --text-mute:    #6f5e4a;
    /* v54+: sepia --text-strong = 近黑,3a3225 → 1a1410 (L: 0.04 → 0.018) 强化对比 */
    --text-strong:  #1a1410;
    /* v38: accent #a05a2c 在 --bg #f5ecd9 上 4.55:1,边缘过不了 WCAG AA(4.5:1);
     改 #8c4a1f → 5.74:1 ✓;阴影/soft/line 同步加深与原色调一致 */
    --accent:       #8c4a1f;
    /* v56+:0.10 → 0.14 — 与 dark/light/night 对齐 .current 视觉强度,
       之前 sepia 在底色较浅背景下当前曲目 bg 偏弱,不易识别 */
    --accent-soft:  rgba(140, 74, 31, 0.14);
    --accent-line:  rgba(140, 74, 31, 0.36);
    /* v54+: sepia --accent-hover 比 #8c4a1f 略亮一档(#a05a2c),保持暖色调和谐 */
    --accent-hover: #a05a2c;
    --shadow-card:        0 1px 3px rgba(120, 80, 40, 0.08);
    --shadow-card-hover:  0 6px 16px -4px rgba(140, 74, 31, 0.22);
    --shadow-popup:       0 10px 30px -10px rgba(120, 80, 40, 0.22);
    /* v38: sepia 沿用 #c2410c,在 #fbf6ed 上 4.84:1 ✓ (浅色危险按钮 OK) */
    --danger:        #c2410c;
    --danger-soft:   rgba(194, 65, 12, 0.08);
}

/* 选区颜色 */
:root[data-theme="sepia"] ::selection {
    background: rgba(160, 90, 44, 0.22);
    color: var(--text);
}

/* 列表奇数行微底色 — 浅暖灰 */
:root[data-theme="sepia"] .m-music-list-wrap li:nth-child(odd) {
    background: rgba(160, 90, 44, 0.025);
}

/* 卡片阴影 — 暖棕色调 */
:root[data-theme="sepia"] .card {
    box-shadow: var(--shadow-card);
}
:root[data-theme="sepia"] .card:hover {
    box-shadow: var(--shadow-card-hover);
}

/* 全屏主播放按钮 inner glow — 中性化 (sepia 下白色高光会过亮) */
:root[data-theme="sepia"] .fs-play::after {
    background:
        radial-gradient(circle at 30% 18%, rgba(255, 255, 255, 0.20) 0%, transparent 55%),
        radial-gradient(circle at 50% 110%, rgba(0, 0, 0, 0.10) 0%, transparent 60%);
}

/* 移动端抽屉阴影用暖色调 */
:root[data-theme="sepia"] .app-sidebar {
    box-shadow: 4px 0 16px rgba(120, 80, 40, 0.18);
}


/* ============== 海洋主题 (Ocean) — 蓝调浅色 ============== */

:root[data-theme="ocean"] {
    color-scheme: light;
    --bg:           #eaf2fa;
    --bg-elevated:  #ffffff;
    --bg-hover:     #dde9f5;
    --bg-active:    #cfdfee;
    --border:       #d3e0ee;
    --border-strong:#b8cbde;
    --text:         #14253a;
    --text-soft:    #3d4d65;
    --text-mute:    #5a6b82;
    /* v54+: ocean --text-strong = 近黑 0a1628,与 --text 14253a 同色相加深 */
    --text-strong:  #0a1628;
    --accent:       #0369a1;
    /* v56+:0.10 → 0.14 — 与其他主题对齐 .current 视觉强度 */
    --accent-soft:  rgba(3, 105, 161, 0.14);
    --accent-line:  rgba(3, 105, 161, 0.36);
    /* v54+: ocean --accent-hover 比 #0369a1 略亮 (#0c7eb5),保持蓝色调和谐 */
    --accent-hover: #0c7eb5;
    --shadow-card:        0 1px 3px rgba(20, 50, 90, 0.06);
    --shadow-card-hover:  0 6px 16px -4px rgba(3, 105, 161, 0.22);
    --shadow-popup:       0 10px 30px -10px rgba(20, 50, 90, 0.18);
    /* v38: ocean 浅色 + #c2410c → 5.20:1 ✓ */
    --danger:        #c2410c;
    --danger-soft:   rgba(194, 65, 12, 0.08);
}

/* 选区 */
:root[data-theme="ocean"] ::selection {
    background: rgba(3, 105, 161, 0.22);
    color: var(--text);
}

/* 列表奇数行 */
:root[data-theme="ocean"] .m-music-list-wrap li:nth-child(odd) {
    background: rgba(3, 105, 161, 0.025);
}

/* 卡片阴影 */
:root[data-theme="ocean"] .card {
    box-shadow: var(--shadow-card);
}
:root[data-theme="ocean"] .card:hover {
    box-shadow: var(--shadow-card-hover);
}

/* 全屏 inner glow 略调 */
:root[data-theme="ocean"] .fs-play::after {
    background:
        radial-gradient(circle at 30% 18%, rgba(255, 255, 255, 0.28) 0%, transparent 55%),
        radial-gradient(circle at 50% 110%, rgba(0, 0, 0, 0.12) 0%, transparent 60%);
}

/* 移动端抽屉阴影 */
:root[data-theme="ocean"] .app-sidebar {
    box-shadow: 4px 0 16px rgba(20, 50, 90, 0.15);
}


/* ============== 森林主题 (Forest) — 绿系浅色 ============== */

:root[data-theme="forest"] {
    color-scheme: light;
    --bg:           #eef3e8;
    --bg-elevated:  #ffffff;
    --bg-hover:     #dfe7d3;
    --bg-active:    #d0dbbf;
    --border:       #d4dec6;
    --border-strong:#bccba6;
    --text:         #152818;
    --text-soft:    #3d4a32;
    /* v47:#56664a 在 --bg #eef3e8 上 5.49:1 ✓ AA,但在 --bg-active #d0dbbf 上仅
       4.18:1 ✗ AA fail。改 #4a5a3e:5 背景全过 AA(bg 6.25:1 / hover 5.55:1 /
       active 4.77:1),与 --text-soft 视觉权重略有差异但仍在合理层级。 */
    --text-mute:    #4a5a3e;
    /* v54+: forest --text-strong = 近黑 0a1f12,与 --text 152818 同绿色调加深 */
    --text-strong:  #0a1f12;
    /* v40 P1 修复:#15803d 在 #eef3e8 上仅 4.45:1、#dfe7d3 (hover) 3.94:1、
       #d0dbbf (active) 3.48:1、accent-soft 上 4.38:1 — 4 处 WCAG AA (4.5:1) 失败。
       改 #0d5b29 → #eef3e8 6.71:1、#dfe7d3 5.84:1、#d0dbbf 5.08:1、accent-soft 5.32:1 ✓
       soft/line 同步加深保持视觉强度一致 */
    --accent:       #0d5b29;
    /* v56+:0.12 → 0.14 — 与其他主题对齐 .current 视觉强度 */
    --accent-soft:  rgba(13, 91, 41, 0.14);
    --accent-line:  rgba(13, 91, 41, 0.36);
    /* v54+: forest --accent-hover 比 #0d5b29 略亮 (#15803d),保持绿色调和谐 */
    --accent-hover: #15803d;
    --shadow-card:        0 1px 3px rgba(20, 60, 30, 0.06);
    --shadow-card-hover:  0 6px 16px -4px rgba(13, 91, 41, 0.24);
    --shadow-popup:       0 10px 30px -10px rgba(20, 60, 30, 0.18);
    /* v38: forest 浅色 + #c2410c → 5.06:1 ✓ */
    --danger:        #c2410c;
    --danger-soft:   rgba(194, 65, 12, 0.08);
}

/* 选区 */
:root[data-theme="forest"] ::selection {
    background: rgba(21, 128, 61, 0.22);
    color: var(--text);
}

/* 列表奇数行 */
:root[data-theme="forest"] .m-music-list-wrap li:nth-child(odd) {
    background: rgba(21, 128, 61, 0.025);
}

/* 卡片阴影 */
:root[data-theme="forest"] .card {
    box-shadow: var(--shadow-card);
}
:root[data-theme="forest"] .card:hover {
    box-shadow: var(--shadow-card-hover);
}

/* 全屏 inner glow 略调 */
:root[data-theme="forest"] .fs-play::after {
    background:
        radial-gradient(circle at 30% 18%, rgba(255, 255, 255, 0.28) 0%, transparent 55%),
        radial-gradient(circle at 50% 110%, rgba(0, 0, 0, 0.12) 0%, transparent 60%);
}

/* 移动端抽屉阴影 */
:root[data-theme="forest"] .app-sidebar {
    box-shadow: 4px 0 16px rgba(20, 60, 30, 0.15);
}


/* ============== 暗夜主题 (Night) — 极夜青 ============== */

:root[data-theme="night"] {
    color-scheme: dark;
    --bg:           #0d1117;
    /* bg-elevated 由 #161b22 提到 #1c232c — 与 bg 对比度 ~1.4,
       popup/card 弹层与主背景视觉层次更清(原 ~1.18 偏暗,弹层几乎贴底) */
    --bg-elevated:  #1c232c;
    --bg-hover:     #1f2630;
    --bg-active:    #262e3a;
    --border:       #21262d;
    --border-strong:#30363d;
    --text:         #e6edf3;
    --text-soft:    #c1cad4;
    --text-mute:    #8d95a0;
    /* v54+: night --text-strong = 近白 f0f6fc,与 --text e6edf3 同冷色相加深 */
    --text-strong:  #f0f6fc;
    --accent:       #22d3ee;
    --accent-soft:  rgba(34, 211, 238, 0.14);
    --accent-line:  rgba(34, 211, 238, 0.36);
    /* v54+: night --accent-hover 比 #22d3ee 略亮 (#67e8f9),保持青色调和谐 */
    --accent-hover: #67e8f9;
    --shadow-card:        0 1px 3px rgba(0, 0, 0, 0.55);
    --shadow-card-hover:  0 6px 16px -4px rgba(34, 211, 238, 0.32);
    --shadow-popup:       0 10px 30px -8px rgba(0, 0, 0, 0.6);
    /* v38: night 主题下用更亮的橘红,确保 13px 文字 ≥4.5:1。
       原 #c2410c(L=0.1306) 在 #0d1117(L=0.0075) 上 3.38:1。
       #f97316(L=0.2969) → 5.74:1 ✓ */
    --danger:        #f97316;
    --danger-soft:   rgba(249, 115, 22, 0.12);
}

/* 选区 */
:root[data-theme="night"] ::selection {
    background: rgba(34, 211, 238, 0.34);
    color: var(--text);
}

/* 列表奇数行 */
:root[data-theme="night"] .m-music-list-wrap li:nth-child(odd) {
    background: rgba(255, 255, 255, 0.025);
}

/* 卡片阴影 — 极夜背景下用青色微光 */
:root[data-theme="night"] .card {
    box-shadow: var(--shadow-card);
}
:root[data-theme="night"] .card:hover {
    box-shadow: var(--shadow-card-hover);
}

/* 全屏 inner glow */
:root[data-theme="night"] .fs-play::after {
    background:
        radial-gradient(circle at 30% 18%, rgba(255, 255, 255, 0.18) 0%, transparent 55%),
        radial-gradient(circle at 50% 110%, rgba(0, 0, 0, 0.35) 0%, transparent 60%);
}
:root[data-theme="night"] .fs-ctrl,
:root[data-theme="night"] .app-fullscreen-close {
    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.55);
}
:root[data-theme="night"] .app-fullscreen-topbar::before {
    background: rgba(255, 255, 255, 0.10);
}
:root[data-theme="night"] .app-sidebar {
    box-shadow: 4px 0 24px rgba(0, 0, 0, 0.65);
}
/* v40 P0 修复:night 沿用 dark 的深遮罩策略,保持白图标 + 深遮罩对比。
   原 rgba(255,255,255,0.20) 半透白遮罩与图标 stroke='white' 几乎不可见。 */
:root[data-theme="night"] .app-player-bar .u-cover::after {
    background: rgba(0, 0, 0, 0.45);
}
:root[data-theme="night"] .m-cheatsheet::backdrop {
    background: rgba(0, 0, 0, 0.65);
}
:root[data-theme="night"] .m-cheatsheet-card {
    box-shadow: 0 24px 60px -16px rgba(0, 0, 0, 0.75);
}
:root[data-theme="night"] .back-home {
    box-shadow: 0 2px 6px rgba(0, 0, 0, 0.55);
}
:root[data-theme="night"] .grid-music-container:not(.app-player-bar):not(.app-main) {
    box-shadow: 0 12px 40px -12px rgba(0, 0, 0, 0.7);
}


/* ============== 主题下拉菜单 (跨主题) ============== */

/* 容器 — 相对定位,popup 绝对定位挂它上面 */
.theme-switcher {
    position: relative;
    display: inline-flex;
    align-items: center;
}

/* 触发按钮 — 复用 .app-theme-btn / .home-theme-btn 形状,加内容布局 */
.theme-trigger {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 6px 10px;
    /* v29 round 4+: 8px → var(--r-md) */
    border-radius: var(--r-md);
    cursor: pointer;
    color: var(--text-soft);
    background: transparent;
    border: 1px solid transparent;
    transition: color var(--t-base) var(--ease), background-color var(--t-base) var(--ease),
                border-color var(--t-base) var(--ease), transform var(--t-fast) var(--ease);
}
.theme-trigger:hover {
    color: var(--accent);
    background: var(--accent-soft);
}
.theme-trigger:active {
    transform: scale(0.96);
}
/* v37:P2-5 删 :focus-visible 重复 outline — 全局 :focus-visible (app.css) 已设 2px accent + offset 2px,
   此处只是重复同样的属性,纯冗余 */
/* popup 打开时,触发按钮保持 accent 色,作为视觉锚点 */
.theme-switcher.open .theme-trigger {
    color: var(--accent);
    background: var(--accent-soft);
}

.theme-trigger-icon {
    display: inline-flex;
    width: 16px;
    height: 16px;
    flex-shrink: 0;
    transition: transform var(--t-base) var(--ease);
}
.theme-trigger:hover .theme-trigger-icon,
.theme-switcher.open .theme-trigger-icon {
    transform: rotate(-15deg);
}
.theme-trigger-icon svg {
    width: 100%;
    height: 100%;
}

.theme-trigger-label {
    font-size: var(--fs-md);
    font-weight: var(--fw-medium);
    letter-spacing: var(--tracking-tag);
    white-space: nowrap;
}

.theme-trigger-caret {
    display: inline-flex;
    width: 12px;
    height: 12px;
    margin-left: 2px;
    transition: transform var(--t-base) var(--ease-in-out);
    opacity: 0.65;
}
.theme-trigger-caret::before {
    content: '';
    display: block;
    width: 0;
    height: 0;
    border-left: 4px solid transparent;
    border-right: 4px solid transparent;
    border-top: 5px solid currentColor;
    margin: 4px auto 0;
}
.theme-switcher.open .theme-trigger-caret {
    transform: rotate(180deg);
}

/* Popup — 默认锚定在触发按钮下方,右对齐 */
.theme-popup {
    position: absolute;
    top: calc(100% + 10px);
    right: 0;
    /* 加 desc 后整体宽度需要更宽 — 240 容不下 6 汉字 desc + swatch + en + check + 4×gap */
    min-width: 268px;
    /* v60+ 极紧凑:header 整体删除后,padding 进一步压到 2px。
       弹窗直接贴着第一项,顶/底各 2px 内边距仅留视觉呼吸。 */
    padding: 2px;
    border-radius: 14px;
    /* v34 P1 修复:不透明背景搬到 ::before,popup 自身透明 → backdrop-filter 真有"后方"可模糊。
       不支持 color-mix 的浏览器由 @supports fallback 重新加回不透明 background。 */
    border: 1px solid var(--border);
    box-shadow: var(--shadow-popup);
    z-index: var(--z-popup);
    display: flex;
    flex-direction: column;
    gap: 2px;
    /* P0 性能修复:backdrop-filter saturate(1.4) blur(12px) 在 z-index 9999 popup
       上每帧都要重模糊视口背后区域。旧实现把 backdrop-filter 直接装在 popup 上,
       入场动画 200ms 期间每帧都重做模糊 + saturation。

       修复:把模糊搬到 ::before 伪元素,默认 opacity:0,入场动画结束时(100%)切到 1。
       动画期间只动 transform/opacity(compositor-only),模糊只渲染一次。
       关闭时也走动画,模糊随 ::before 一起淡出,不留视觉割裂。

       v40 P0 修复:加 max-height + overflow-y auto,避免 568×320 横屏 / ≤320 极窄高
       视口下 popup 整体 346px 高超出视口 84px,后几个主题被截断无滚动条。 */
    max-height: calc(100dvh - var(--safe-top) - var(--safe-bottom) - 16px);
    overflow-y: auto;
    transform-origin: top right;
    animation: theme-popup-in .2s cubic-bezier(.2, .8, .3, 1.05);
}
/* 模糊放在伪元素上 — 伪元素继承 popup 形状,inset:0 铺满。
   ::before 不参与 transform,但通过自身的 opacity 同步淡入。
   animation-fill-mode: backwards 让 0% 关键帧在动画启动前就生效(opacity:0),
   避免 popup 显示瞬间模糊层闪现一下。
   v34 P1 修复:把 popup 的不透明背景搬到 ::before 上,让 backdrop-filter 真有"后方内容"可模糊 —
   原版 popup 自身 background: var(--bg-elevated) 不透明,::before 用 z-index:-1 被画在父背景后,
   但父背景自己就是不透明色,backdrop-filter 看到的"后面"是 popup 纯色背景而非视口内容 → 6 主题
   glassmorphism 全失效(看着仍是纯白/纯深卡),P0 性能修复的收益完全落空。
   现在 ::before 既带背景色又带 backdrop-filter,opacity 控制淡入淡出,blur 真起作用。 */
.theme-popup::before {
    content: '';
    position: absolute;
    inset: 0;
    border-radius: inherit;
    pointer-events: none;
    /* popup 自身不再设 background,改成 ::before 持有半透明背景 + 模糊。
       var(--bg-elevated) 在 6 主题下都是纯色,用 rgb 通道转换为半透明 — 但写死 rgba
       又会破坏主题切换。最简办法:用 color-mix() 把 bg-elevated 调到 88% 不透明,
       老 Safari 不支持 color-mix 的地方 fallback 到 100% (theme-popup 自身的 background)。 */
    background: color-mix(in srgb, var(--bg-elevated) 88%, transparent);
    backdrop-filter: saturate(1.4) blur(12px);
    -webkit-backdrop-filter: saturate(1.4) blur(12px);
    animation: theme-popup-blur-in .2s cubic-bezier(.2, .8, .3, 1.05) backwards;
}
/* v34 P0 修复:backdrop-filter 不进动画。
   backdrop-filter 每帧插值会让浏览器每帧重新模糊 popup 背后整片视口,
   与同块注释里"只动 transform/opacity"的优化目标冲突。
   改为:模糊静态放在 ::before 自身,动画期间只动 opacity(compositor-only)。
   saturate/blur 值固定,模糊只渲染一次,入场动画结束随 ::before 一起 100% 不透明。 */
@keyframes theme-popup-blur-in {
    from { opacity: 0; }
    to   { opacity: 1; }
}
/* @supports 兜底分两路:
   1) 浏览器完全不支持 backdrop-filter — ::before 没模糊意义,直接当背景用
   2) 浏览器不支持 color-mix — popup 自身用 fallback 不透明背景 */
@supports not (backdrop-filter: blur(1px)) {
    /* 极老浏览器兜底:始终显示 */
    .theme-popup::before { display: none; }
    .theme-popup { background: var(--bg-elevated); }
}
@supports not (background: color-mix(in srgb, red, blue)) {
    /* 不支持 color-mix — popup 用 fallback 不透明背景,glassmorphism 失效但能用 */
    .theme-popup { background: var(--bg-elevated); }
}

/* HTML `hidden` 属性默认 `display: none`,但上面规则用 `display: flex`
   优先级更高导致 popup 默认就显示出来 — 用 [hidden] 提高特异性,
   强制关闭。未触发时不占布局、不可见。 */
.theme-popup[hidden] {
    display: none !important;
    animation: none;
}
@keyframes theme-popup-in {
    from { opacity: 0; transform: scale(0.96) translateY(-4px); }
    to   { opacity: 1; transform: scale(1)    translateY(0);    }
}

/* 在 .app 上下文里 trigger 是顶栏最右按钮 — popup 必须右对齐贴在 trigger 右边缘,
   否则 popup 会向右延伸到视口外,把英文名/描述裁掉。
   原 left:0 是为了避开中间的分类标题,但 trigger 现在在最右,
   右对齐自然不会越过分类标题(它在左边),反而是唯一不裁内容的方案。 */
.app .theme-popup {
    right: 0;
    left: auto;
    transform-origin: top right;
    animation-name: theme-popup-in;
}

/* 单个选项 */
.theme-option {
    position: relative;
    display: grid;
    grid-template-columns: 20px 1fr auto 18px;
    align-items: center;
    gap: 12px;
    padding: 9px 12px;
    border: none;
    background: transparent;
    color: var(--text);
    font-size: var(--fs-md);
    border-radius: 9px;
    cursor: pointer;
    text-align: left;
    transition:
        background-color var(--t-base) var(--ease),
        color var(--t-base) var(--ease),
        transform var(--t-base) var(--ease);
}
/* hover/focus 时左侧滑入一道色条,显示该选项的**真实主题色**(而非当前主题色)。
   --theme-accent 由 buildPopup 给每个 option 注入 inline style,
   与 .theme-option-swatch 用同一组 swatch,做到色条与色点"双锚点"同步。 */
.theme-option::before {
    content: '';
    position: absolute;
    left: 4px;
    /* top:20% + height:60% = bottom 80%,垂直完美居中。
       之前 top:50% + margin-top:-30% 是错的:CSS 规范里 percentage margin
       基于 containing block 的 **width**(不是 height,也不是元素自身 height),
       option width ≈ 250px → margin-top:-30% = -75px,与 top:50%(26.6px) 相加
       后变成 -48px,色条整个跑到 option 上方视野外,看起来"错位"。
       删 margin-top,直接 top:20% 让静态定位只依赖 height,既正确又与
       scaleY(0→1) transform 动画不冲突。 */
    top: 20%;
    width: 3px;
    height: 60%;
    border-radius: 3px;
    background: var(--theme-accent, var(--accent));
    /* P1 性能修复:旧版 transition: height + margin-top 是 layout-triggering 属性,
       每帧重排。改为 transition: transform + opacity(compositor-only)。
       默认 scaleY(0) 隐藏在中心(默认 transform-origin 50% 50%,塌缩到 50% 一线),
       hover 时 scaleY(1) 撑开,无 layout。 */
    transform: scaleY(0);
    opacity: 0;
    transition: transform var(--t-base) var(--ease-in-out),
                opacity var(--t-base) var(--ease);
}
.theme-option:hover,
.theme-option:focus-visible {
    background: var(--bg-hover);
    outline: none;
}
/* 不再改 padding-left 制造"内容右移"效果:
   旧版 padding 12→18px 触发 layout shift,快速 hover 时内容左右跳 6px,看起来错位。
   视觉反馈现在靠 3 个静态元素:
   1. ::before 左侧色条 scaleY(0→1) 出现
   2. 背景 var(--bg-hover) 着色
   3. swatch 圆点 scale(1→1.15) 放大
   这三个组合的反馈强度已经足够,不需要 layout-shifting 的滑动。
   bar 固定在 left:4-7px,content 在 12px+,5px 间隙足够,不需要为它让位。 */
.theme-option:hover::before,
.theme-option:focus-visible::before {
    transform: scaleY(1);
    opacity: 1;
}
.theme-option:active {
    background: var(--bg-active);
    transform: scale(0.985);
}

/* 颜色圆点 — 用内联 style 注入真实 swatch,不受主题变量覆盖。
   双层 box-shadow ring 是必须的(不依赖 --ring-swatch 主题变量):
   6 个主题的 swatch 跨越深/浅/亮/暗(black/white/cyan/brown/blue/green),
   任意当前 popup 主题下都可能有"swatch 与 popup 背景对比不足"的问题
   (如 dark 黑 swatch 在 dark popup 看不见、light 白 swatch 在 light popup 看不见)。
   固定双 ring(外白 + 内黑)在任何主题 popup 下都给 swatch 一个清晰边界。 */
.theme-option-swatch {
    display: inline-block;
    width: 16px;
    height: 16px;
    border-radius: 50%;
    box-shadow:
        0 0 0 1px rgba(255, 255, 255, 0.55),   /* 外白边:深色 popup 下区分深色 swatch */
        0 0 0 2px rgba(0, 0, 0, 0.30),         /* 内黑边:浅色 popup 下区分浅色 swatch */
        0 1px 2px rgba(0, 0, 0, 0.20);         /* 软阴影:立体感 */
    flex-shrink: 0;
    transition: transform var(--t-base) var(--ease);
}
.theme-option:hover .theme-option-swatch {
    transform: scale(1.15);
}

.theme-option-label {
    font-weight: var(--fw-medium);
    /* v74:"Dark 深色" 这类 名称+中文 标签在 ≤340 视口曾被折成两行
       ("Dark 深 / 色"),6 个标签都是固定短串,直接 nowrap 更安全。 */
    white-space: nowrap;
    /* v42:letter-spacing 0.02em → var(--tracking-tag) token 化 */
    letter-spacing: var(--tracking-tag);
    transition: color var(--t-base) var(--ease);
}

/* label + desc 纵向堆叠 — 让 desc 在主题名下方一行小字辅助说明 */
.theme-option-text {
    display: inline-flex;
    flex-direction: column;
    align-items: flex-start;
    min-width: 0;
    /* grid 1fr 列里要 min-width:0 才能让 flex 子项正确截断 */
    gap: 2px;
}
.theme-option-desc {
    /* v37:font-size 11px → var(--fs-sm) token 化;line-height 1.3 → var(--lh-meta) */
    font-size: var(--fs-sm);
    color: var(--text-mute);
    /* v42:letter-spacing 0.02em → var(--tracking-tag) token 化 */
    letter-spacing: var(--tracking-tag);
    line-height: var(--lh-meta);
    transition: color var(--t-base) var(--ease);
    /* 长描述也允许截断,但 6 个主题的 desc 都是 5-7 汉字,通常不会触发 */
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    max-width: 100%;
}

.theme-option-en {
    /* v37:font-size 11px → var(--fs-sm) token 化 */
    font-size: var(--fs-sm);
    color: var(--text-mute);
    /* v42:硬编码 mono 栈 → var(--mono) token 化,与全局一致 */
    font-family: var(--mono);
    /* v42:letter-spacing 0.04em → var(--tracking-en) token 化 */
    letter-spacing: var(--tracking-en);
    transition: color var(--t-base) var(--ease);
}

/* 选中态时 desc 跟随主色但降透明度,与 en 一致 */
.theme-option.active .theme-option-desc {
    color: var(--accent);
    opacity: 0.7;
}

/* 选中标记 — 默认隐藏,active 时显示并打勾色。
   颜色用 --theme-accent(active 项本身 = 当前主题时,三者一致:swatch / 色条 / check 都同一色)。
   故意保留 cubic-bezier(.2, .8, .3, 1.3) overshoot spring 曲线(token --ease 没有 1.3 overshoot),
   让 ✓ 弹一下更有"打勾"的反馈感。 */
.theme-option-check {
    display: inline-flex;
    width: 16px;
    height: 16px;
    color: var(--theme-accent, var(--accent));
    opacity: 0;
    transform: scale(0.6);
    transition: opacity var(--t-base) var(--ease),
                transform .22s cubic-bezier(.2, .8, .3, 1.3);
}
.theme-option-check svg {
    width: 100%;
    height: 100%;
}
.theme-option.active .theme-option-check {
    opacity: 1;
    transform: scale(1);
}

/* 选中态:v33 起 hover 不再预览主题,active 必须常驻可视。
   三重视觉锚点让"当前主题"在 6 个选项中一眼可见:
   1. 常驻淡背景 var(--bg-hover) — 与未选中形成背景 vs 无背景的对比
   2. 左侧色条常驻(::before scaleY(1),色用 --theme-accent = 该主题真实色,
      active 项 swatch / 色条 / check 三者同色,锚点最强)
   3. swatch 保持放大 scale(1.15) — 与 hover 的 swatch 缩放一致
   文字/en 仍走 var(--accent) 提示"这是选中" */
.theme-option.active {
    background: var(--bg-hover);
    color: var(--accent);
}
.theme-option.active::before {
    transform: scaleY(1);
    opacity: 1;
}
.theme-option.active .theme-option-swatch {
    transform: scale(1.15);
}
.theme-option.active .theme-option-en {
    color: var(--accent);
    opacity: 0.7;
}
/* active 上 hover/focus 时再深一档 — 区别于普通 hover 的 var(--bg-hover) */
.theme-option.active:hover,
.theme-option.active:focus-visible {
    background: var(--bg-active);
}


/* ============== 全局切换过渡 (仅在切换那一瞬) ============== */

/* 平时不生效;theme.js 在切换时给 body 加 .theme-transitioning,
   320ms 后移除 — 只在切换那一瞬过渡,平时无开销。

   P0 性能修复:旧版 transition background/fill/stroke 给 1547+ 个元素装 7 个 transition clock,
   切主题时 280ms 内反复触发 style invalidation + 全树重绘。改为:
   - 只 transition 实际可平滑过渡的 color/background-color/border-color/box-shadow/opacity
   - 移除 `background` shorthand(它会强制解析 background-image,渐变无法过渡都是浪费)
   - 移除 `fill`/`stroke`(只影响 SVG,装在所有元素上 99% 没用)
   - 移除 `*::before/*::after`(伪元素没必要一起过渡)
   - 移除 `!important`(让已有 transition 的元素保留自己的,不再被强制覆盖)
   注:用背景的容器(主题菜单 popup 等)自己有局部 transition,不需要 body 级兜底。 */
body.theme-transitioning,
body.theme-transitioning * {
    transition:
        background-color 280ms ease,
        color 280ms ease,
        border-color 280ms ease,
        box-shadow 280ms ease,
        opacity 280ms ease,
        /* 聚焦元素 :focus-visible { outline: 2px solid var(--accent) } —
           主题切换时让 outline 颜色平滑过渡,而不是与 accent 一起跳变 */
        outline-color 280ms ease;
}


/* v32+:desktop 已统一为右对齐(见 .app .theme-popup),不再需要 ≤720 单独改一次。
   ≤720 移动端 popup 全宽铺开,desc 隐藏保持紧凑。
   v60+:max-width: 640 → 720 — 与项目其余 4 个 CSS 文件断点统一(app.css/favorites.css/
   smusic.css/smusic.enhance.css 全部用 720);641-720 视口下主题弹窗原本按桌面渲染,
   抽屉/侧栏已切移动端,弹层布局与其他模块不同步。 */
@media (max-width: 720px) {
    .theme-popup {
        min-width: 200px;
        max-width: calc(100vw - 32px);
        right: 8px;
    }
    .theme-trigger-label {
        /* v37:font-size 12px → var(--fs-base) token 化 */
        font-size: var(--fs-base);
    }
    /* 移动端隐藏描述行,popup 保持紧凑;色卡圆点 + 中文名已能区分 */
    .theme-option-desc {
        display: none;
    }
    /* 隐藏 desc 后,label 不再需要独占一行,取消 .theme-option-text 的纵向堆叠 */
    .theme-option-text {
        display: inline;
    }
    /* v60+:header padding 桌面/移动已统一为 4/6,这里不再覆盖。 */
}

/* 小屏手机:popup 占满右半屏 */
@media (max-width: 480px) {
    .theme-popup {
        min-width: 180px;
        max-width: calc(100vw - 24px);
    }
    .theme-option {
        padding: 10px 12px;
        /* v42:font-size 14px → var(--fs-lg) token 化 */
        font-size: var(--fs-lg);
        /* v74:隐藏英文 chip 后栅格从 4 列减到 3 列(色点 | 标签 | 勾选),
           与下方 .theme-option-en display:none 同步。 */
        grid-template-columns: 18px 1fr 16px;
    }
    .theme-option-en {
        /* v37:font-size 11px → var(--fs-sm) token 化 */
        font-size: var(--fs-sm);
        /* v74:≤480 弹窗宽只有 180-296px,"Amber 琥珀" + nowrap 标签与
           右侧 monospace chip 在 320 视口直接重叠("Amber 琥珀mber")。
           移动端靠 色点 + 中文名 + 勾选 已足够区分 6 主题,en chip 是
           冗余信息,窄屏隐藏(桌面端保留,chip 兼作 localStorage 值提示)。 */
        display: none;
    }
}

/* 触摸设备:去掉 popup 入场动画(避免抖动) */
@media (hover: none) {
    .theme-popup {
        animation: none;
    }
    .app .theme-popup {
        animation: none;
    }

    /* v18+:主题触发按钮(视觉 34px)触摸区扩到 ≥50。
       inset -8 让视觉 34 + 16 = 50,达到 iOS HIG 44 并留余量。 */
    .theme-trigger {
        position: relative;
    }
    .theme-trigger::before {
        content: "";
        position: absolute;
        inset: -8px;
        /* v29 round 4+: 12px → var(--r-lg) */
        border-radius: var(--r-lg);
    }

    /* v18+:主题选项(visual padding 9+12 → 33-36px)触摸区扩到 ≥42。
       注意:.theme-option::before 已被主题原 css 占用(hover 滑入色条),
       这里改用 ::after 扩展触摸区,不与 ::before 冲突。
       v27+:-4 → -7,默认视口(主题弹窗 33-36px)触摸 49-50px,达标 iOS HIG 44。 */
    .theme-option {
        position: relative;
    }
    .theme-option::after {
        content: "";
        position: absolute;
        inset: -7px;
        border-radius: 9px;
    }
}

/* v71+: *:active 按压瞬时反馈规则统一在 app.css 定义(含 no-preference 门控),
   本文件此前的重复块已移除 — 5 份相同规则纯冗余,且注释里的级联说明有误。 */

/* 用户偏好减少动画 */
@media (prefers-reduced-motion: reduce) {
    *, *::before, *::after {
        transition-duration: 0.01ms !important;
        animation-duration: 0.01ms !important;
        /* v29 round 4+: 与 app.css prefers-reduced-motion 块对齐,
           补 animation-iteration-count 兜底,避免未来有动画依赖
           iteration-count 而非 duration 时被遗漏 */
        animation-iteration-count: 1 !important;
    }
    /* body.theme-transitioning 的 transition: 简写在 cascade 中
       后置定义,会清空 longhand transition-duration — 需显式置零 */
    body.theme-transitioning,
    body.theme-transitioning *,
    body.theme-transitioning *::before,
    body.theme-transitioning *::after {
        transition: none !important;
    }
}
