/* ============================================================================
 * depth3d.css — 「暖器 · 立体」组件层
 * ----------------------------------------------------------------------------
 * 在 tokens.css 之后加载，覆盖四个页面的外壳风格：
 *   1) 立体机制：透视倾斜（.dz-tilt）+ 指针光泽（.dz-glare）
 *   2) 体积感：接触阴影 + 环境阴影 + 顶部高光 + 内凹阴影
 *   3) 统一：导航 / 按钮 / 卡片 / 表单 / 徽章 / 表格
 *
 * 铁律（来自 DESIGN.md）：
 *   · 层次优先用「底色明度差 → 1px 发丝边 → 极淡阴影」，不用粗边框与硬阴影
 *   · 单一强调色，出现面积 ≤ 10%
 *   · 只动 transform 与 opacity，且保留 prefers-reduced-motion 降级
 * ========================================================================== */

/* ============================================================================
 * 0′. 无 JS 兜底（重要）
 * ----------------------------------------------------------------------------
 * `.reveal { opacity: 0 }` 靠 JS 观察器加 `.visible` 才显示 ——
 * 一旦脚本被禁用、被扩展拦截，或某个脚本在旧浏览器上抛错，整段内容会**永远看不见**。
 * 改成渐进增强：只有 <html class="js">（由 head 里的脚本标记）时才隐藏。
 * ========================================================================== */
html:not(.js) .reveal { opacity: 1 !important; transform: none !important; }
/* 保险丝：脚本层面确认"观察器确实没生效"时挂上这个类，内容一律显示 */
html.no-reveal .reveal { opacity: 1 !important; transform: none !important; }
/* ==========================================================================
   0. 基础：字体、氛围光、选区、滚动条、焦点环
   ========================================================================== */

/* 滚动条位置**永久预留**。
   ----------------------------------------------------------------------------
   这是"整页横向位移"这一类闪烁的总根因，实测数据：
     不预留：锁滚动前内容宽 912 → 锁定时 922（被撑开一整条滚动条）→ 解锁后又缩回 912
     预留后：912 → 912 → 912，全程纹丝不动
   受影响的场景有两个：
     ① 相册灯箱开/关时的滚动锁 —— 整页（含模糊光斑、玻璃导航）跟着重排重绘一次；
     ② 短页面 ↔ 长页面之间跳转（相册只有一张图，没有滚动条；首页很长，有滚动条）
        —— 同样是"整页横移一档"，这就是"从相册返回主页会乱闪"的来源。
   预留之后两种情况都不会再位移，跨页之间也保持一致。
   不支持该属性的浏览器（老 Safari）用的是浮层滚动条，本来就不会位移，无副作用。 */
html {
  /* overflow-y: scroll 是必须的：Chromium 只在"滚动条可能出现"时才兑现 scrollbar-gutter，
     实测短页面（相册只有一张图、offline 页）若只写 gutter，占位仍是 0，
     于是在"短页面 ↔ 长页面"之间跳转时整页会横移一档。
     配上 scrollbar-gutter 之后全站占位恒为一条滚动条宽度，跨页零位移。
     长页面本来就有滚动条（观感不变）；短页面会多出一条不可用的滚动条轨道。
     移动端是浮层滚动条，此规则无可见影响。 */
  overflow-y: scroll;
  scrollbar-gutter: stable;
}

/* ============================================================================
   触摸设备：全站关闭毛玻璃（backdrop-filter）
   ----------------------------------------------------------------------------
   这不是审美取舍，是**修闪烁**：
     · backdrop-filter 是一层"实时重采样"的合成层，背后内容一变就要重新模糊；
     · 相册灯箱全屏淡入、首页进场动画叠加在它上面时，安卓 GPU 上会出现明显的闪烁/重绘异常；
     · 实测（线上 v32，手机视口）：相册页滚动后导航胶囊 .nav-inner 仍带 blur(14px)
       —— 旧那份"逐个列元素"的名单漏了它（以及 mbti 卡片、admin 头部、游戏工具栏、首页小标签）；
     · 微信内置浏览器用的是老内核，**根本不支持 backdrop-filter**，所以从来不闪 ——
       这正是"微信不闪、Edge 闪"的另一半原因。
   用通配符而不是继续补名单：这类漏网以后不会再发生。
   可读性由各元素自身的半透明底 + site.css 里那几条 hover:none 加深规则保证；
   首页还有 @supports not (backdrop-filter) 的兜底配色，观感与"浏览器不支持毛玻璃"时一致。
   ========================================================================== */
/* 判据只用 (hover: none) —— 与全站其它触摸降级规则保持一致。
   不要加 (pointer: coarse)：无头/无指针环境会把它判真，桌面端会被误伤（实测过）。 */
@media (hover: none) {
  *, *::before, *::after {
    backdrop-filter: none !important;
    -webkit-backdrop-filter: none !important;
  }
  /* 导航胶囊：关掉模糊后把底子加厚（只改背景色，胶囊自带的渐变与边框保留） */
  body > nav .nav-inner { background-color: rgba(20, 24, 34, .92); }
  :root[data-theme="light"] body > nav .nav-inner { background-color: rgba(255, 255, 255, .94); }
}

body {
  font-family: var(--w-font-sans);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

::selection { background: var(--w-accent); color: #fff; }

/* 焦点环必须用 outline，不能用 box-shadow：
   `:focus-visible` 只有 (0,1,0)，而几乎所有组件自己都声明了 box-shadow（卡片/按钮/输入框），
   结果是键盘用户**完全看不到焦点在哪**。outline 不会被 box-shadow 覆盖。 */
:focus-visible {
  outline: 2px solid color-mix(in srgb, var(--w-accent) 88%, transparent);
  outline-offset: 2px;
  border-radius: var(--w-r-sm);
}
/* 老浏览器不支持 :focus-visible 时，退回到 :focus（不影响鼠标点击——鼠标点击不匹配 :focus-visible） */
@supports not selector(:focus-visible) {
  a:focus, button:focus, input:focus, textarea:focus, select:focus, [tabindex]:focus {
    outline: 2px solid color-mix(in srgb, var(--w-accent) 88%, transparent);
    outline-offset: 2px;
  }
}

/* 细滚动条：只在需要滚动的容器里出现，不抢视觉 */
* { scrollbar-width: thin; scrollbar-color: color-mix(in srgb, var(--w-ink) 22%, transparent) transparent; }
*::-webkit-scrollbar { width: 8px; height: 8px; }
*::-webkit-scrollbar-track { background: transparent; }
*::-webkit-scrollbar-thumb {
  background: color-mix(in srgb, var(--w-ink) 18%, transparent);
  border-radius: 999px; border: 2px solid transparent; background-clip: content-box;
}
*::-webkit-scrollbar-thumb:hover { background: color-mix(in srgb, var(--w-ink) 30%, transparent); background-clip: content-box; }

/* 等宽只用于元信息：编号 / 计数 / 时间戳 / 房间号 / IP */
.nav-time, .item-no, .room-id span, .detail-meta, .ip-addr, .stat-num,
.p-cards, .multiplier, .quiz-count, .dim-nums, .auth-status {
  font-family: var(--w-font-mono);
  font-variant-numeric: tabular-nums;
  letter-spacing: .01em;
}

/* ==========================================================================
   1. 立体机制
   --------------------------------------------------------------------------
   JS 给目标加 .dz-tilt / .dz-glare，并写入 4 个变量：
     --rx / --ry  指针倾斜角     --mx / --my  光泽位置
   离开时 JS 移除 .is-live，transform 用长缓动回位（"落回桌面"）
   ========================================================================== */

/* 说明：**倾斜的 transform 由 JS 直接写内联样式**（见 depth3d.js 的 apply()），
   这里只负责过渡与提示。
   早先的写法是 CSS 读 `--rx/--ry` 自己算 transform，但 `.dz-tilt:hover` 的特异度只有
   (0,2,0)，会被各页原有的 `.item:hover{transform:translateY(-3px)}`、`.stat-card:hover`
   之类顶掉 —— 表现为"JS 还在每帧算角度，元素纹丝不动"，既看不到效果又白烧 CPU。
   内联样式天然压过普通规则，同时顺带消掉了各页原有的悬停位移
   （位移正是命中盒抖动 / 边框闪烁的来源）。 */
.dz-tilt {
  transition:
    transform var(--dz-ease-out),
    box-shadow var(--dz-ease-out),
    border-color var(--dz-ease),
    background-color var(--dz-ease);
  will-change: transform;
}

/* 指针按下期间：跟手要"紧"，缓动收到 90ms */
.dz-tilt.is-live {
  transition: transform 90ms linear, box-shadow var(--dz-ease), border-color var(--dz-ease);
}

/* 光泽：跟着指针走的镜面高光 */
.dz-glare { position: relative; }
.dz-glare::after {
  content: '';
  position: absolute; inset: 0; z-index: 3;
  border-radius: inherit;
  pointer-events: none;
  background: radial-gradient(
    420px circle at var(--mx, 50%) var(--my, -10%),
    var(--dz-glare) 0%,
    transparent 62%
  );
  opacity: 0;
  transition: opacity var(--w-dur-2) var(--w-ease);
}
.dz-glare:hover::after,
.dz-glare.is-live::after { opacity: 1; }

/* ==========================================================================
   2. 顶部导航（全站唯一的半透明模糊元素）
   ========================================================================== */

body > nav {
  border-bottom: 1px solid var(--w-hair);
  box-shadow: var(--w-bevel-soft), var(--w-e1);
  transition: box-shadow var(--w-dur-2) var(--w-ease), background-color var(--w-dur-2) var(--w-ease);
}
body > nav.is-scrolled {
  box-shadow: var(--w-bevel-soft), var(--w-e2);
}
/* 导航右侧那一组（时间 / 主题按钮 / 链接）：MBTI 原本没有这个容器样式，
   加上主题按钮后需要它，统一在这里定义。 */
.nav-right { display: flex; align-items: center; gap: 12px; }

/* 首页导航：品牌 + 标语 + 时间 + 主题按钮 */
html[data-page="home"] body > nav {
  background: var(--nav-bg);
  backdrop-filter: blur(var(--blur)) saturate(160%);
  -webkit-backdrop-filter: blur(var(--blur)) saturate(160%);
}
html[data-page="home"] .brand { letter-spacing: -.01em; }
html[data-page="home"] .nav-links a {
  position: relative;
  padding-bottom: 3px;
}
html[data-page="home"] .nav-links a::after {
  content: ''; position: absolute; left: 0; right: 0; bottom: calc(50% - 10px); height: 1.5px;
  background: var(--w-accent); border-radius: 2px;
  transform: scaleX(0); transform-origin: left;
  transition: transform var(--w-dur-2) var(--w-ease-out);
}
html[data-page="home"] .nav-links a:hover::after { transform: scaleX(1); }

/* 主题按钮做成"自包含"样式：MBTI 那页的全局样式里没有 .theme-btn，
   只靠继承会变成方按钮。
   --------------------------------------------------------------------------
   ⚠ 必须用 **ID 选择器**，不能写 `.theme-btn`：
   游戏页的主题皮肤按钮是 `class="speed-btn theme-btn"`（经典/海洋/新年/紫罗兰），
   用类选择器会把它们一起压成 44×44 的圆按钮，文字直接折成竖条（实测踩过）。 */
#theme-btn,
#btn-theme {
  width: 44px; height: 44px;
  border-radius: 50%;
  display: grid; place-items: center;
  font-size: 16px; line-height: 1; cursor: pointer;
  background: var(--glass-bg);
  color: var(--w-ink);
  border: 1px solid var(--w-hair);
  box-shadow: var(--w-bevel), var(--w-e1);
  transition: transform var(--w-dur-1) var(--w-ease), box-shadow var(--w-dur-2) var(--w-ease), background-color var(--w-dur-1) var(--w-ease);
}
#theme-btn:hover, #btn-theme:hover { transform: translateY(-1px); box-shadow: var(--w-bevel), var(--w-e2); }
#theme-btn:active, #btn-theme:active { transform: translateY(1px) scale(.96); box-shadow: var(--w-bevel-soft), var(--w-e1); }

/* 主题按钮里的图标：内联 SVG + currentColor，深浅两色自动跟随。
   为什么不用 ☀️/🌙：那是**彩色 emoji**，会在一套受控色板（暖中性 + 单一强调色）里
   蹦出橙黄/亮黄色块，看起来就是"按钮颜色错了"。
   两个图标都写在按钮里，由 :root[data-theme] 决定显示哪个 —— JS 不用碰 innerHTML。 */
#theme-btn svg,
#btn-theme svg { width: 18px; height: 18px; display: block; }
#theme-btn .ic-sun,
#btn-theme .ic-sun { display: none; }
:root[data-theme="dark"] #theme-btn .ic-sun,
:root[data-theme="dark"] #btn-theme .ic-sun { display: block; }
:root[data-theme="dark"] #theme-btn .ic-moon,
:root[data-theme="dark"] #btn-theme .ic-moon { display: none; }

/* 导航高度统一为 52px（DESIGN.md §7.5）：首页原本 62px、MBTI 58px，两页并排看会明显不齐 */
html[data-page="home"] .nav-inner,
html[data-page="mbti"] .nav-inner { height: 52px; }

/* ==========================================================================
   3. 按钮：三型 + 四态（默认 / hover / active / focus-visible）
   ========================================================================== */

/* 通用按压：沉入表面（阴影收缩 + 轻微下移），比单纯 scale 更"实" */
.btn, button { -webkit-tap-highlight-color: transparent; }

html[data-page="home"] .btn,
html[data-page="admin"] .btn,
html[data-page="mbti"] .btn {
  border-radius: var(--w-r-pill);
  transition:
    transform var(--w-dur-1) var(--w-ease),
    box-shadow var(--w-dur-2) var(--w-ease),
    background-color var(--w-dur-1) var(--w-ease),
    border-color var(--w-dur-1) var(--w-ease),
    color var(--w-dur-1) var(--w-ease);
}

/* 首页：Hero 主按钮（实底强调色，每屏最多一个） */
html[data-page="home"] .hero-actions .btn:first-child {
  background: linear-gradient(180deg, var(--w-accent-hi) 0%, var(--w-accent) 100%);
  color: #fff;
  border: 1px solid color-mix(in srgb, var(--w-accent) 70%, #000 12%);
  box-shadow:
    var(--w-bevel),
    0 1px 2px rgba(28, 21, 16, .18),
    0 10px 22px -8px color-mix(in srgb, var(--w-accent) 60%, transparent);
  font-weight: 600;
}
html[data-page="home"] .hero-actions .btn:first-child:hover {
  box-shadow:
    var(--w-bevel),
    0 2px 4px rgba(28, 21, 16, .18),
    0 16px 30px -10px color-mix(in srgb, var(--w-accent) 70%, transparent);
}
html[data-page="home"] .hero-actions .btn:first-child:active {
  transform: translateY(1px) scale(.985);
  box-shadow: var(--w-bevel-soft), 0 1px 2px rgba(28, 21, 16, .2);
}

/* 首页：次按钮（淡底 + 强调色文字） */
html[data-page="home"] .hero-actions .btn:not(:first-child) {
  background: var(--w-accent-wash);
  color: var(--w-accent-tx);
  border: 1px solid color-mix(in srgb, var(--w-accent) 26%, transparent);
  box-shadow: var(--w-bevel-soft), var(--w-e1);
}
html[data-page="home"] .hero-actions .btn:not(:first-child):hover {
  background: color-mix(in srgb, var(--w-accent) 16%, transparent);
  box-shadow: var(--w-bevel-soft), var(--w-e2);
}

/* 通用主按钮：首页表单按钮 / 后台主按钮 */
html[data-page="home"] .treehole-form button,
html[data-page="admin"] .btn-primary,
html[data-page="mbti"] .btn {
  background: linear-gradient(180deg, var(--w-accent-hi) 0%, var(--w-accent) 100%);
  color: #fff;
  border: 1px solid color-mix(in srgb, var(--w-accent) 70%, #000 10%);
  box-shadow:
    var(--w-bevel),
    0 1px 2px rgba(28, 21, 16, .16),
    0 8px 18px -8px color-mix(in srgb, var(--w-accent) 58%, transparent);
}
html[data-page="home"] .treehole-form button:hover,
html[data-page="admin"] .btn-primary:hover,
html[data-page="mbti"] .btn:hover {
  filter: none;
  box-shadow:
    var(--w-bevel),
    0 2px 4px rgba(28, 21, 16, .16),
    0 14px 26px -10px color-mix(in srgb, var(--w-accent) 66%, transparent);
}
html[data-page="admin"] .btn:active,
html[data-page="mbti"] .btn:active,
html[data-page="home"] .treehole-form button:active {
  transform: translateY(1px) scale(.985);
  box-shadow: var(--w-bevel-soft), 0 1px 2px rgba(28, 21, 16, .18);
}

/* 次按钮 / 幽灵按钮 / 描边按钮：淡强调底，不用渐变 */
html[data-page="admin"] .btn-outline {
  background: var(--w-accent-wash);
  color: var(--w-accent-tx);
  border: 1px solid color-mix(in srgb, var(--w-accent) 28%, transparent);
  box-shadow: var(--w-bevel-soft), var(--w-e1);
}
html[data-page="admin"] .btn-outline:hover {
  background: color-mix(in srgb, var(--w-accent) 18%, transparent);
  transform: translateY(-1px);
}
html[data-page="admin"] .btn-ghost {
  background: transparent;
  border: 1px solid var(--w-hair);
  color: var(--w-muted);
  box-shadow: none;
}
html[data-page="admin"] .btn-ghost:hover { color: var(--w-ink); background: var(--w-surface-2); }
html[data-page="admin"] .btn-danger { border-color: color-mix(in srgb, var(--w-danger) 40%, transparent); box-shadow: none; }

html[data-page="mbti"] .btn.ghost {
  background: rgba(245, 242, 238, .05);
  color: var(--w-ink);
  border: 1px solid var(--w-hair);
  box-shadow: var(--w-bevel-soft), var(--w-e1);
}
html[data-page="mbti"] .btn.ghost:hover { background: rgba(245, 242, 238, .09); box-shadow: var(--w-bevel-soft), var(--w-e2); }

/* 文字按钮：无底无框 */
.btn-text, .treehole-del, .treehole-reply-btn, .reply-item .reply-actions button {
  border-radius: var(--w-r-sm);
  transition: color var(--w-dur-1) var(--w-ease), background-color var(--w-dur-1) var(--w-ease);
}

/* ==========================================================================
   3′. 悬停一律不位移（命中盒稳定）
   --------------------------------------------------------------------------
   这一条是"边框抽搐"的根治：任何 `:hover{transform:translateY(..)}` 都会让元素的
   命中盒跟着动，鼠标贴边时 hover 反复进出 → 边框颜色/阴影高频翻转。
   停掉位移，抬起感交给"阴影加深 + 边框亮起 + 光泽跟随"。
   （`:active` 的按压反馈保留 —— 那时指针已经按住，不存在反复横跳。）
   ========================================================================== */

/* 注意 `:not(:active)`：不加它，这几条（位置更靠后）会顶掉各页的 `:active` 按压反馈，
   按钮就"按不下去了"。
   `:not(.btn-hero-*)`：首屏两个按钮的位移由磁吸（--mg-*，写在 home-flagship.css）负责，
   这里不能把它们按住。
   倾斜卡片（.stat-card / .rec-item / .item / .social …）**不在这个名单里** ——
   它们的 transform 由 JS 内联控制，不需要也不应该被这里覆盖。 */
html[data-page] #theme-btn:hover:not(:active),
html[data-page] #btn-theme:hover:not(:active),
html[data-page] .treehole-more:hover:not(:active),
html[data-page] .opt:hover:not(:active),
html[data-page] .rank-row:hover:not(:active),
html[data-page] .btn-outline:hover:not(:active),
html[data-page] .btn:hover:not(:active):not(.btn-hero-primary):not(.btn-hero-ghost),
html[data-page] .btn-primary:hover:not(:active):not(.btn-hero-primary),
html[data-page] .treehole-form button:hover:not(:active),
html[data-page="admin"] .tab:hover:not(:active),
html[data-page="game"] .btn-big:hover:not(:active),
html[data-page="game"] .btn-mid:hover:not(:active),
html[data-page="game"] .btn-act:hover:not(:active),
html[data-page="game"] .btn-bid:hover:not(:active),
html[data-page="game"] .btn-util:hover:not(:active),
html[data-page="game"] .btn-sound:hover:not(:active),
html[data-page="game"] .profile-chip:hover:not(:active) {
  transform: none;
}

/* 悬停/倾斜态的"抬起感"：只加深阴影，不动几何 */
.dz-tilt.is-live {
  box-shadow: var(--w-bevel-soft), var(--w-e3);
}

/* ==========================================================================
   3″. 主题切换
   --------------------------------------------------------------------------
   点右上角切白天/夜间时，颜色是整页一起变的。
   以前的做法是给 `html.theme-switching *` 挂一组颜色过渡 —— 但那是**整篇文档每个元素**
   同时动画（首页 500+ 个元素 × 7 个属性，含 opacity），桌面 Chrome 勉强撑住，
   微信 X5 内核压不住：元素各画各的、分层重绘，就是用户说的"切主题乱闪"。
   现在改成一层幕布（见本文件第 18 节 .theme-curtain），这里不再需要任何逐元素过渡。
   ========================================================================== */

/* ==========================================================================
   4. 表单：内凹（sunken）+ 聚焦环
   ========================================================================== */

html[data-page="home"] .treehole-form input,
html[data-page="home"] .treehole-form textarea,
html[data-page="home"] .reply-form input,
html[data-page="admin"] .login-card input,
html[data-page="admin"] .input,
html[data-page="mbti"] .login-card input,
html[data-page="game"] input[type="text"],
html[data-page="game"] #nickname-input,
html[data-page="game"] .join-row input {
  background: var(--w-sunken);
  border: 1px solid var(--w-hair);
  border-radius: var(--w-r-sm);
  color: var(--w-ink);
  box-shadow: var(--w-inset);
  transition: border-color var(--w-dur-1) var(--w-ease), box-shadow var(--w-dur-1) var(--w-ease), background-color var(--w-dur-1) var(--w-ease);
}
html[data-page="home"] .treehole-form input::placeholder,
html[data-page="home"] .treehole-form textarea::placeholder,
html[data-page="home"] .reply-form input::placeholder,
html[data-page="admin"] .input::placeholder,
html[data-page="admin"] .login-card input::placeholder { color: var(--w-faint); }

html[data-page="home"] .treehole-form input:focus,
html[data-page="home"] .treehole-form textarea:focus,
html[data-page="home"] .reply-form input:focus,
html[data-page="admin"] .login-card input:focus,
html[data-page="admin"] .input:focus {
  border-color: var(--w-accent);
  box-shadow: var(--w-inset), var(--w-ring);
  outline: none;
}

/* 树洞发布区：做成一块下沉的"工作台"，与卡片形成前后关系 */
html[data-page="home"] .treehole-form {
  background: color-mix(in srgb, var(--w-surface) 55%, transparent);
  border: 1px solid var(--w-hair);
  border-radius: var(--w-r-xl);
  box-shadow: var(--w-inset);
  padding: 22px 24px;
}

/* ==========================================================================
   5. 立体卡片基类
   ========================================================================== */

html[data-page="home"] .about-card,
html[data-page="home"] .item,
html[data-page="home"] .social {
  background: var(--glass-bg);
  border: 1px solid var(--w-hair);
  border-radius: var(--w-r-xl);
  box-shadow: var(--w-bevel-soft), var(--w-e2);
  backdrop-filter: blur(var(--blur)) saturate(140%);
  -webkit-backdrop-filter: blur(var(--blur)) saturate(140%);
}
html[data-page="home"] .about-card { padding: 36px 34px; }
/* 悬停/倾斜态视觉由 JS 的 .is-live 驱动（带 140ms 迟滞）：
   浏览器自己的 :hover 在倾斜边缘会抖动，视觉不能跟着它走 */
html[data-page="home"] .about-card:hover,
html[data-page="home"] .about-card.is-live { box-shadow: var(--w-bevel-soft), var(--w-e3); }

/* 作品卡：关掉原来的上下浮动循环动画 —— 那种"一直在动"的卡片会显廉价，
     换成指针驱动的透视倾斜（更贵、更克制） */
html[data-page="home"] .item:hover { animation: none; background: var(--card-hover); border-color: var(--w-hair); }
html[data-page="home"] .item:hover,
html[data-page="home"] .item.is-live,
html[data-page="home"] .social:hover,
html[data-page="home"] .social.is-live { box-shadow: var(--w-bevel), var(--w-e3); }
html[data-page="home"] .item-no {
  color: var(--w-accent);
  font-weight: 600;
  opacity: .9;
}
html[data-page="home"] .item-tag {
  background: var(--w-accent-wash);
  color: var(--w-accent-tx);
  border: 1px solid color-mix(in srgb, var(--w-accent) 24%, transparent);
  box-shadow: var(--w-bevel-soft);
}
html[data-page="home"] .item.dim { opacity: .5; }

html[data-page="home"] .social-icon {
  background: linear-gradient(180deg, color-mix(in srgb, var(--w-surface) 92%, transparent), var(--w-surface-2));
  border: 1px solid var(--w-hair);
  border-radius: var(--w-r-md);
  box-shadow: var(--w-bevel), var(--w-e2);
  color: var(--w-ink);
}

/* 树洞留言卡 */
html[data-page="home"] .treehole-item {
  background: var(--glass-bg);
  border: 1px solid var(--w-hair);
  border-radius: var(--w-r-lg);
  box-shadow: var(--w-bevel-soft), var(--w-e2);
  backdrop-filter: blur(var(--blur)) saturate(140%);
  -webkit-backdrop-filter: blur(var(--blur)) saturate(140%);
  transition: box-shadow var(--w-dur-2) var(--w-ease), border-color var(--w-dur-2) var(--w-ease), background-color var(--w-dur-2) var(--w-ease);
}
html[data-page="home"] .treehole-item:hover,
html[data-page="home"] .treehole-item.is-live { box-shadow: var(--w-bevel-soft), var(--w-e3); }
/* 展开态：左侧强调色竖线，不改变任何尺寸（避免重排跳动） */
html[data-page="home"] .treehole-item.active {
  border-color: color-mix(in srgb, var(--w-accent) 45%, transparent);
  box-shadow: var(--w-bevel-soft), var(--w-e3), inset 3px 0 0 var(--w-accent);
}
html[data-page="home"] .treehole-more {
  border-radius: var(--w-r-pill);
  border: 1px solid var(--w-hair);
  background: color-mix(in srgb, var(--w-surface) 70%, transparent);
  box-shadow: var(--w-bevel), var(--w-e1);
  transition: transform var(--w-dur-1) var(--w-ease), box-shadow var(--w-dur-2) var(--w-ease);
}
html[data-page="home"] .treehole-more:hover { transform: translateY(-1px); box-shadow: var(--w-bevel), var(--w-e2); }
html[data-page="home"] .reply-form button {
  background: linear-gradient(180deg, var(--w-accent-hi), var(--w-accent));
  border-radius: var(--w-r-sm);
  box-shadow: var(--w-bevel), var(--w-e1);
}
html[data-page="home"] footer {
  border-top: 1px solid var(--w-hair);
  color: var(--w-faint);
}

/* ==========================================================================
   6. 首页：氛围光（暖光晕 + 细网格，来自 release/PHILOSOPHY.md）
   ========================================================================== */

html[data-page="home"] .bg-blobs .b1 { background: radial-gradient(circle, var(--w-amb-1), transparent 68%); }
html[data-page="home"] .bg-blobs .b2 { background: radial-gradient(circle, var(--w-amb-2), transparent 68%); }
html[data-page="home"] .bg-blobs .b3 { background: radial-gradient(circle, var(--w-amb-3), transparent 70%); }
html[data-page="home"] .bg-blobs i { filter: blur(60px); }
/* 多层视差：三团光斑位移速率不同 —— 眼睛读到的就是"前后两个平面"
   用 translate 属性而非 transform，避免和主题切换的过渡互相打断 */
html[data-page="home"] .bg-blobs .b1 { translate: 0 calc(var(--dz-scroll, 0) * -0.035px); }
html[data-page="home"] .bg-blobs .b2 { translate: 0 calc(var(--dz-scroll, 0) * -0.085px); }
html[data-page="home"] .bg-blobs .b3 { translate: 0 calc(var(--dz-scroll, 0) * -0.058px); }

/* 细网格：向下淡出，像工程图纸而不是壁纸 */
html[data-page="home"] .bg-blobs::after {
  content: '';
  position: absolute; inset: 0;
  background-image:
    linear-gradient(var(--w-grid) 1px, transparent 1px),
    linear-gradient(90deg, var(--w-grid) 1px, transparent 1px);
  background-size: 64px 64px;
  -webkit-mask-image: radial-gradient(120% 78% at 50% 0%, #000 12%, transparent 72%);
  mask-image: radial-gradient(120% 78% at 50% 0%, #000 12%, transparent 72%);
}
/* 顶部一道柔光：给页面一个"光源方向"，立体阴影才讲得通 */
html[data-page="home"] body::before {
  content: '';
  position: fixed; inset: 0; z-index: -1; pointer-events: none;
  background: radial-gradient(120% 60% at 50% -10%, color-mix(in srgb, var(--w-accent) 7%, transparent), transparent 70%);
}

html[data-page="home"] #cursor-glow {
  background: radial-gradient(circle, var(--w-amb-1), var(--w-amb-2) 42%, transparent 70%);
  mix-blend-mode: screen;
}

/* 注意：首页首屏标题**由 home-flagship.css 负责**（.hero-title）。
   这里曾经有一条 `html[data-page="home"] .hero h1 { ... }`，
   它的特异度是 (0,2,2)，比旗舰层的 `.hero-title`(0,2,1) 更高 ——
   结果旗舰层的字号/字距/行高被静默顶掉（实测桌面端渲染 72px 而不是设计的 89.6px）。
   同元素跨文件抢规则是这类"改了没生效"的典型来源，所以这里不再重复声明。 */
html[data-page="home"] .sec-title { letter-spacing: -.028em; font-weight: 700; }
html[data-page="home"] .sec-tag { font-family: var(--w-font-mono); letter-spacing: .22em; font-size: 11px; opacity: .9; }
/* 只改纵向！用 `padding` 简写会把 `.wrap` 的 `padding: 0 24px` 一起清零
   （本条特异度 (0,1,2) 高于 `.wrap` 的 (0,1,0)）——
   实测 375px 手机上首页四个 section 的标题与卡片直接贴屏。 */
html[data-page="home"] section { padding-block: var(--w-sp-section); }
/* 区块节奏只靠留白与底色，不再叠加额外 margin（否则两段之间会出现双倍空隙） */
html[data-page="home"] #works,
html[data-page="home"] #treehole,
html[data-page="home"] #social { margin-top: 0; }
html[data-page="home"] .sec-head { margin-bottom: clamp(32px, 4vw, 52px); }

/* 作品卡内部：标题与描述各占一行（原先是 inline 的 span，会挤在同一行折断） */
html[data-page="home"] .item { gap: 18px; padding: 26px 28px; }
html[data-page="home"] .item-main { display: flex; flex-direction: column; gap: 4px; }
html[data-page="home"] .item-title { display: block; line-height: 1.35; }
html[data-page="home"] .item-desc { display: block; margin-top: 0; line-height: 1.5; }
html[data-page="home"] .social-icon { font-size: 24px; }

/* ==========================================================================
   7. MBTI 页
   ========================================================================== */

html[data-page="mbti"] body::before {
  background:
    radial-gradient(760px 460px at 12% -12%, var(--w-amb-1), transparent 62%),
    radial-gradient(760px 480px at 108% 4%, var(--w-amb-2), transparent 62%);
}
html[data-page="mbti"] body > nav {
  background: rgba(20, 17, 16, .72);
  backdrop-filter: blur(18px) saturate(150%);
  -webkit-backdrop-filter: blur(18px) saturate(150%);
}
html[data-page="mbti"] .brand b { background: var(--grad); -webkit-background-clip: text; background-clip: text; }

html[data-page="mbti"] .card {
  /* 上亮下暗的极淡渐变 = 受光面，比纯半透明色更"像一块材料" */
  background: linear-gradient(180deg, rgba(245, 242, 238, .068) 0%, rgba(245, 242, 238, .034) 100%);
  border: 1px solid var(--w-hair);
  border-radius: var(--w-r-xl);
  box-shadow: var(--w-bevel-soft), var(--w-e2);
  backdrop-filter: blur(14px) saturate(140%);
  -webkit-backdrop-filter: blur(14px) saturate(140%);
  transition: box-shadow var(--w-dur-2) var(--w-ease), border-color var(--w-dur-2) var(--w-ease);
}
html[data-page="mbti"] .card:hover,
html[data-page="mbti"] .card.is-live { box-shadow: var(--w-bevel-soft), var(--w-e3); }

/* 选项：可按压的实体板 */
html[data-page="mbti"] .opt {
  background: rgba(245, 242, 238, .04);
  border: 1px solid var(--w-hair);
  border-radius: var(--w-r-md);
  box-shadow: var(--w-bevel-soft), var(--w-e1);
  transition:
    transform var(--w-dur-1) var(--w-ease),
    box-shadow var(--w-dur-2) var(--w-ease),
    background-color var(--w-dur-1) var(--w-ease),
    border-color var(--w-dur-1) var(--w-ease);
}
html[data-page="mbti"] .opt:hover {
  background: rgba(245, 242, 238, .075);
  border-color: color-mix(in srgb, var(--w-accent) 45%, transparent);
  transform: translateY(-2px);
  box-shadow: var(--w-bevel), var(--w-e2);
}
html[data-page="mbti"] .opt:active { transform: translateY(1px) scale(.99); box-shadow: var(--w-bevel-soft), var(--w-e1); }
html[data-page="mbti"] .opt .k {
  background: var(--w-accent-wash);
  color: var(--w-accent-tx);
  box-shadow: var(--w-bevel-soft);
  font-family: var(--w-font-mono);
}

html[data-page="mbti"] .progress,
html[data-page="mbti"] .dim-bar {
  background: rgba(245, 242, 238, .09);
  box-shadow: var(--w-inset);
  border-radius: 999px;
}
html[data-page="mbti"] .progress i,
html[data-page="mbti"] .dim-bar .fill,
html[data-page="mbti"] .rec-detail .dim-bar .fill {
  background: linear-gradient(90deg, var(--w-accent), var(--w-accent-hi));
  box-shadow: 0 0 12px -2px color-mix(in srgb, var(--w-accent) 65%, transparent), var(--w-bevel);
}
html[data-page="mbti"] .dim-bar .mid,
html[data-page="mbti"] .rec-detail .dim-bar .mid { background: rgba(245, 242, 238, .38); }
html[data-page="mbti"] .result .type,
html[data-page="mbti"] .rec-type {
  background: linear-gradient(180deg, #ffd0b4, var(--w-accent));
  -webkit-background-clip: text; background-clip: text;
  text-shadow: 0 12px 40px color-mix(in srgb, var(--w-accent) 22%, transparent);
}
html[data-page="mbti"] .rec-item {
  background: rgba(245, 242, 238, .035);
  border: 1px solid var(--w-hair);
  border-radius: var(--w-r-md);
  box-shadow: var(--w-bevel-soft), var(--w-e1);
  transition: transform var(--w-dur-1) var(--w-ease), box-shadow var(--w-dur-2) var(--w-ease), background-color var(--w-dur-1) var(--w-ease);
}
html[data-page="mbti"] .rec-item:hover,
html[data-page="mbti"] .rec-item.is-live {
  background: rgba(245, 242, 238, .07);
  border-color: color-mix(in srgb, var(--w-accent) 40%, transparent);
  transform: translateY(-2px);
  box-shadow: var(--w-bevel), var(--w-e2);
}
html[data-page="mbti"] .rec-detail {
  background: color-mix(in srgb, var(--w-surface) 66%, transparent);
  border: 1px solid var(--w-hair);
  box-shadow: var(--w-bevel-soft), var(--w-e2);
}
html[data-page="mbti"] .res-extra .trait {
  background: var(--w-accent-wash);
  color: var(--w-accent-tx);
  border: 1px solid color-mix(in srgb, var(--w-accent) 28%, transparent);
  box-shadow: var(--w-bevel-soft);
}
html[data-page="mbti"] .res-extra .growth {
  background: color-mix(in srgb, var(--w-warn) 9%, transparent);
  border-left: 3px solid var(--w-warn);
  border-radius: var(--w-r-sm);
}
html[data-page="mbti"] .res-extra ul.plus li::before { background: var(--w-ok); box-shadow: 0 0 8px -2px var(--w-ok); }
html[data-page="mbti"] .res-extra ul.minus li::before { background: var(--w-danger); box-shadow: 0 0 8px -2px var(--w-danger); }
html[data-page="mbti"] .intro .ic { filter: drop-shadow(0 12px 22px color-mix(in srgb, var(--w-accent) 40%, transparent)); }

/* ==========================================================================
   7′. MBTI 浅色覆盖
   --------------------------------------------------------------------------
   上面这些规则里有一批"浅色半透明铺在深底上"写死的值（rgba(245,244,247,…)）——
   深色下是玻璃，浅色下会变成白糊糊。这里逐条翻过来。
   ========================================================================== */

:root[data-page="mbti"][data-theme="light"] body::before {
  background:
    radial-gradient(760px 460px at 12% -12%, rgba(255, 90, 31, .10), transparent 62%),
    radial-gradient(760px 480px at 108% 4%, rgba(124, 92, 255, .10), transparent 62%);
}
:root[data-page="mbti"][data-theme="light"] body > nav {
  background: rgba(251, 251, 253, .74);
  border-bottom-color: rgba(11, 11, 13, .08);
}
:root[data-page="mbti"][data-theme="light"] .card {
  background: linear-gradient(180deg, #ffffff 0%, #faf9fc 100%);
  border-color: rgba(11, 11, 13, .09);
  box-shadow: var(--w-bevel), var(--w-e2);
}
:root[data-page="mbti"][data-theme="light"] .brand b {
  background: linear-gradient(135deg, #ff5a1f, #c2471a);
  -webkit-background-clip: text; background-clip: text; color: transparent;
}
:root[data-page="mbti"][data-theme="light"] .intro .ic {
  filter: drop-shadow(0 12px 22px rgba(255, 90, 31, .28));
}
:root[data-page="mbti"][data-theme="light"] .opt {
  background: #ffffff;
  border-color: rgba(11, 11, 13, .10);
  color: var(--w-text);
  box-shadow: var(--w-bevel), var(--w-e1);
}
:root[data-page="mbti"][data-theme="light"] .opt:hover {
  background: #ffffff;
  border-color: rgba(255, 90, 31, .45);
  box-shadow: var(--w-bevel), var(--w-e2);
}
:root[data-page="mbti"][data-theme="light"] .opt .k {
  background: rgba(255, 90, 31, .10);
  color: #c2471a;
}
:root[data-page="mbti"][data-theme="light"] .progress,
:root[data-page="mbti"][data-theme="light"] .dim-bar {
  background: rgba(24, 18, 30, .08);
}
:root[data-page="mbti"][data-theme="light"] .dim-bar .mid,
:root[data-page="mbti"][data-theme="light"] .rec-detail .dim-bar .mid {
  background: rgba(24, 18, 30, .32);
}
:root[data-page="mbti"][data-theme="light"] .rec-item {
  background: #ffffff;
  border-color: rgba(11, 11, 13, .09);
  box-shadow: var(--w-bevel), var(--w-e1);
}
:root[data-page="mbti"][data-theme="light"] .rec-item:hover {
  background: #ffffff;
  border-color: rgba(255, 90, 31, .40);
}
:root[data-page="mbti"][data-theme="light"] .rec-detail {
  background: #ffffff;
  border-color: rgba(11, 11, 13, .09);
  box-shadow: var(--w-bevel), var(--w-e2);
}
:root[data-page="mbti"][data-theme="light"] .btn.ghost {
  background: rgba(11, 11, 13, .045);
  color: var(--w-ink);
  border-color: rgba(11, 11, 13, .10);
}
:root[data-page="mbti"][data-theme="light"] .btn.ghost:hover { background: rgba(11, 11, 13, .08); }
:root[data-page="mbti"][data-theme="light"] .res-extra .growth {
  background: rgba(201, 132, 35, .10);
  color: #6b5a3a;
}
:root[data-page="mbti"][data-theme="light"] .result .type,
:root[data-page="mbti"][data-theme="light"] .rec-type {
  background: linear-gradient(180deg, #ff9a5e, #c2471a);
  -webkit-background-clip: text; background-clip: text;
  text-shadow: none;
}

/* ==========================================================================
   8. GM 后台
   ========================================================================== */

html[data-page="admin"] .admin-header {
  border-bottom: 1px solid var(--w-hair);
  box-shadow: var(--w-bevel-soft), var(--w-e1);
  backdrop-filter: blur(18px) saturate(150%);
  -webkit-backdrop-filter: blur(18px) saturate(150%);
}
html[data-page="admin"] .admin-brand { color: var(--w-accent); font-weight: 700; letter-spacing: -.01em; }
html[data-page="admin"] .auth-status {
  border: 1px solid var(--w-hair);
  background: var(--w-surface-2);
  box-shadow: var(--w-inset);
}

html[data-page="admin"] .login-card,
html[data-page="admin"] .card {
  background: var(--w-surface);
  border: 1px solid var(--w-hair);
  border-radius: var(--w-r-xl);
  box-shadow: var(--w-bevel-soft), var(--w-e2);
  transition: box-shadow var(--w-dur-2) var(--w-ease), border-color var(--w-dur-2) var(--w-ease);
}
html[data-page="admin"] .card:hover { border-color: color-mix(in srgb, var(--w-accent) 20%, transparent); box-shadow: var(--w-bevel-soft), var(--w-e3); }
html[data-page="admin"] .card-head {
  border-bottom: 1px solid var(--w-hair);
  background: linear-gradient(180deg, color-mix(in srgb, var(--w-surface-2) 70%, transparent), transparent);
}
html[data-page="admin"] .card-head h3 { color: var(--w-ink); font-size: 15px; letter-spacing: -.01em; }
html[data-page="admin"] .login-card h2 { color: var(--w-ink); letter-spacing: -.02em; }

html[data-page="admin"] .tab {
  border: 1px solid transparent;
  border-radius: var(--w-r-pill);
  color: var(--w-muted);
  transition: transform var(--w-dur-1) var(--w-ease), background-color var(--w-dur-1) var(--w-ease), color var(--w-dur-1) var(--w-ease), box-shadow var(--w-dur-2) var(--w-ease);
}
html[data-page="admin"] .tab:hover { background: var(--w-surface-2); color: var(--w-ink); box-shadow: var(--w-bevel-soft), var(--w-e1); }
html[data-page="admin"] .tab.active {
  background: linear-gradient(180deg, var(--w-accent-hi), var(--w-accent));
  color: #fff;
  border-color: color-mix(in srgb, var(--w-accent) 70%, #000 10%);
  box-shadow: var(--w-bevel), 0 8px 18px -8px color-mix(in srgb, var(--w-accent) 60%, transparent);
}

html[data-page="admin"] .stat-card {
  background: linear-gradient(180deg, color-mix(in srgb, var(--w-surface-2) 60%, var(--w-surface)), var(--w-surface));
  border: 1px solid var(--w-hair);
  border-radius: var(--w-r-xl);
  box-shadow: var(--w-bevel-soft), var(--w-e1);
}
html[data-page="admin"] .stat-card:hover,
html[data-page="admin"] .stat-card.is-live { box-shadow: var(--w-bevel), var(--w-e3); border-color: color-mix(in srgb, var(--w-accent) 28%, transparent); }
html[data-page="admin"] .stat-card .stat-num { color: var(--w-accent); font-weight: 600; letter-spacing: -.02em; }
html[data-page="admin"] .stat-card .stat-label { color: var(--w-muted); }

/* 表格：发丝线 + 表头小号等宽大写标签 */
html[data-page="admin"] .data-table th {
  background: var(--w-surface-2);
  color: var(--w-muted);
  font-family: var(--w-font-mono);
  font-size: 11px;
  letter-spacing: .12em;
  text-transform: uppercase;
  font-weight: 500;
  border-bottom: 1px solid var(--w-hair);
  position: sticky; top: 0; z-index: 2;
}
html[data-page="admin"] .data-table th,
html[data-page="admin"] .data-table td { border-bottom: 1px solid var(--w-hair-soft); }
html[data-page="admin"] .data-table tbody tr { transition: background-color var(--w-dur-1) var(--w-ease); }
html[data-page="admin"] .data-table tbody tr:hover { background: var(--w-accent-wash); }
html[data-page="admin"] .table-wrap {
  border: 1px solid var(--w-hair);
  border-radius: var(--w-r-lg);
  box-shadow: var(--w-inset);
  overflow: auto;
  background: var(--w-surface);
}

html[data-page="admin"] .badge {
  border-radius: var(--w-r-pill);
  border: 1px solid transparent;
  box-shadow: var(--w-bevel-soft);
  font-weight: 500;
}
html[data-page="admin"] .badge.waiting { background: color-mix(in srgb, var(--w-info) 14%, transparent); color: var(--w-info); border-color: color-mix(in srgb, var(--w-info) 30%, transparent); }
html[data-page="admin"] .badge.playing { background: color-mix(in srgb, var(--w-ok) 14%, transparent); color: var(--w-ok); border-color: color-mix(in srgb, var(--w-ok) 30%, transparent); }
html[data-page="admin"] .ip-addr { color: var(--w-text); }
html[data-page="admin"] .ip-src-warn { color: var(--w-warn); }

html[data-page="admin"] .toast,
html[data-page="game"] .toast {
  border: 1px solid var(--w-hair);
  box-shadow: var(--w-bevel-soft), var(--w-e4);
  border-radius: var(--w-r-lg);
}

/* ==========================================================================
   9. 斗地主：绒布桌的纵深 + 真实卡牌厚度
   ========================================================================== */

/* 桌面：中央受光、四周压暗（营造"灯从上方照下来"的体积） */
html[data-page="game"] #game-screen {
  background:
    radial-gradient(ellipse at 50% 28%,
      color-mix(in srgb, var(--table) 76%, #ffffff) 0%,
      var(--table) 34%,
      var(--table-dark) 68%,
      var(--bg) 100%);
}
html[data-page="game"] .table {
  background:
    radial-gradient(ellipse at 50% 40%, rgba(255, 255, 255, .09) 0%, transparent 54%),
    radial-gradient(ellipse at 50% 118%, rgba(0, 0, 0, .42) 0%, transparent 62%),
    linear-gradient(165deg, var(--table), var(--table-dark));
}
html[data-page="game"] .table::after {
  border: 1px solid color-mix(in srgb, var(--gold) 18%, transparent);
  border-radius: var(--w-r-2xl);
  box-shadow:
    inset 0 0 60px rgba(0, 0, 0, .32),
    inset 0 1px 0 color-mix(in srgb, var(--gold) 12%, transparent);
}

/* 面板类：暖暗实底 + 顶部受光 + 深投影（不再用硬编码绿色） */
html[data-page="game"] .login-box,
html[data-page="game"] .room-panel,
html[data-page="game"] .modal-content {
  background:
    linear-gradient(180deg,
      color-mix(in srgb, var(--bg2) 92%, #ffffff 3%) 0%,
      var(--bg) 100%);
  border: 1px solid color-mix(in srgb, var(--gold) 20%, transparent);
  border-radius: var(--w-r-2xl);
  box-shadow:
    var(--w-bevel),
    0 4px 10px rgba(0, 0, 0, .38),
    0 30px 60px -24px rgba(0, 0, 0, .72);
}
html[data-page="game"] .logo,
html[data-page="game"] .menu-title,
html[data-page="game"] .modal-title {
  color: var(--gold);
  letter-spacing: .01em;
  text-shadow: 0 2px 20px color-mix(in srgb, var(--gold) 34%, transparent);
}
html[data-page="game"] .seat {
  background: color-mix(in srgb, var(--bg2) 88%, #ffffff 3%);
  border: 1px solid color-mix(in srgb, var(--gold) 20%, transparent);
  border-radius: var(--w-r-lg);
  box-shadow: var(--w-bevel), 0 8px 20px -10px rgba(0, 0, 0, .6);
}
html[data-page="game"] .seat.empty {
  border-style: dashed;
  border-color: color-mix(in srgb, var(--gold) 22%, transparent);
  box-shadow: none;
}

/* 头像：立体徽章 */
html[data-page="game"] .player .avatar,
html[data-page="game"] .my-info .avatar {
  border: 2px solid color-mix(in srgb, var(--gold) 45%, transparent);
  background: linear-gradient(180deg, color-mix(in srgb, var(--bg2) 70%, #ffffff 8%), var(--bg2));
  box-shadow:
    var(--w-bevel),
    0 2px 6px rgba(0, 0, 0, .45),
    0 10px 24px -12px rgba(0, 0, 0, .7);
}

/* 手牌：真实纸牌厚度 = 上高光 + 下暗边 + 两层投影
   --------------------------------------------------------------------------
   防抖设计（三段，缺一段都会"抽搐"）：
     ① transform-origin 放到底边 → 抬起时只有顶边后仰，底边不再扫过鼠标
     ② 悬停不再缩放 → 横向命中盒零变化，相邻牌之间不会互相抢 hover
     ③ ::after 把命中盒向下多留 18px → 牌抬起后鼠标仍在它的命中范围内，
        断掉「抬起 → 鼠标落空 → 放下 → 又抬起」的高频弹跳
   -------------------------------------------------------------------------- */
html[data-page="game"] .hand { perspective: 1400px; perspective-origin: 50% 100%; }
html[data-page="game"] .card {
  border: 1px solid rgba(60, 44, 28, .16);
  border-radius: 10px;
  transform-origin: 50% 100%;
  background: linear-gradient(158deg, #fffefb 0%, var(--card-bg) 48%, var(--card-bg2) 100%);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, .98),
    inset 0 -1.5px 0 rgba(120, 96, 64, .16),
    0 1px 1px rgba(0, 0, 0, .26),
    0 4px 8px -2px rgba(0, 0, 0, .30),
    0 12px 22px -10px rgba(0, 0, 0, .38);
  transition:
    transform .16s var(--w-ease-out),
    box-shadow .16s var(--w-ease-out),
    border-color .16s var(--w-ease);
}
/* 命中盒稳定器：不可见、只负责"接住"鼠标 */
html[data-page="game"] .card::after {
  content: '';
  position: absolute;
  left: 0; right: 0; top: -3px; bottom: -18px;
  border-radius: 10px;
}
/* 牌面斜向光泽：让平面的牌有"覆膜"质感 */
html[data-page="game"] .card::before {
  content: '';
  position: absolute; inset: 0; border-radius: inherit; pointer-events: none;
  background: linear-gradient(126deg, rgba(255, 255, 255, .85) 0%, rgba(255, 255, 255, 0) 38%, rgba(255, 255, 255, 0) 62%, rgba(120, 96, 64, .07) 100%);
  opacity: .75;
}
html[data-page="game"] .card:hover {
  transform: translateY(-12px) rotateX(4deg);
  z-index: 3;
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, .98),
    0 2px 3px rgba(0, 0, 0, .3),
    0 12px 20px -4px rgba(0, 0, 0, .34),
    0 30px 48px -16px rgba(0, 0, 0, .46);
}
/* 选中：抬起 + 强调色描边 + 外发光（同样不缩放，避免命中盒跳变） */
html[data-page="game"] .card.selected {
  transform: translateY(-22px) rotateX(4deg);
  z-index: 4;
  border-color: var(--gold);
  box-shadow:
    0 0 0 2px var(--gold),
    0 4px 6px rgba(0, 0, 0, .3),
    0 16px 26px -6px rgba(0, 0, 0, .36),
    0 28px 44px -12px color-mix(in srgb, var(--gold) 42%, transparent);
}
html[data-page="game"] .card.selected:hover { transform: translateY(-26px) rotateX(4deg); }

/* 已打出的牌 / 底牌：小尺寸但同样有厚度 */
html[data-page="game"] .mini-card {
  border: 1px solid rgba(60, 44, 28, .18);
  background: linear-gradient(160deg, #fffefb, var(--card-bg2));
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, .95),
    0 1px 1px rgba(0, 0, 0, .3),
    0 5px 10px -4px rgba(0, 0, 0, .42);
}
html[data-page="game"] .mini-card.card-back {
  background: linear-gradient(150deg, #b8483a 0%, #8e2f26 55%, #6d2119 100%);
  border-color: rgba(255, 210, 170, .28);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .3), 0 3px 8px -2px rgba(0, 0, 0, .5);
}

/* 底部操作栏：一块浮起的托盘 */
html[data-page="game"] .action-bar,
html[data-page="game"] .bar-utils {
  background: color-mix(in srgb, var(--bg) 62%, transparent);
  border: 1px solid color-mix(in srgb, var(--gold) 16%, transparent);
  border-radius: var(--w-r-pill);
  backdrop-filter: blur(12px) saturate(140%);
  -webkit-backdrop-filter: blur(12px) saturate(140%);
  box-shadow: var(--w-bevel-soft), 0 14px 30px -14px rgba(0, 0, 0, .7);
}
html[data-page="game"] .bottom-label {
  background: color-mix(in srgb, var(--bg) 66%, transparent);
  border: 1px solid color-mix(in srgb, var(--gold) 18%, transparent);
  border-radius: var(--w-r-pill);
  box-shadow: var(--w-bevel-soft), 0 6px 14px -6px rgba(0, 0, 0, .6);
}
html[data-page="game"] .landlord-tag,
html[data-page="game"] .p-status {
  border: 1px solid color-mix(in srgb, var(--gold) 30%, transparent);
  box-shadow: var(--w-bevel), 0 6px 14px -6px rgba(0, 0, 0, .6);
}
html[data-page="game"] .multiplier {
  border: 1px solid color-mix(in srgb, var(--gold) 26%, transparent);
  background: color-mix(in srgb, var(--bg) 68%, transparent);
  box-shadow: var(--w-bevel-soft), 0 8px 18px -8px rgba(0, 0, 0, .65);
}
html[data-page="game"] .profile-chip,
html[data-page="game"] .btn-sound,
html[data-page="game"] .btn-util {
  border: 1px solid color-mix(in srgb, var(--gold) 20%, transparent);
  background: color-mix(in srgb, var(--bg) 60%, transparent);
  box-shadow: var(--w-bevel-soft), 0 6px 14px -8px rgba(0, 0, 0, .6);
}
html[data-page="game"] .btn-util:hover,
html[data-page="game"] .btn-sound:hover,
html[data-page="game"] .profile-chip:hover { background: color-mix(in srgb, var(--gold) 16%, transparent); }
html[data-page="game"] .double-card-toggle,
html[data-page="game"] .setting-row {
  border: 1px solid color-mix(in srgb, var(--gold) 16%, transparent);
  background: color-mix(in srgb, var(--bg) 52%, transparent);
  border-radius: var(--w-r-md);
  box-shadow: var(--w-inset);
}

/* 游戏内按钮：保留配色识别度，统一加"上高光 + 双段投影 + 按压沉入" */
html[data-page="game"] button {
  border-radius: var(--w-r-md);
  transition: transform var(--w-dur-1) var(--w-ease), box-shadow var(--w-dur-2) var(--w-ease), filter var(--w-dur-1) var(--w-ease);
}
html[data-page="game"] .btn-big,
html[data-page="game"] .btn-mid,
html[data-page="game"] .btn-act,
html[data-page="game"] .btn-bid,
html[data-page="game"] .speed-btn {
  box-shadow: var(--w-bevel), 0 2px 4px rgba(0, 0, 0, .28), 0 10px 20px -10px rgba(0, 0, 0, .55);
}
html[data-page="game"] .btn-primary { background: linear-gradient(180deg, #ff8b7d, #d93f36); }
html[data-page="game"] .btn-green { background: linear-gradient(180deg, #4ee094, #23a35c); }
html[data-page="game"] .btn-blue { background: linear-gradient(180deg, #5cb4ff, #2b74d8); }
html[data-page="game"] .btn-gold { background: linear-gradient(180deg, #ffdd7a, var(--gold-dark)); color: #4a3200; }
html[data-page="game"] .btn-purple { background: linear-gradient(180deg, #c09aff, #7f52ea); }
html[data-page="game"] .btn-cyan { background: linear-gradient(180deg, #58e2e8, #239aa8); }
html[data-page="game"] .btn-gray {
  background: linear-gradient(180deg, color-mix(in srgb, var(--bg2) 82%, #ffffff 6%), var(--bg2));
  color: color-mix(in srgb, var(--text) 88%, transparent);
}
html[data-page="game"] .btn-hint { background: linear-gradient(180deg, #55665c, #31403a); }
html[data-page="game"] .btn-pass { background: linear-gradient(180deg, #66766d, #3d4c44); }
html[data-page="game"] .btn-big:hover,
html[data-page="game"] .btn-mid:hover,
html[data-page="game"] .btn-act:hover { transform: translateY(-2px); filter: brightness(1.06); }
html[data-page="game"] .btn-big:active,
html[data-page="game"] .btn-mid:active,
html[data-page="game"] .btn-act:active,
html[data-page="game"] .btn-bid:active {
  transform: translateY(1px) scale(.98);
  filter: brightness(.96);
  box-shadow: var(--w-bevel-soft), 0 1px 2px rgba(0, 0, 0, .3);
}
html[data-page="game"] .speed-btn.active {
  background: linear-gradient(180deg, var(--gold-light), var(--gold));
  color: #43300f;
  box-shadow: var(--w-bevel), 0 6px 14px -6px color-mix(in srgb, var(--gold) 60%, transparent);
}
html[data-page="game"] #join-room-input:focus,
html[data-page="game"] #nickname-input:focus {
  border-color: var(--gold);
  box-shadow: var(--w-inset), 0 0 0 3px color-mix(in srgb, var(--gold) 26%, transparent);
}

html[data-page="game"] .rank-row { border-radius: var(--w-r-md); }
html[data-page="game"] .rank-row:hover { background: color-mix(in srgb, var(--gold) 10%, transparent); }

/* 停掉两处**无限循环的 box-shadow 动画**：
   ① .card.selected 的 selectedGlow —— 它会压掉本文件给选中牌写的四段阴影+外发光
      （CSS 动画优先级高于普通声明），而且每张选中的牌都在无限重绘 box-shadow，正是"抽搐"来源；
   ② .menu-title 的 titleGlow —— 同理，常驻重绘 text-shadow。
   两者都改成静态的高光/阴影，视觉几乎一致，开销归零。 */
html[data-page="game"] .card.selected { animation: none; }
html[data-page="game"] .menu-title { animation: none; }

/* 游戏页是"固定视口"布局（style.css: html,body{overflow:hidden}），
   内容一高就会被裁且**滚不到** —— 横屏矮视口（844×390）最明显。
   给可能变高的容器补滚动兜底。 */
html[data-page="game"] .menu-body {
  overflow-y: auto;
  overscroll-behavior: contain;
  -webkit-overflow-scrolling: touch;
}
html[data-page="game"] #room-screen,
html[data-page="game"] #login-screen {
  overflow-y: auto;
  overscroll-behavior: contain;
  -webkit-overflow-scrolling: touch;
}
/* 设置弹窗在窄屏上必须允许换行：
   "🎨 主题皮肤" 一行里要放 4 个皮肤按钮（每个约 53px + 间距），
   在 390px 手机上会把弹窗撑宽 —— 实测文档宽 413 > 视口 390（横向溢出 23px）。 */
html[data-page="game"] .setting-row {
  flex-wrap: wrap;
  gap: 8px 10px;
}
html[data-page="game"] .speed-group { flex-wrap: wrap; }
/* 别让"可点区域 44px"把矮视口撑爆：横屏时用紧凑尺寸，仍满足 44px 的只有图标按钮 */
@media (orientation: landscape) and (max-height: 480px) {
  html[data-page="game"] .btn-mid,
  html[data-page="game"] .btn-big,
  html[data-page="game"] #btn-join,
  html[data-page="game"] .speed-btn,
  html[data-page="game"] .join-row input { min-height: 38px; }
  html[data-page="game"] .card.selected { transform: translateY(-12px) rotateX(3deg); }
  html[data-page="game"] .card.selected:hover { transform: translateY(-14px) rotateX(3deg); }
  html[data-page="game"] .card:hover { transform: translateY(-8px) rotateX(3deg); }
}
html[data-page="game"] .settle-row,
html[data-page="game"] .history-row {
  border-radius: var(--w-r-md);
  box-shadow: var(--w-bevel-soft), 0 4px 10px -6px rgba(0, 0, 0, .5);
}
html[data-page="game"] .badge-chip {
  border: 1px solid color-mix(in srgb, var(--gold) 28%, transparent);
  background: color-mix(in srgb, var(--gold) 12%, transparent);
  box-shadow: var(--w-bevel-soft);
}
html[data-page="game"] .modal {
  /* 全屏 backdrop-filter 是移动 GPU 上最贵的一笔开销，而且它下面正好是结算动画。
     这里只保留压暗，去掉模糊 —— 观感几乎无差，帧率稳得多。 */
  background: rgba(6, 10, 8, .78);
}
html[data-page="game"] .rotate-hint-inner {
  border: 1px solid color-mix(in srgb, var(--gold) 20%, transparent);
  box-shadow: var(--w-bevel), 0 30px 60px -24px rgba(0, 0, 0, .7);
}

/* ==========================================================================
   10. 入场与降级
   ========================================================================== */

/* 分段入场：轻微透视 + 上浮，只播一次 */
.reveal {
  transform: translateY(24px) scale(.985);
  transform-origin: 50% 100%;
  transition:
    opacity var(--w-dur-3) var(--w-ease-out),
    transform var(--w-dur-3) var(--w-ease-out);
}
.reveal.visible { transform: translateY(0) scale(1); }

/* 系统开启"减少动态效果"：关掉倾斜、光泽、浮动与入场位移 */
@media (prefers-reduced-motion: reduce) {
  .dz-tilt,
  .dz-tilt:hover,
  .dz-tilt.is-live {
    transform: none !important;
    transition: none !important;
  }
  .dz-tilt > * { transform: none !important; }
  .dz-glare::after { display: none; }
  .reveal { transform: none; transition: none; }
  html[data-page="game"] .card:hover,
  html[data-page="game"] .card.selected { transform: none; }
  html[data-page="home"] .bg-blobs i { animation: none; }
  * { animation-duration: .001ms !important; animation-iteration-count: 1 !important; }
}

/* 触摸设备：关模糊（保帧率），提高不透明度保可读性 */
@media (hover: none) {
  /* 首页导航的背景现在挂在"胶囊"(.nav-inner) 上，不是 nav 本身 */
  html[data-page="home"] body > nav.is-scrolled .nav-inner {
    background: color-mix(in srgb, var(--w-bg) 94%, transparent);
    backdrop-filter: none;
    -webkit-backdrop-filter: none;
  }
  html[data-page="home"] .about-card,
  html[data-page="home"] .item,
  html[data-page="home"] .social,
  html[data-page="home"] .treehole-item { background: color-mix(in srgb, var(--w-surface) 94%, transparent); }
  html[data-page="home"] .treehole-form { background: color-mix(in srgb, var(--w-surface) 80%, transparent); }
  html[data-page="mbti"] .card { background: color-mix(in srgb, var(--w-surface) 92%, transparent); }
  html[data-page="game"] .action-bar,
  html[data-page="game"] .bar-utils { backdrop-filter: none; -webkit-backdrop-filter: none; }
  .dz-tilt { transform: none; }
  .dz-tilt > * { transform: none; }
}

/* 移动端：按钮最小可点高度 48px */
@media (max-width: 734px) {
  html[data-page="home"] .hero-actions .btn,
  html[data-page="admin"] .btn,
  html[data-page="mbti"] .btn { min-height: 48px; }
}

/* ==========================================================================
   12. 触屏适配：输入框字号 / 点按区域 / 安全区
   --------------------------------------------------------------------------
   三类真实问题（均由多设备实测发现）：
     ① 输入框字号 < 16px —— iOS 一聚焦就会把整页放大，用户会以为"页面坏了"；
        游戏页原本在移动端媒体查询里把 16px 降到了 15px/14px，正好踩中。
     ② 可点区域 < 44×44 —— Apple HIG 的建议值；图标按钮原本只有 34px。
     ③ 带刘海/挖孔的机型（viewport-fit=cover）会把底部操作栏压在 Home 指示条下。
   ========================================================================== */

/* ① 输入框统一 ≥16px（覆盖各页原有的 14/15px 与移动端降级规则） */
html[data-page] input,
html[data-page] textarea { font-size: 16px; }
html[data-page] select.input { font-size: 14px; }        /* 后台表格里的下拉：桌面保持紧凑 */

/* ② 图标按钮与文字按钮的可点区域 */
html[data-page] #theme-btn,
html[data-page] #btn-theme { width: 44px; height: 44px; }
html[data-page] .nav-links a {
  display: inline-flex; align-items: center;
  min-height: 44px; padding: 0 6px;      /* 6px 内边距让"关于/作品/关注"这类短词也够 44px 宽 */
}
html[data-page] .nav-back {
  display: inline-flex; align-items: center; justify-content: center;
  min-height: 44px; min-width: 44px;
}
html[data-page] .treehole-reply-btn { min-height: 44px; padding: 10px 4px; }
/* 页脚链接的可点区域：横向内边距从 4px 提到 10px（配合 .foot-links 的 gap 8px），
   手机上每个链接从 30~35px 宽变为 42~47px，达到触摸目标的推荐尺寸。
   这条规则特异性 0,1,3，是页脚链接 padding 的**唯一权威定义**（blog.css 里不再重复声明）。 */
html[data-page] footer a { display: inline-block; padding: 12px 10px; }
/* 导航中间那句标语已按需求删除（连同它的规则一起清掉，不留死代码）。 */
html[data-page="game"] #btn-home,
html[data-page="game"] #btn-sound { min-width: 44px; min-height: 44px; }
html[data-page="game"] .btn-mid,
html[data-page="game"] .btn-big,
html[data-page="game"] #btn-join,
html[data-page="game"] .speed-btn { min-height: 44px; }
html[data-page="game"] .join-row input { min-height: 44px; }
html[data-page="admin"] .btn,
html[data-page="admin"] .tab { min-height: 44px; }

/* 粗指针（手机/平板/触屏本）：下拉也抬到 16px，避免聚焦放大 */
@media (pointer: coarse) {
  html[data-page] select.input { font-size: 16px; }
}

/* ③ 安全区：只在 viewport-fit=cover 的游戏页生效（刘海屏横屏时左右也会被裁） */
@supports (padding: env(safe-area-inset-bottom)) {
  /* 用容器内边距，而不是给面板加 margin —— 面板宽度是 92vw/90vw，
     加 margin 会让它在刘海机上左右各被裁掉一截。 */
  html[data-page="game"] .screen {
    padding-left: env(safe-area-inset-left);
    padding-right: env(safe-area-inset-right);
  }
  html[data-page="game"] .bottom-panel {
    padding-bottom: max(14px, env(safe-area-inset-bottom));
    padding-left: max(16px, env(safe-area-inset-left));
    padding-right: max(16px, env(safe-area-inset-right));
  }
  html[data-page="game"] .menu-header {
    padding-left: max(24px, env(safe-area-inset-left));
    padding-right: max(24px, env(safe-area-inset-right));
  }
  /* 首页/后台也做底部兜底，避免 Home 指示条压住页脚与表单 */
  html[data-page="home"] footer { padding-bottom: max(28px, env(safe-area-inset-bottom)); }
  html[data-page="home"] .treehole-form { margin-bottom: env(safe-area-inset-bottom); }
}

/* 管理后台头部因为主题按钮抬到 44px 而变高（62→72px），
   admin.css 的主面板仍按 `calc(100vh - 60px)` 算，会多出一条滚动 —— 这里对齐。 */
html[data-page="admin"] .main-panel { min-height: calc(100vh - 72px); }

/* ==========================================================================
   13. 小屏首屏收紧
   --------------------------------------------------------------------------
   注意：这一条**必须写在 home-flagship.css 里**（那里定义了展台高度）。
   我最初写在这里，结果被后加载的旗舰层同特异度规则覆盖，等于没生效 ——
   跨文件覆盖时"谁后加载谁生效"，修改时别只看单文件。
   ========================================================================== */

/* ==========================================================================
   页脚导航行（首页 / 文章归档 / 说说 / 相册 / 树洞 / RSS）
   --------------------------------------------------------------------------
   放在 depth3d.css 是因为它是**所有页面共用**的，而 blog.css 只有首页和博客页加载 ——
   树洞页曾经因此吃到浏览器默认的链接色（蓝/紫），看着就是"跳转颜色不对"。
   ========================================================================== */
.foot-links {
  /* 横向间距缩小、改由链接自身的 padding 提供 —— 触摸目标更大：
     原来 gap 22px + 链接仅 4px 内边距，手机上每个链接可点宽度只有 30~35px
     （"RSS" 只有 30px），手指容易点空。现在 8+10+10 = 28px 的视觉间距基本不变，
     可点宽度是 27+20 = 47px。 */
  display: flex; flex-wrap: wrap; justify-content: center; gap: 10px 8px;
  margin-bottom: 14px;
}
.foot-links a,
.foot-links a:visited {
  color: var(--w-muted);
  text-decoration: none;
  font-size: 13.5px;
  transition: color .2s var(--w-ease);
}
.foot-links a:hover { color: var(--w-ink); }
.foot-links a:focus-visible { outline: 2px solid var(--w-accent); outline-offset: 3px; border-radius: 4px; }

/* ==========================================================================
   备案号（全站每个页面的最底部一行）
   --------------------------------------------------------------------------
   工信部要求：网站底部展示备案号，并且**必须能点进 beian.miit.gov.cn**。
   视觉上延续页脚的节奏 —— 居中、比正文小一号、用 muted 色，只有悬停/键盘聚焦时
   才升到 ink 色，不抢主体内容的注意力；和版权行之间只留很小的间距，读起来是一段。
   可读性：12.5px / 1.5 行高，手机上不缩、不换行（号码本身不可断开）。
   触摸目标：可点区域由链接自身撑到 40px 高，手指不会点歪。
   ========================================================================== */
.foot-icp {
  display: block;
  margin-top: 2px;
  text-align: center;
  font-size: 12.5px;
  line-height: 1.5;
  color: var(--w-muted);
  letter-spacing: .01em;
  white-space: nowrap;          /* 备案号不能断行，断了会读错 */
}
.foot-icp a {
  display: inline-flex;
  align-items: center;
  min-height: 40px;             /* 手机上够大，同时把这一行的视觉留白做出来 */
  padding: 0 10px;
  color: inherit;
  text-decoration: none;
  border-radius: 6px;
  transition: color .2s var(--w-ease), background-color .2s var(--w-ease);
}
.foot-icp a:hover,
.foot-icp a:focus-visible {
  color: var(--w-ink);
  background: color-mix(in srgb, var(--w-ink) 7%, transparent);
}
.foot-icp a:focus-visible { outline: 2px solid var(--w-accent); outline-offset: 2px; }

/* 没写完整页脚的页面（MBTI / 游戏 / 后台 / 离线页）：单独一条精简页脚 */
.foot-icp-bar {
  padding: 12px 16px calc(14px + env(safe-area-inset-bottom, 0px));
  text-align: center;
  color: var(--w-muted);
}

/* 游戏页整页是固定高度的牌桌（html、body 都是 height:100% + overflow:hidden），
   流式页脚会被裁掉，所以固定在底部压一条窄带：
   容器不接收点击（pointer-events:none），只有链接可点，绝不挡牌桌操作。 */
html[data-page="game"] .foot-icp-bar {
  position: fixed;
  left: 0; right: 0; bottom: 0;
  z-index: 30;
  padding: 0 10px calc(2px + env(safe-area-inset-bottom, 0px));
  pointer-events: none;
  background: linear-gradient(180deg, transparent, rgba(0, 0, 0, .42));
}
html[data-page="game"] .foot-icp { font-size: 12px; margin: 0; opacity: .72; }
html[data-page="game"] .foot-icp a { min-height: 30px; padding: 0 8px; pointer-events: auto; }

/* ==========================================================================
   MBTI 页的导航：与首页/treehole 同一套观感
   --------------------------------------------------------------------------
   分段控件的"权威实现"在 home-flagship.css 与 pages.css 里（各自带页面作用域），
   这里给 MBTI 再声明一份 —— 数值改动时三处要一起改。
   ========================================================================== */
html[data-page="mbti"] body > nav {
  height: 52px;
  background: transparent;
  border-bottom-color: transparent;
  box-shadow: none;
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
}
html[data-page="mbti"] .nav-inner {
  position: absolute; top: 50%; left: 50%;
  transform: translate(-50%, -50%);
  width: min(980px, calc(100% - 48px));
  height: 52px; padding: 0 20px;
  border-radius: 999px;
  border: 1px solid transparent;
  background: transparent;
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
}
html[data-page="mbti"] body > nav.is-scrolled .nav-inner {
  width: min(860px, calc(100% - 48px));
  height: 50px; padding: 0 16px;   /* 50 而不是 44：44px 按钮 + 2px 内边距 + 2px 边框 = 48~50px，装不进 44px 的胶囊 */
  background: var(--nav-bg);
  border-color: var(--w-hair);
  box-shadow: var(--w-bevel-soft), var(--w-e2);
}
/* 返回按钮：与树洞/博客页同一种胶囊 */
html[data-page="mbti"] .nav-back {
  display: inline-flex; align-items: center;
  min-height: 44px; padding: 0 16px;
  border-radius: 999px;
  border: 1px solid var(--w-hair);
  background: rgba(255, 255, 255, .04);
  color: var(--w-muted) !important;
  text-decoration: none; font-size: 13.5px;
  transition: color .2s var(--w-ease), border-color .2s var(--w-ease);
}
html[data-page="mbti"] .nav-back:hover { color: var(--w-ink) !important; border-color: var(--w-accent); }
@media (max-width: 560px) {
  html[data-page="mbti"] .nav-inner .brand { font-size: 13px; }
}

/* ==========================================================================
   横向溢出兜底（所有页面）
   --------------------------------------------------------------------------
   移动端只要有一个元素比屏幕宽，浏览器就会整页缩小来适应 —— 表现为"东西挤在
   一起、文字像溢出了框"。用 clip 而不是 hidden：clip 不创建滚动容器，
   position: sticky 的导航照常吸顶。
   （这条最初误写在 home-flagship.css 里，只有首页加载得到，游戏页没有这道保护。）
   ========================================================================== */
html, body { overflow-x: clip; }

/* ==========================================================================
   16. 导航里的返回按钮（MBTI / 树洞 / 说说 / 相册）
   ========================================================================== */
.nav-back {
  display: inline-flex; align-items: center; justify-content: center; gap: 6px;
  min-height: 44px; padding: 0 15px; flex: none;
  border-radius: 999px;
  border: 1px solid var(--w-hair);
  background: rgba(255, 255, 255, .04);
  color: var(--w-muted); text-decoration: none; font-size: 13.5px;
  transition: color .22s var(--w-ease), border-color .22s var(--w-ease),
              background-color .22s var(--w-ease), transform .22s var(--w-ease);
  animation: dzBackIn .5s var(--w-ease-out) both;
}
.nav-back::before { content: '\2190'; font-size: 15px; line-height: 1; }
.nav-back:hover {
  color: var(--w-ink);
  border-color: color-mix(in srgb, var(--w-accent) 46%, transparent);
  background: color-mix(in srgb, var(--w-accent) 10%, transparent);
  transform: translateX(-2px);
}
.nav-back:active { transform: scale(.95); }
@keyframes dzBackIn {
  from { opacity: 0; transform: translateX(10px); }
  to   { opacity: 1; transform: none; }
}

/* 窄屏给导航腾地方：分段控件间距收紧、返回按钮只留箭头（仍 44px 可点） */
@media (max-width: 480px) {
  .nav-right { gap: 6px; }
  .seg { padding: 1px; }
  .nav-back { min-width: 44px; padding: 0; gap: 0; font-size: 0; }
  .nav-back::before { font-size: 16px; }
}
@media (max-width: 390px) {
  /* 注意特异性：各页的 .seg-item 规则带页面作用域（如 html[data-page="treehole"] .seg-item
     是 0,2,1），只写 .seg-item 压不过它 —— 这里提到 0,3,1 才能真正生效。 */
  html[data-page] .nav-inner .seg-item { min-width: 40px; min-height: 40px; }
  html[data-page] .nav-inner .nav-back { min-width: 40px; min-height: 40px; }
  html[data-page] .nav-inner .seg--theme .seg-item[data-theme-btn="auto"] { display: none; }
}

/* ==========================================================================
   17. 中英文切换的过渡动画
   --------------------------------------------------------------------------
   只动"文字容器"的 opacity / translateY / blur，不动卡片本身的 transform ——
   卡片上可能有倾斜动画写的内联 transform，改它会和倾斜互相打架。
   ========================================================================== */
html.lang-switching .sec-title,
html.lang-switching .sec-desc,
html.lang-switching .sec-tag,
html.lang-switching .brand--link span,
html.lang-switching .item-title,
html.lang-switching .item-desc,
html.lang-switching .item-tag,
html.lang-switching .post-title,
html.lang-switching .post-summary,
html.lang-switching .foot-copy,
html.lang-switching .foot-links,
html.lang-switching .me-intro p,
html.lang-switching .me-role,
html.lang-switching .treehole-title {
  animation: dzLangRise .46s var(--w-ease-out) both;
}
html.lang-switching .seg-thumb { animation: dzThumbPulse .5s var(--w-ease-out) both; }
@keyframes dzLangRise {
  from { opacity: .2; transform: translateY(5px); filter: blur(2px); }
  to   { opacity: 1;  transform: none;            filter: none; }
}
@keyframes dzThumbPulse {
  0%   { box-shadow: var(--w-bevel), 0 0 0 0 color-mix(in srgb, var(--w-accent) 40%, transparent); }
  60%  { box-shadow: var(--w-bevel), 0 0 0 7px color-mix(in srgb, var(--w-accent) 0%, transparent); }
  100% { box-shadow: var(--w-bevel), var(--w-e1); }
}

/* ==========================================================================
   18. 明暗切换 —— 幕布式交叉淡化
   --------------------------------------------------------------------------
   **为什么改**：原来在切换的 460ms 内给 `html.theme-switching *` 挂 7 个属性的过渡，
   等于整篇文档几百个元素同时做颜色/透明度动画。桌面 Chrome 能凑合，微信 X5 不行：
   每帧要重绘的区域太大，元素之间进度不一致 —— 观感就是"乱闪"。
   而且这个类加一次、460ms 后再删一次，各触发一次全文档样式重算，等于闪两轮。

   **现在**：只动**一个** fixed 层的 opacity（纯合成，不触发重排、不重绘页面内容）：
     ① 新主题底色的幕布淡入（~150ms）
     ② 全不透明的瞬间切 data-theme（这一下被幕布盖住，看不见）
     ③ 幕布淡出（~160ms）
   全程只有 1 个元素在动画，任何引擎都能跑满帧；主题状态仍然是一次性切换，不会出现
   "一半亮一半暗"的中间态。
   ========================================================================== */
:root[data-theme="dark"] { color-scheme: dark; }
:root[data-theme="light"] { color-scheme: light; }

.theme-curtain {
  position: fixed;
  inset: 0;
  z-index: 9999;
  pointer-events: none;          /* 绝不挡住任何点击 */
  opacity: 0;
  transition: opacity .16s linear;
  will-change: opacity;
}
.theme-curtain.is-in { opacity: 1; }
/* 颜色与 tokens.css 的 --w-bg 保持一致（亮 / 暗两套），不在 JS 里重复写死 */
.theme-curtain--to-dark { background: #100f13; }
.theme-curtain--to-light { background: #f7f6f4; }

/* 关闭动效的用户：不播任何过渡/动画 */
@media (prefers-reduced-motion: reduce) {
  html.lang-switching *,
  .nav-back { animation: none !important; transition: none !important; }
  .theme-curtain { display: none !important; }
}

/* 窄屏隐藏品牌（所有页面统一）：导航里已经有返回按钮负责回首页，
   品牌头像再占 32~44px 只会把分段控件挤出胶囊（这正是横向溢出的成因之一）。
   特异性提到 0,3,1 以压过各页自己的 .brand--link 规则。 */
/* 结构性保证：**让品牌做那个"让位"的元素，两个切换控件永远不被挤出去。**
   导航是一行 nowrap 的 flex：品牌（white-space:nowrap，最小宽度=文字整宽）+ 间距 +
   语言分段 + 配色分段 + 返回按钮。这些子项默认 flex-shrink:1，但 nowrap 文本和按钮的
   最小内容宽度就等于它们的实际宽度 —— 谁也压不小，于是整行只能往外溢。 */
html[data-page] .nav-inner .brand,
html[data-page] .nav-inner .brand--link {
  flex: 0 1 auto; min-width: 0; overflow: hidden;
}
html[data-page] .nav-inner .brand--link span {
  min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
html[data-page] .nav-inner .brand-avatar { flex: 0 0 auto; }
html[data-page] .nav-inner .nav-right { flex: 0 0 auto; margin-left: auto; }

/* 窄屏隐藏品牌（所有页面统一）：导航里已经有返回按钮负责回首页，
   品牌头像再占 32~44px 只会把分段控件挤出胶囊（这正是横向溢出的成因之一）。
   特异性提到 0,3,1 以压过各页自己的 .brand--link 规则。
   --------------------------------------------------------------------------
   断点从 560 提到 680：实测"品牌 + 语言分段 + 配色分段 + 返回按钮 + 间距"
   最少需要 508px 内容宽，而胶囊在 561px 视口只给得出 473px（亏 10px，返回按钮被推出胶囊 4px）；
   561~600 这一段一直处于"差几像素"的状态，字号一旦被系统放大 25% 立刻溢出。
   680 之后余量 ≥85px，留够字体缩放的余量。 */
@media (max-width: 680px) {
  html[data-page] .nav-inner .brand,
  html[data-page] .nav-inner .brand--link { display: none; }
}
/* 窄屏把胶囊左右内边距压到 12px，控件尺寸不动（仍 40/44px 可点）。
   两条老规则之所以没救回来，是特异性输给了各页自己的 0,2,1：
   `@media (max-width:360px) { .nav-inner { padding: 0 12px } }` 是 0,1,0，
   而 `html[data-page="blog"] .nav-inner { padding: 0 20px }` 是 0,2,1 ——
   所以 320~360 这些页面上内边距一直是 20px，实测"两个分段 + 返回"要 239px、
   胶囊只给 232px，亏 7px。这里用 0,2,2 / 0,3,2 直接压过页面作用域。
   320px 复查：胶囊 272 - 24 = 248 ≥ 239，余 9px。 */
@media (max-width: 420px) {
  html[data-page] body > nav .nav-inner { padding-left: 12px; padding-right: 12px; }
  html[data-page] body > nav.is-scrolled .nav-inner { padding-left: 12px; padding-right: 12px; }
}
/* 320px 再收 2px：滚动态"两个分段 + 返回"要 247px，12px 内边距只给 248px（1px 余量太脆）。
   pages.css 里有同值的 ≤340 段 —— 那边的滚动态规则与这里同权，两边都写才不会取决于文件顺序。 */
@media (max-width: 340px) {
  html[data-page] body > nav .nav-inner { padding-left: 10px; padding-right: 10px; }
  html[data-page] body > nav.is-scrolled .nav-inner { padding-left: 10px; padding-right: 10px; }
}
/* 超窄屏（≤360）再给导航腾 16px：收窄胶囊内外边距，控件尺寸不动（仍 40/44px 可点） */
@media (max-width: 360px) {
  .nav-inner { width: min(980px, calc(100% - 28px)); padding: 0 12px; }
  body > nav.is-scrolled .nav-inner { width: min(860px, calc(100% - 28px)); padding: 0 10px; }
}


/* ==========================================================================
   19. 阅读进度条 + 回到顶部（文章/归档/说说/相册/树洞）
   ========================================================================== */
.dz-progress {
  position: fixed; top: 0; left: 0; right: 0; height: 2.5px; z-index: 90;
  transform-origin: 0 50%;
  transform: scaleX(0);
  background: linear-gradient(90deg, var(--w-accent), #f5c542 55%, #3ddc97);
  pointer-events: none;
}
.dz-top {
  position: fixed; right: 18px; z-index: 91;
  bottom: calc(18px + env(safe-area-inset-bottom));
  display: grid; place-items: center;
  width: 44px; height: 44px;
  border-radius: 999px;
  border: 1px solid var(--w-hair);
  background: var(--nav-bg);
  color: var(--w-ink); font: inherit; font-size: 17px; cursor: pointer;
  box-shadow: var(--w-bevel), var(--w-e2);
  opacity: 0; transform: translateY(10px) scale(.92); pointer-events: none;
  transition: opacity .26s var(--w-ease), transform .26s var(--w-ease), border-color .2s var(--w-ease);
}
.dz-top.is-on { opacity: 1; transform: none; pointer-events: auto; }
.dz-top:hover { border-color: var(--w-accent); }
.dz-top:active { transform: scale(.93); }


/* ==========================================================================
   20. 分段控件（中文/ENG、浅色/深色/跟随系统）—— **唯一权威实现**
   --------------------------------------------------------------------------
   以前这套样式在三个文件里各有一份（home-flagship / pages / 本文件给 MBTI 的那份），
   改一个数值要同时改三处，漏一处就会出现"首页好看、树洞页崩了"这种问题。
   现在只有这一份，用 html[data-page] 提高特异性以压过各页可能残留的旧规则。
   分段滑块的位置由 depth3d.js 的 __segSync 写入 --seg-x / --seg-w。
   ========================================================================== */
html[data-page] .seg {
  position: relative;
  display: inline-flex; align-items: center; gap: 2px;
  padding: 2px;
  border-radius: 999px;
  border: 1px solid var(--w-hair);
  background: rgba(255, 255, 255, .05);
  box-shadow: var(--w-inset);
}
html[data-page] .seg-thumb {
  position: absolute; top: 2px; left: 0;
  height: calc(100% - 4px);
  width: var(--seg-w, 44px);
  border-radius: 999px;
  background: var(--w-surface);
  box-shadow: var(--w-bevel), var(--w-e1);
  transform: translateX(var(--seg-x, 2px));
  transition: transform .36s var(--w-ease-out), width .36s var(--w-ease-out);
  pointer-events: none; z-index: 0;
}
html[data-page] .seg-item {
  position: relative; z-index: 1;
  appearance: none; border: 0; background: transparent;
  color: var(--w-muted); font: inherit; cursor: pointer;
  display: grid; place-items: center;
  min-width: 44px; min-height: 44px;
  padding: 0 12px;
  border-radius: 999px;
  transition: color .2s var(--w-ease);
}
html[data-page] .seg-item:hover { color: var(--w-ink); }
html[data-page] .seg-item[aria-pressed="true"] { color: var(--w-ink); }
html[data-page] .seg--theme .seg-item { padding: 0; }
html[data-page] .seg--theme .seg-item svg { width: 15px; height: 15px; display: block; }
/* 滚动状态**不要**改分段控件的内部几何：
   一旦 padding / min-width 变了，JS 算出来的滑块位置（--seg-x / --seg-w）就是旧值，
   滑块会停在错位的地方 —— 用户看到的就是"切换按钮自己在左右滑"。
   缩小的效果由外面的胶囊容器（.nav-inner 的宽高）负责，控件保持稳定。 */
/* 滚动态：胶囊变矮（52 → 50），分段控件必须跟着收 1px 内边距。
   算一下高度就明白为什么：44px 按钮 + 上下各 2px 内边距 + 上下各 1px 边框 = 50px，
   胶囊只有 44px 时控件会上下各探出 3px —— 这就是"滚动后切换控件溢出胶囊"的成因。
   控件内部几何变了，滑块位置（--seg-x / --seg-w）会短暂失准，
   depth3d.js 在 nav 的 transitionend 里会补一次 __segSync() 重算，所以是安全的。 */
html[data-page] body > nav.is-scrolled .seg { padding: 1px; }
html[data-page] body > nav.is-scrolled .seg-item { min-width: 44px; min-height: 44px; }
html:not(.js) .seg-thumb { display: none; }
/* 窄屏：控件收小、只留必要的档位（品牌与返回按钮在 depth3d 的导航段里统一处理） */
@media (max-width: 480px) {
  html[data-page] .seg { padding: 1px; }
  html[data-page] .seg-item { padding: 0 10px; }
}
@media (max-width: 390px) {
  html[data-page] .nav-inner .seg-item { min-width: 40px; min-height: 40px; padding: 0 8px; }
  html[data-page] .nav-inner .seg--theme .seg-item[data-theme-btn="auto"] { display: none; }
}
