/* ============================================================================
   麻将研习社 · 视觉升级层  (beautify.css)
   ----------------------------------------------------------------------------
   这一层只做「视觉」——不改结构、不改内容、不改交互逻辑。
   它必须在 style.css 之后、且在所有页面内联 <style> 之后加载
   （注入脚本把它插在 </head> 之前，保证覆盖页面内联样式）。

   分三段：
     §1  设计令牌 + 全局底子（背景、滚动条、排版细节）
     §2  组件升级（导航 / Hero / 卡片 / 按钮 / 标题 / 表格 / 价格 / FAQ）
     §3  主题适配（浅色、高对比）与响应式、动效、无障碍
   ========================================================================== */

/* ==========================================================================
   §1  设计令牌 + 全局底子
   ========================================================================== */

:root{
  /* —— 金色体系：给金色分出「高光 / 主体 / 深底」三层，才有金属感 —— */
  --bz-gold-hi:#fbeaa6;
  --bz-gold-mid:#e6c463;
  --bz-gold-deep:#a8801f;
  --bz-gold-line:rgba(212,175,55,.20);
  --bz-gold-line-a:rgba(212,175,55,.52);

  /* —— 墨色体系：深棕黑，比纯黑更有温度 —— */
  --bz-ink-0:#0b0803;
  --bz-ink-1:#151006;
  --bz-ink-2:#1e160a;

  /* —— 卡片令牌（深色主题默认值，浅色主题在 §3 覆盖） —— */
  --bz-card-bg:linear-gradient(165deg,rgba(255,255,255,.055) 0%,rgba(255,255,255,.018) 48%,rgba(212,175,55,.04) 100%);
  --bz-card-bd:rgba(212,175,55,.17);
  --bz-card-sh:0 2px 10px rgba(0,0,0,.22), inset 0 1px 0 rgba(255,255,255,.055);
  --bz-card-bd-h:rgba(212,175,55,.55);
  --bz-card-sh-h:
    0 24px 52px -18px rgba(0,0,0,.78),
    0 0 0 1px rgba(212,175,55,.13),
    0 0 48px -14px rgba(212,175,55,.30),
    inset 0 1px 0 rgba(255,255,255,.10);

  /* —— 图标底衬 —— */
  --bz-icon-bg:radial-gradient(circle at 32% 26%,rgba(212,175,55,.26),rgba(212,175,55,.05) 70%);
  --bz-icon-bd:rgba(212,175,55,.24);

  /* —— 文字层级：把「正文 / 次要 / 更弱」拉开，避免一片灰 —— */
  --bz-body:rgba(255,255,255,.80);
  --bz-body-dim:rgba(255,255,255,.62);

  /* —— 统一的缓动 —— */
  --bz-ease:cubic-bezier(.22,.61,.36,1);
  --bz-dur:.28s;
}

/* --------------------------------------------------------------------------
   1.1  页面背景
   原来 body::before 叠了一张实景照片（人脸/桌面），在正文后面透出眼睛、
   鼻子的轮廓，读起来很脏。这里换成「金色氛围光晕 + 极淡牌面点阵」，
   保留暖棕金调性，但把干扰降到几乎为零。
   -------------------------------------------------------------------------- */
body::before{
  background:
    url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='152' height='152' viewBox='0 0 152 152'><g fill='none' stroke='%23d4af37' stroke-width='1.2' opacity='0.13'><circle cx='76' cy='76' r='13'/><circle cx='76' cy='76' r='4.4'/></g></svg>")
      0 0/152px 152px repeat,
    radial-gradient(1200px 620px at 14% -6%,rgba(212,175,55,.17),transparent 62%),
    radial-gradient(1000px 560px at 88% 6%,rgba(230,57,70,.075),transparent 60%),
    radial-gradient(900px 700px at 50% 106%,rgba(212,175,55,.10),transparent 62%),
    linear-gradient(180deg,#100b04 0%,#171006 44%,#0c0802 100%) !important;
  background-attachment:fixed,fixed,fixed,fixed,fixed;
}

/* 页脚原来也用同一张照片，同样换掉，改成金线 + 深墨渐变 */
.footer{
  background:linear-gradient(180deg,#0a0703 0%,#120c05 60%,#080502 100%) !important;
  border-top:1px solid var(--bz-gold-line) !important;
}
.footer::before{
  background:
    radial-gradient(900px 240px at 50% 0%,rgba(212,175,55,.13),transparent 70%),
    linear-gradient(180deg,rgba(212,175,55,.05),transparent 60%) !important;
  opacity:1 !important;
}
.footer::after{
  background:none !important;
}

/* --------------------------------------------------------------------------
   1.2  滚动条 / 选区 / 焦点
   -------------------------------------------------------------------------- */
/* ★ 第 19 轮：滚动条 thumb 原来是 rgba(212,175,55,.42)（半透明金）。
   实测（pseudo-audit.js，全站 44 页 × 三配色）对轨只有 **1.25~2.54** —— 基本看不见。
   ★ 可行域（先算再改）：**金 thumb 数学上不可能达标** —— 完全不透明的 #d4af37
     压最亮的轨（#faf6ec）也只有 1.95。而 thumb 还要**同时**压住两类轨：
     深色页面轨 rgb(23,17,7) 与浅色牌面/牌手轨 rgb(253,251,243) / 深绿 rgb(23,57,44)。
     逐轨解不等式 ⇒ thumb 的相对亮度必须落在 **[0.19871, 0.23340]** 这个窄窗里。
   取 #9d7a24（L=0.21215，窗内居中）：实测 11 种真实轨的**最小**比值 = 3.16。
   ⚠ 第一版曾按主题分别给值（浅色 #78601a），实测发现 `:root[data-theme="light"] *`
     里的 **`*` 不匹配 <html> 自身** ⇒ 整页主滚动条（最显眼那条）漏掉了，仍是 1.66。
     改成「一个颜色通吃」后既更简单，也不再依赖主题选择器。 */
*{scrollbar-width:thin;scrollbar-color:#9d7a24 transparent}
::-webkit-scrollbar{width:11px;height:11px}
/* ★ 第 19 轮：轨改 transparent —— 原来这里是 rgba(0,0,0,.22)（一条灰槽）。
   改成 transparent 后，旧 webkit 路径与上面的 scrollbar-color 路径**行为完全一致**
   （轨都透出元素底色）⇒ 同一个 thumb 色在两条路径上给出同一组比值，
   不必再为「Chrome 内测不到 webkit 路径」单独算一套（原灰槽下 thumb 只有 1.10）。 */
::-webkit-scrollbar-track{background:transparent}
::-webkit-scrollbar-thumb{
  background:#9d7a24;
  border-radius:99px;
  border:3px solid transparent;
  background-clip:padding-box;
}
/* ★ 第 19 轮：hover 也必须落在同一个窗内（原 hover 渐变压浅轨只有 1.22）。
   #a17e28（L=0.22652）：11 种轨最小比值 = 3.07。 */
::-webkit-scrollbar-thumb:hover{background:#a17e28;background-clip:padding-box}
::-webkit-scrollbar-corner{background:transparent}

::selection{background:#6f5410;color:#fff}
/* ★ 第 19 轮：原来是 background:rgba(212,175,55,.34)（半透明金）+ color:#fff。
   半透明 ⇒ 合成底随**元素自身底色**而变，白字在浅底元素上直接崩：
   实测（pseudo-audit.js，全站 44 页 × 三配色，10,663 个样本）最差 1.27~1.30；
   截图实证：浅色下选中 .logo-text「麻将研习社」= 白字压浅金带，几乎读不出。
   而 .logo-text / index.html h1 的 span / pricing .stat .n 都是
   background-clip:text 的渐变字 —— ::selection 的 color 一旦不是 transparent，
   字形就用这个 color 画（不再是渐变），所以 color:inherit 也救不了
   （渐变浅端 #a8842a 压浅金带只有 1.63）。
   ⇒ 唯一确定性修法：**选中底改不透明**。底固定 ⇒ 白字恒定，与元素底色无关。
   实测 #6f5410 底 + #fff 字 = 7.11（浅/深/hc 三套配色完全一致）。
   #6f5410 取的是站点 hc 浅色的 --gold2，与既有调色板同源。 */

:focus-visible{
  outline:2px solid var(--gold2);
  outline-offset:3px;
  border-radius:6px;
}

/* --------------------------------------------------------------------------
   1.3  排版细节
   -------------------------------------------------------------------------- */
body{
  -webkit-font-smoothing:antialiased;
  -moz-osx-font-smoothing:grayscale;
  text-rendering:optimizeLegibility;
}
h1,h2,h3,.section-title,.hero h1{text-wrap:balance}
p,li,td,th{text-wrap:pretty}

/* 正文整体抬一档亮度，长文阅读更省力 */
.chapter p,.chapter li{color:var(--bz-body)}

/* ==========================================================================
   §2  组件升级
   ========================================================================== */

/* --------------------------------------------------------------------------
   2.1  导航
   -------------------------------------------------------------------------- */
.nav{
  box-shadow:
    0 1px 0 rgba(255,255,255,.05) inset,
    0 10px 34px -10px rgba(0,0,0,.55) !important;
}
.logo{transition:transform var(--bz-dur) var(--bz-ease)}
.logo:hover{transform:translateY(-1px)}
.logo-badge{
  position:relative;
  box-shadow:
    0 4px 14px -4px rgba(212,175,55,.6),
    inset 0 1px 0 rgba(255,255,255,.45),
    inset 0 -2px 6px rgba(0,0,0,.18);
  transition:box-shadow var(--bz-dur) var(--bz-ease),transform var(--bz-dur) var(--bz-ease);
}
.logo-badge::after{
  content:'';position:absolute;inset:0;border-radius:inherit;pointer-events:none;
  background:linear-gradient(150deg,rgba(255,255,255,.5) 0%,transparent 46%);
  mix-blend-mode:overlay;
}
.logo:hover .logo-badge{box-shadow:0 6px 20px -4px rgba(212,175,55,.85),inset 0 1px 0 rgba(255,255,255,.5)}
.logo-text{
  background:linear-gradient(120deg,var(--bz-gold-hi) 0%,var(--gold) 46%,var(--bz-gold-deep) 100%);
  -webkit-background-clip:text;background-clip:text;color:transparent;
  filter:drop-shadow(0 1px 2px rgba(0,0,0,.35));
}

/* 导航项：hover 时从底部升起一条金线，比单纯换底色更精致 */
.nav-links a{position:relative;transition:color .22s var(--bz-ease),background .22s var(--bz-ease)}
.nav-links a::after{
  content:'';position:absolute;left:12px;right:12px;bottom:4px;height:2px;
  border-radius:2px;
  background:linear-gradient(90deg,transparent,var(--gold2),transparent);
  transform:scaleX(0);transform-origin:center;
  transition:transform .3s var(--bz-ease);
}
.nav-links a:hover::after{transform:scaleX(1)}
.nav-links a.nav-cta::after,
.nav-links a.nav-bold::after{display:none}

/* 导航里的两个 CTA 按钮：主次分明 */
.nav-links a.nav-cta:not(.nav-bold){
  background:linear-gradient(135deg,var(--gold) 0%,var(--gold2) 100%) !important;
  color:#1a1206 !important;
  box-shadow:0 6px 18px -6px rgba(212,175,55,.7),inset 0 1px 0 rgba(255,255,255,.42);
  transition:transform .22s var(--bz-ease),box-shadow .22s var(--bz-ease);
}
.nav-links a.nav-cta:not(.nav-bold):hover{
  transform:translateY(-1px);
  box-shadow:0 10px 26px -6px rgba(212,175,55,.9),inset 0 1px 0 rgba(255,255,255,.5);
}

/* 下拉菜单：加投影与描边，跟玻璃导航拉开层次 */
.nav-chapters-drop{
  border-radius:14px !important;
  box-shadow:
    0 28px 64px -20px rgba(0,0,0,.85),
    0 0 0 1px rgba(212,175,55,.14),
    inset 0 1px 0 rgba(255,255,255,.05) !important;
}
.nav-chapters-drop a{border-radius:8px}
.nav-chapters-drop a:hover{
  background:linear-gradient(90deg,rgba(212,175,55,.16),rgba(212,175,55,.04)) !important;
  color:var(--gold2) !important;
}

/* --------------------------------------------------------------------------
   2.2  Hero
   三个硬伤：
     a) 浅色主题下 --text 变深色，而 hero-box 背景是硬编码深色
        → 深字压深底，完全不可读；
     b) 页面用内联样式把副标题设成 var(--text-d)，同样被主题带跑；
     c) 按钮行的 flex 默认左对齐，跟居中的标题对不齐。
   -------------------------------------------------------------------------- */
.hero{filter:none !important}

/* Hero 内一律用「亮金」：浅色主题会把 --gold / --gold2 调暗成墨金
   （为了在白底上够深），但那套颜色压在 hero 的深色底上会发灰发脏。
   所以在 hero 作用域内重新定义这两个变量，主题怎么切都不影响这里。 */
.hero{
  --gold:#d4af37;
  --gold2:#f5d76e;
}

/* 背景照片保留（有实景氛围），但压暗成「氛围层」，文字才立得住 */
.hero::before{
  background:
    radial-gradient(92% 128% at 50% -10%,rgba(212,175,55,.16),transparent 58%),
    linear-gradient(180deg,rgba(8,5,1,.60) 0%,rgba(8,5,1,.46) 38%,rgba(6,4,1,.80) 100%) !important;
}

.hero .hero-box{
  background:
    radial-gradient(130% 150% at 10% -20%,rgba(212,175,55,.20) 0%,transparent 56%),
    radial-gradient(100% 120% at 100% 120%,rgba(230,57,70,.10) 0%,transparent 58%),
    linear-gradient(135deg,rgba(12,8,3,.92) 0%,rgba(20,14,7,.84) 52%,rgba(10,7,2,.94) 100%) !important;
  border:1px solid rgba(212,175,55,.34) !important;
  box-shadow:
    0 40px 90px -30px rgba(0,0,0,.92),
    0 0 70px -24px rgba(212,175,55,.34),
    inset 0 1px 0 rgba(255,255,255,.08) !important;
  /* 这里刻意不加 backdrop-filter：卡片背景本身已是 0.9 左右的不透明深色，
     模糊背景几乎看不出来，却要在整块大区域上做一次全屏采样，
     低端机（软件渲染）上会明显拖慢首屏。 */
}

/* —— 关键修复：hero 卡片内的文字一律浅色，不受主题变量影响 —— */
.hero .hero-box h1{color:#fff !important;text-shadow:0 2px 16px rgba(0,0,0,.8),0 1px 3px rgba(0,0,0,.9)}
.hero .hero-box p{
  color:rgba(255,255,255,.86) !important;
  text-shadow:0 2px 10px rgba(0,0,0,.7) !important;
}
.hero .hero-box .sub,
.hero .hero-box small,
.hero .hero-box li{color:rgba(255,255,255,.80) !important}
/* 注意：不要碰 h1 里的 <span>——它的金色渐变靠 color:transparent 实现 */

/* —— 修复：CTA 按钮行居中（:has 精确命中「装了按钮的那一行」） —— */
.hero .hero-box div:has(> .btn),
.hero > div div:has(> .btn),
.hero-box div:has(> a.btn){
  justify-content:center;
}

/* 标题与正文之间加一点呼吸感 */
.hero .hero-box h1{margin-bottom:16px !important;letter-spacing:-.02em}
.hero .hero-box p{margin-bottom:28px !important}

/* Hero 上方那排「麻将牌」
   原来是 emoji（U+1F000 区）：Windows 上渲染成黑底白纹的方块、macOS 上是彩色、
   部分 Linux 直接是豆腐块——完全不可控。改成用 CSS 画的牌背：跨平台一致，
   而且比 emoji 更像真牌。对应 HTML 是 index.html 里的 .hero-tiles。 */
.hero-tiles{
  display:flex;
  gap:9px;
  justify-content:center;
  align-items:flex-end;
  margin-bottom:22px;
}
.hero-tiles span{
  position:relative;
  width:36px;
  height:48px;
  border-radius:7px;
  background:linear-gradient(158deg,#fffdf6 0%,#f3ecd9 48%,#e2d7bc 100%);
  border:1px solid rgba(212,175,55,.55);
  box-shadow:
    0 12px 22px -12px rgba(0,0,0,.85),
    inset 0 1px 0 #fff,
    inset 0 -3px 0 rgba(140,108,40,.22);
}
/* 牌背斜纹 */
.hero-tiles span::after{
  content:'';position:absolute;inset:7px;border-radius:3px;
  background:repeating-linear-gradient(45deg,rgba(160,120,40,.16) 0 2px,transparent 2px 5px);
}
/* 中间那张微微抬起，一排不至于太呆板 */
.hero-tiles span:nth-child(3){transform:translateY(-5px)}
@media (max-width:640px){
  .hero-tiles{gap:7px;margin-bottom:18px}
  .hero-tiles span{width:30px;height:40px;border-radius:6px}
  .hero-tiles span:nth-child(3){transform:translateY(-4px)}
}

/* hero 标题里的金色渐变：浅色主题会把 --gold2 调暗成墨金，
   压在深色卡片上会发灰。这里直接钉死成亮金，两种主题下都够亮。 */
.hero .hero-box h1 span{
  background:linear-gradient(135deg,#fff1bd 0%,#f6d878 44%,#dcb542 100%) !important;
  -webkit-background-clip:text !important;
  background-clip:text !important;
  color:transparent !important;
  filter:drop-shadow(0 2px 14px rgba(245,215,110,.42));
}

/* --------------------------------------------------------------------------
   2.3  区块标题
   -------------------------------------------------------------------------- */
.section-title{
  position:relative;
  letter-spacing:-.015em;
  font-weight:900;
}
.section-title::after{
  content:'';display:block;
  width:64px;height:3px;margin:14px auto 0;
  border-radius:99px;
  background:linear-gradient(90deg,transparent,var(--gold) 22%,var(--bz-gold-hi) 50%,var(--gold) 78%,transparent);
  box-shadow:0 0 16px rgba(212,175,55,.5);
}
.section-sub{
  color:var(--bz-body-dim) !important;
  font-size:15.5px !important;
  line-height:1.7;
}

/* --------------------------------------------------------------------------
   2.4  卡片（.module / .ch-card / .t-card 等通用容器）
   -------------------------------------------------------------------------- */
.module{
  position:relative;
  background:var(--bz-card-bg) !important;
  border:1px solid var(--bz-card-bd) !important;
  box-shadow:var(--bz-card-sh);
  transition:
    transform var(--bz-dur) var(--bz-ease),
    border-color var(--bz-dur) var(--bz-ease),
    box-shadow var(--bz-dur) var(--bz-ease),
    background var(--bz-dur) var(--bz-ease);
}
/* 顶部一抹金线：hover 时从左向右扫过 */
.module::before{
  content:'';position:absolute;left:0;right:0;top:-1px;height:2px;
  border-radius:2px 2px 0 0;
  background:linear-gradient(90deg,transparent,var(--gold2) 35%,var(--bz-gold-hi) 50%,var(--gold2) 65%,transparent);
  transform:scaleX(0);transform-origin:left center;
  transition:transform .45s var(--bz-ease);
  pointer-events:none;
}
.module:hover{
  background:var(--bz-card-bg) !important;
  border-color:var(--bz-card-bd-h) !important;
  box-shadow:var(--bz-card-sh-h);
  transform:translateY(-4px);
}
.module:hover::before{transform:scaleX(1)}

/* 图标放进圆角底衬里，不再是「光秃秃一个 emoji」 */
.module-icon{
  align-self:flex-start;
  display:grid;place-items:center;
  min-width:54px;min-height:54px;padding:8px;
  border-radius:15px;
  background:var(--bz-icon-bg);
  border:1px solid var(--bz-icon-bd);
  box-shadow:inset 0 1px 0 rgba(255,255,255,.10),0 6px 16px -8px rgba(0,0,0,.6);
  line-height:1;
  transition:transform var(--bz-dur) var(--bz-ease),box-shadow var(--bz-dur) var(--bz-ease);
}
.module:hover .module-icon{
  transform:scale(1.06) rotate(-3deg);
  box-shadow:inset 0 1px 0 rgba(255,255,255,.16),0 10px 24px -8px rgba(212,175,55,.45);
}

/* 编号/标签：左侧一颗发光小金块，长短文本都好看 */
.module-num{
  align-self:flex-start;
  position:relative;
  padding-left:15px;
  font-weight:800 !important;
  letter-spacing:.12em !important;
  text-transform:none;
}
.module-num::before{
  content:'';position:absolute;left:0;top:.5em;
  width:7px;height:7px;border-radius:2px;
  background:linear-gradient(135deg,var(--bz-gold-hi),var(--gold));
  box-shadow:0 0 10px rgba(212,175,55,.75);
}

.module h3{letter-spacing:-.01em}
.module p{line-height:1.68}
.module .sub{letter-spacing:.01em}

/* --------------------------------------------------------------------------
   2.5  按钮
   -------------------------------------------------------------------------- */
.btn{
  position:relative;
  border-radius:11px;
  letter-spacing:.01em;
  transition:
    transform .22s var(--bz-ease),
    box-shadow .22s var(--bz-ease),
    background .22s var(--bz-ease),
    color .22s var(--bz-ease),
    border-color .22s var(--bz-ease);
}
.btn-primary{
  background:linear-gradient(135deg,var(--gold) 0%,var(--gold2) 52%,var(--bz-gold-hi) 100%) !important;
  color:#1a1206 !important;
  box-shadow:
    0 8px 22px -8px rgba(212,175,55,.75),
    inset 0 1px 0 rgba(255,255,255,.5),
    inset 0 -2px 6px rgba(140,100,10,.22);
  font-weight:800 !important;
}
.btn-primary:hover{
  transform:translateY(-2px);
  box-shadow:
    0 16px 36px -10px rgba(212,175,55,.9),
    inset 0 1px 0 rgba(255,255,255,.6),
    inset 0 -2px 6px rgba(140,100,10,.22);
  filter:brightness(1.05);
}
.btn-primary:active{transform:translateY(0) scale(.985)}
.btn-ghost{
  background:linear-gradient(160deg,rgba(255,255,255,.075),rgba(255,255,255,.02)) !important;
  border:1px solid var(--bz-gold-line-a) !important;
  box-shadow:inset 0 1px 0 rgba(255,255,255,.09),0 4px 14px -8px rgba(0,0,0,.6);
  backdrop-filter:blur(4px);
}
.btn-ghost:hover{
  background:linear-gradient(160deg,rgba(212,175,55,.20),rgba(212,175,55,.06)) !important;
  border-color:var(--gold2) !important;
  color:var(--gold2) !important;
  transform:translateY(-2px);
  box-shadow:0 12px 28px -10px rgba(212,175,55,.5),inset 0 1px 0 rgba(255,255,255,.14);
}
.btn-ghost:active{transform:translateY(0) scale(.985)}

/* --------------------------------------------------------------------------
   2.6  表格（章节里的对照表）
   -------------------------------------------------------------------------- */
.chapter table{
  border-radius:12px !important;
  overflow:hidden;
  box-shadow:0 8px 26px -14px rgba(0,0,0,.7),inset 0 0 0 1px var(--bz-gold-line);
}
.chapter th{
  background:linear-gradient(180deg,rgba(212,175,55,.20),rgba(212,175,55,.10)) !important;
  color:var(--bz-gold-hi) !important;
  letter-spacing:.02em;
  border-bottom:1px solid var(--bz-gold-line-a) !important;
}
.chapter tbody tr{transition:background .2s var(--bz-ease)}
.chapter tbody tr:hover{background:rgba(212,175,55,.075)}
.chapter td{color:var(--bz-body) !important}
.chapter tbody tr:nth-child(even) td{background:rgba(255,255,255,.018)}
/* 2.6b 表标题 caption（第 22 轮 1.3.1：skills.html 标题行从 th 改 caption，视觉与 .chapter th 对齐） */
.chapter caption{
  caption-side:top;
  text-align:center;
  padding:10px 12px;
  font-weight:600;
  letter-spacing:.02em;
  color:var(--bz-gold-hi);
  background:linear-gradient(180deg,rgba(212,175,55,.20),rgba(212,175,55,.10));
  border-bottom:1px solid var(--bz-gold-line-a);
}

/* --------------------------------------------------------------------------
   2.7  价格卡 / FAQ / 保证条
   -------------------------------------------------------------------------- */
.price-card{
  background:var(--bz-card-bg) !important;
  border:1px solid var(--bz-card-bd) !important;
  box-shadow:var(--bz-card-sh);
  transition:transform var(--bz-dur) var(--bz-ease),box-shadow var(--bz-dur) var(--bz-ease),border-color var(--bz-dur) var(--bz-ease);
}
.price-card:hover{
  transform:translateY(-5px);
  border-color:var(--bz-card-bd-h) !important;
  box-shadow:var(--bz-card-sh-h);
}
.price-card.featured{
  border:1.5px solid var(--gold) !important;
  box-shadow:
    0 0 0 1px rgba(212,175,55,.22),
    0 30px 70px -26px rgba(0,0,0,.8),
    0 0 80px -22px rgba(212,175,55,.5) !important;
  background:
    radial-gradient(120% 100% at 50% -20%,rgba(212,175,55,.16),transparent 62%),
    var(--bz-card-bg) !important;
}
.price-card.featured:hover{
  transform:translateY(-8px);
  box-shadow:
    0 0 0 1px rgba(212,175,55,.32),
    0 40px 90px -26px rgba(0,0,0,.85),
    0 0 100px -20px rgba(212,175,55,.62) !important;
}
.price-card .badge{
  box-shadow:0 8px 22px -6px rgba(212,175,55,.8),inset 0 1px 0 rgba(255,255,255,.5);
  letter-spacing:.02em;
}
.price-card .price{
  letter-spacing:-.02em;
  filter:drop-shadow(0 2px 10px rgba(212,175,55,.35));
}

.faq-item{
  background:var(--bz-card-bg) !important;
  border:1px solid var(--bz-card-bd) !important;
  box-shadow:var(--bz-card-sh);
  transition:border-color var(--bz-dur) var(--bz-ease),box-shadow var(--bz-dur) var(--bz-ease);
}
.faq-item:hover{border-color:var(--bz-card-bd-h) !important;box-shadow:var(--bz-card-sh-h)}
.faq-item summary{position:relative;padding-right:52px !important}
.faq-item summary::after{
  content:'';position:absolute;right:22px;top:50%;
  width:9px;height:9px;margin-top:-6px;
  border-right:2px solid var(--gold2);border-bottom:2px solid var(--gold2);
  transform:rotate(45deg);
  transition:transform .3s var(--bz-ease);
}
.faq-item[open] summary::after{transform:rotate(-135deg);margin-top:-2px}
.faq-item .a{line-height:1.75}

.guarantee{
  box-shadow:0 20px 50px -24px rgba(6,214,160,.4),inset 0 1px 0 rgba(255,255,255,.08);
}

/* --------------------------------------------------------------------------
   2.8  修正：Before / After 标签的对比度
   原样式把文字色写死成浅粉/浅绿，浅色主题下压在浅底上几乎看不见。
   -------------------------------------------------------------------------- */
.t-card .before{
  background:rgba(230,57,70,.14) !important;
  color:#ff9d9d !important;
  border:1px solid rgba(230,57,70,.32);
  font-weight:600;
}
.t-card .after{
  background:rgba(6,214,160,.14) !important;
  color:#6fe9c4 !important;
  border:1px solid rgba(6,214,160,.32);
  font-weight:600;
}
.t-card{
  background:var(--bz-card-bg) !important;
  border:1px solid var(--bz-card-bd) !important;
  box-shadow:var(--bz-card-sh);
  transition:border-color var(--bz-dur) var(--bz-ease),box-shadow var(--bz-dur) var(--bz-ease);
}
.t-card:hover{border-color:var(--bz-card-bd-h) !important;box-shadow:var(--bz-card-sh-h)}
.t-card .stars{letter-spacing:3px;filter:drop-shadow(0 0 6px rgba(212,175,55,.55))}

/* 数据卡（stat） */
.stat{
  background:var(--bz-card-bg) !important;
  border:1px solid var(--bz-card-bd) !important;
  box-shadow:var(--bz-card-sh);
  transition:transform var(--bz-dur) var(--bz-ease),box-shadow var(--bz-dur) var(--bz-ease);
}
.stat:hover{transform:translateY(-3px);box-shadow:var(--bz-card-sh-h)}
.stat .n{filter:drop-shadow(0 2px 10px rgba(212,175,55,.4))}

/* --------------------------------------------------------------------------
   2.9  章节页：目录、进度、锚点导航
   -------------------------------------------------------------------------- */
.ch-card{
  background:var(--bz-card-bg) !important;
  border:1px solid var(--bz-card-bd) !important;
  box-shadow:var(--bz-card-sh);
  transition:transform var(--bz-dur) var(--bz-ease),border-color var(--bz-dur) var(--bz-ease),box-shadow var(--bz-dur) var(--bz-ease);
}
.ch-card:hover{
  transform:translateY(-4px);
  border-color:var(--bz-card-bd-h) !important;
  box-shadow:var(--bz-card-sh-h);
}
.jumpnav a{
  background:var(--bz-card-bg) !important;
  border:1px solid var(--bz-card-bd) !important;
  transition:all .22s var(--bz-ease);
}
.jumpnav a:hover{
  transform:translateY(-1px);
  border-color:var(--bz-gold-line-a) !important;
  box-shadow:0 8px 20px -10px rgba(212,175,55,.55);
}

/* ==========================================================================
   §3  主题适配 · 响应式 · 动效 · 无障碍
   ========================================================================== */

/* --------------------------------------------------------------------------
   3.1  浅色主题
   浅色下卡片用「实底 + 暖白」比半透明更干净；对比度整体抬一档。
   -------------------------------------------------------------------------- */
:root[data-theme="light"]{
  --bz-card-bg:linear-gradient(168deg,#fffdf8 0%,#fbf5e9 100%);
  --bz-card-bd:rgba(168,128,31,.28);
  --bz-card-sh:0 1px 2px rgba(120,90,20,.07),0 10px 26px -16px rgba(120,90,20,.35);
  --bz-card-bd-h:rgba(168,128,31,.62);
  --bz-card-sh-h:
    0 26px 54px -22px rgba(120,90,20,.5),
    0 0 0 1px rgba(168,128,31,.18),
    0 0 42px -16px rgba(168,128,31,.35),
    inset 0 1px 0 rgba(255,255,255,.9);
  --bz-icon-bg:radial-gradient(circle at 32% 26%,rgba(168,128,31,.20),rgba(168,128,31,.05) 72%);
  --bz-icon-bd:rgba(168,128,31,.30);
  --bz-gold-line:rgba(168,128,31,.26);
  --bz-gold-line-a:rgba(168,128,31,.55);
  --bz-body:rgba(36,29,16,.88);
  --bz-body-dim:rgba(36,29,16,.70);
}

/* --------------------------------------------------------------------------
   深色主题 · 对比度补齐
   --------------------------------------------------------------------------
   原站的深色调色板把 --text-m 定成 #6a6a75（中灰），压在深色卡片底上实测只有
   2.98 ~ 3.76；--red #e63946 压在深色底上 3.62 ~ 4.37。都不到 AA（正文 4.5）。
   全站 28 页扫出 53 条，其中 48 条都出自 --text-m 这一个变量。

   这是**原站遗留**问题，不是本次美化引入的。对照实验：临时把本文件移开、
   重扫同样 5 个页面，数字完全相同（index 6 / pricing 4 / course-probability 8 /
   course-drills 5 / anti-cheat 4，一一对应）—— 也就是说这些失败与美化层无关。

   选择器用 :not([data-theme="light"]) 而不是 [data-theme="dark"]：站点在 JS
   未执行时不会写 data-theme 属性，那时走的是 :root 的深色默认值，:not 这种
   写法能一并覆盖。高对比模式（data-hc="on"）只针对浅色主题定义，不冲突。
   -------------------------------------------------------------------------- */
:root:not([data-theme="light"]){
  --text-m:#8e8e99;
  --red:#f0626d;
}
/* --red 提亮后，「红底 + 白字」的填充场景要换回深红：白字压在 #f0626d 上只有
   3.15。这类场景是「红作底色」而不是「红作字色」，两者的方向刚好相反。 */
:root:not([data-theme="light"]) #micBtn.mic-on{
  background:#c62828 !important;
  border-color:#c62828 !important;
}
/* 听牌训练页的等级徽标（11px 小字）压在 rgba(255,255,255,.06) 的内嵌面上，
   底色比正文底亮一档，--text-m(#8e8e99) 在这里只剩 4.32:1。

   不能靠整体提亮 --text-m 解决：它和 --text-d(#9a9aa5) 本来就只差 12 级，
   再提亮两者就分不出层级了（次要/更次要的视觉区分会消失）。
   所以只提这一处，实测 4.77:1。 */
:root:not([data-theme="light"]) .tp-grade{color:#96969f}
:root:not([data-theme="light"]) .dr-opt.dr-no .dr-opt-letter{background:#c62828;color:#fff}

/* --------------------------------------------------------------------------
   浅色主题 · 对比度补齐
   --------------------------------------------------------------------------
   用 WCAG 对比度公式实测全站（工具：_tools/audit.js），这几个原变量在浅色底
   上差一点点，小字会发虚：
     --text-m  #8a826e → 3.19 ~ 3.76   次要说明文字（"8 课 · 零基础可学"等）
     --green   #06d6a0 → 1.65          「30 天无理由退款」标题（亮绿压浅绿底）
     --red     #e63946 → 4.10          安全必修标签、金额强调
     --gold2   #8a6c1c → 4.14 ~ 4.16   金色小字
   差距都在 0.4 ~ 1.3 之间，肉眼不易察觉，但确实不达 AA（正文 4.5）。
   这里统一压深到 4.5 以上，色相不变，观感几乎无差别。

   --text-m 压了两轮：先 #736a52，全站复测后仍有 8 处卡在 4.49（差 0.01），
   再压到 #6b6249。这两个值在页脚那种更深的底（#ece0c6）上分别是 4.05 / 4.63，
   所以 4.49 那批其实是"底色比正文底更深"导致的，不是变量本身不够深。

   注意：高对比模式 data-hc="on" 自己定义了更深的 --text-m / --gold2，
   优先级更高，不受这里影响；而 --green / --red 它没有定义，正好由这里补上。
   -------------------------------------------------------------------------- */
:root[data-theme="light"]{
  --text-m:#6b6249;
  --green:#067a5c;
  --red:#c62828;
  --gold2:#78601a;
}

/* ---------------------------------------------------------------------------
   --orange 全站从未定义（原版遗留）
   ---------------------------------------------------------------------------
   原版 style.css 的 :root 只定义了 --bg/--card/--border/--text 系列/--gold 系列
   --red/--green —— **没有 --orange**，但 4 个页面 7 处引用了它：

     beginner.html      .bg-ex-no{border-left:3px solid var(--orange)}
     beginner.html      .bg-ex-no .bg-ex-badge{...;color:var(--orange)}
     course-drills.html .dr-lv1 .dr-bar span{background:var(--orange)}
     course-drills.html .dr-lv1 .dr-card-pct{color:var(--orange)}
     course-drills.html .dr-res-bad{color:var(--orange)}
     course-reading.html .rd-no{...;color:var(--orange)}

   原始的生成脚本 build_drills_page.py 里就是这么写的，所以是**原版就有的
   缺陷**，不是这一轮引入的。

   后果是静默的：`color:var(--orange)` 因为变量不存在而整条声明失效，
   元素退化成**继承父级颜色**——对比度检测照样通过（继承来的通常是 --text，
   对比度很高），所以审计报 0，但**语义色全丢了**：
     · 「✗ 这不是和牌」徽标不再是橙色，和「✓ 这是和牌」的绿色不成对
     · 难度 Lv1 的进度条 `background:var(--orange)` 直接**透明**，条看不见
     · `.dr-res-bad`「建议改进」与 `.dr-res-good` 长得一模一样

   取 #f59c3c：这是页面里所有橙色描边/底纹用的 rgba(245,156,60,…) 对应的
   实色，即原作者的意图色。浅色主题下压到 #8a4708（与 .rd-no 同色，
   色板一致），实测 5.2~5.7:1。
   --------------------------------------------------------------------------- */
:root{--orange:#f59c3c}
:root[data-theme="light"]{--orange:#8a4708}

/* 评分星星是纯装饰性金色，主色 --gold 不宜整体压深（会影响按钮和描边），
   单独把这一处调深。 */
:root[data-theme="light"] .t-card .stars{color:#8a6c1c}
/* 页脚底色比正文底更深（#f3ead6 → #ece0c6），同一个 --text-m 在这里
   只剩 4.05，所以页脚单独再压深一档。 */
:root[data-theme="light"] .footer,
:root[data-theme="light"] .footer p,
:root[data-theme="light"] .footer .footer-copy{color:#6b6249}

/* 痕迹逆向页的标签（.win / .tr-tag）：原样式把字色写死成浅粉 #ff9ca4，
   压在同样浅的粉底上，实测 1.61 —— 基本等于看不见。

   这里踩过一个坑，记下来：最初写成 `.win{color:#a8323f !important}`，
   结果把 `.win.w-mid` 的「中风险」金色语义一起压成了红色 —— 实测
   .win 与 .win.w-mid 的计算色完全相同。这属于静默回归：审计不会报错
   （红色本身对比度达标），只有把两个变体并排打出来才看得见。

   所以现在按变体分别配色，并且背景一律改成**不透明**。不透明是关键：
   半透明背景会和父容器叠加，同一段 CSS 在不同页面得到不同实际底色，
   既不好测也不好维护。 */
:root[data-theme="light"] .win,
:root[data-theme="light"] .tr-tag{
  color:#8e1f2b;
  background:#fbeae8;
  border-color:rgba(142,31,43,.42);
}
:root[data-theme="light"] .win.w-mid{
  color:#5e4a0d;
  background:#f7f0dc;
  border-color:rgba(94,74,13,.42);
}
:root[data-theme="light"] .win.w-long{
  color:#7d1a25;
  background:#f7dedc;
  border-color:rgba(125,26,37,.5);
}

/* --------------------------------------------------------------------------
   浅色主题 · 修复「硬编码深色背景」的组件
   --------------------------------------------------------------------------
   全站扫描出 9 处把背景写死成 rgba(0,0,0,.2 ~ .3)（深色主题下用来压暗卡片），
   浅色主题下就变成灰块 —— 上面的金色/灰色文字实测只有 2.7 ~ 4.0 的对比度。

   这里用 :where() 把主题限定的优先级**归零**，于是选择器权重等于单独一个类名，
   与组件的基础规则同级、靠后加载取胜；而 .dr-opt:hover / .dr-opt.dr-ok /
   .dr-opt.dr-no 这些更高优先级的状态色不受影响，照常生效。
   -------------------------------------------------------------------------- */
:where(:root[data-theme="light"]) :is(
  .ac-hub-card, .dr-wrong-item, .dr-opt,
  .pu-kv, .pu-chart, .pu-conf, .pu-dchart, .stat-formula
){
  background-color:#fdfaf3;
  border-color:rgba(168,128,31,.28);
}
/* 概率页的柱状图用的是 rgba(255,255,255,.22) 白色柱子，浅色底上等于隐形 */
:where(:root[data-theme="light"]) .pu-bar{background:rgba(120,90,20,.28)}
/* 首页邀请链接的输入框是内联 style 写死的 rgba(0,0,0,.3)，只能靠 !important 盖。
   ★ 第 14 轮：边框色从 rgba(168,128,31,.35) 改成 #8a6c1c ——
   前者叠在这个输入框的浅色渐变底（最暗色标 #f6eeda）上只有 1.30:1，
   而控件填充与页面底色几乎同色 ⇒ 边框是识别它的唯一手段 ⇒ 必须 ≥3:1。
   #8a6c1c 实测 vs 底 4.28:1、vs 页面 4.87:1。
   ⚠ 这条是 `input[readonly]` 选择器 + !important，**按类名 grep .ref-input 找不到它** ——
     第 14 轮就是先漏了它，改完 CSS 复测仍报 1.30，才用规则枚举探针揪出来。 */
:where(:root[data-theme="light"]) input[readonly]{
  background:linear-gradient(168deg,#fffdf8,#f6eeda) !important;
  border-color:#8a6c1c !important;
}

/* --------------------------------------------------------------------------
   浅色主题 · 「交互后才出现」的状态色
   --------------------------------------------------------------------------
   这类问题静态审计扫不到：同一时刻只显示一种状态，页面默认渲染的是没交互的
   样子。用 _tools/audit.js 扫全站，这几处一条都报不出来 —— 不是没问题，是
   没被渲染。我是另建了 _probe/states.html 把所有状态平铺出来才测到的。

   实测（浅色主题，1440px）：
     .dr-opt.dr-ok  .dr-opt-letter     1.35   #062 深绿压在 --green 上
     .dr-opt.dr-no  .dr-opt-mark       1.61   #ff9ca4 浅粉压在浅红底上
     .pu-warning    .pu-verdict-text   1.87   #f59c3c 写死的橙色

   处理原则同样是「背景不透明」：半透明底会随父容器变化，测出来的值不可复现。
   -------------------------------------------------------------------------- */

/* ---- 概率检测页：判定条 5 种状态（JS 按 p 值切换 v.level） ---- */
:root[data-theme="light"] .pu-normal{background:#e8f4ee;border-color:rgba(5,107,80,.30)}
:root[data-theme="light"] .pu-normal .pu-verdict-text{color:#056b50}
:root[data-theme="light"] .pu-watch{background:#f6f0da;border-color:rgba(120,96,26,.32)}
:root[data-theme="light"] .pu-watch .pu-verdict-text{color:#78601a}
:root[data-theme="light"] .pu-warning{background:#faeede;border-color:rgba(154,74,0,.34)}
:root[data-theme="light"] .pu-warning .pu-verdict-text{color:#9a4a00}
:root[data-theme="light"] .pu-critical{background:#fbe9e9;border-color:rgba(183,28,28,.36)}
:root[data-theme="light"] .pu-critical .pu-verdict-text{color:#b71c1c}
:root[data-theme="light"] .pu-insufficient{background:#f4f1ea;border-color:rgba(120,96,26,.22)}

/* ---- 演练页：选项的三种状态（答题后才加 dr-ok / dr-no） ---- */
:root[data-theme="light"] .dr-opt.dr-ok{background:#e6f4ee;border-color:rgba(5,107,80,.42)}
:root[data-theme="light"] .dr-opt.dr-ok .dr-opt-letter{background:#067a5c;color:#fff}
:root[data-theme="light"] .dr-opt.dr-ok .dr-opt-mark{color:#056b50}
:root[data-theme="light"] .dr-opt.dr-no{background:#fbeaea;border-color:rgba(183,28,28,.42)}
:root[data-theme="light"] .dr-opt.dr-no .dr-opt-mark{color:#b71c1c}

/* 未作答态的选项与字母块：底色从半透明改成实色，金色字才有稳定底子 */
:root[data-theme="light"] .dr-opt .dr-opt-letter{background:#f1e9d6;color:#78601a}
:root[data-theme="light"] .dr-opt:hover:not(:disabled){background:#f8f1de}
:root[data-theme="light"] .ac-hub-card:hover{background:#f8f1de}

:root[data-theme="light"] body::before{
  background:
    url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='152' height='152' viewBox='0 0 152 152'><g fill='none' stroke='%23a8801f' stroke-width='1.2' opacity='0.11'><circle cx='76' cy='76' r='13'/><circle cx='76' cy='76' r='4.4'/></g></svg>")
      0 0/152px 152px repeat,
    radial-gradient(1200px 620px at 14% -6%,rgba(212,175,55,.20),transparent 62%),
    radial-gradient(1000px 560px at 88% 6%,rgba(230,57,70,.06),transparent 60%),
    radial-gradient(900px 700px at 50% 106%,rgba(212,175,55,.14),transparent 62%),
    linear-gradient(180deg,#fdfaf3 0%,#f7f0e0 46%,#fbf7ee 100%) !important;
}

/* 导航 logo 的渐变文字：首端原本是 #c39a2c，压在浅色导航底
   rgb(250,246,236) 上只有 2.44（大字需 3.0）—— 也就是「麻」这个字最亮。

   压深到 #a07c22 之后，桌面端（20px，算大字，需 3.0）过了 3.60，
   但**窄屏又挂了**：≤420px 时本文件把 .logo-text 缩到 18px，18 < 18.66，
   不再算大字，判据变成 4.5 —— 于是 28 个页面全部报 3.60。这是只看桌面
   尺寸时看不到的。最终按 4.5 这条更严的线定值：
   #8a6c1c / #7a5f18 / #6b5110 → 4.59 / 5.60 / 6.93，桌面与窄屏同时成立。

   这一处是审计工具的**盲区**：渐变文字用 color:transparent，常规对比度检测
   在「前景 alpha < 0.05」那一步就跳过了，报 0 条不等于没问题。补上渐变检测
   之后才看见（见 _tools/audit.js 里的 GRAD 段）。 */
:root[data-theme="light"] .logo-text{
  background:linear-gradient(120deg,#8a6c1c 0%,#7a5f18 55%,#6b5110 100%);
  -webkit-background-clip:text;background-clip:text;color:transparent;
  filter:none;
}
:root[data-theme="light"] .nav-links a.nav-cta:not(.nav-bold){color:#241d10 !important}

/* ★ 2026-10-05：浅色主题下金色渐变的**深端**不达标 —— 全站主 CTA 都受影响。
   根因：本文件 :665 把浅色的 --gold2 定成 #78601a（墨金，为了在白底上当**文字**够深），
   但 .btn-primary / .price-card .badge / .plan-badge 把它当**底色**用，
   上面压的是近黑字 #1a1206 / #241d10 —— 深压深，只有 2.77:1。
   ★ 为什么以前没发现：审计只取渐变的**第一个色标**（= --gold #a8842a → 4.77 达标），
     而最弱的一环在中间那个 52% 的 --gold2。这是量具的盲区，不是页面的新问题。
   ★ 为什么现在必须修：这一条和「对局页第 4 批」是同一族（同一个 --gold2），
     一起修才不留半截。量具：工作区 _mj_audit_strict.js。
   实测：a.btn.btn-primary 2.77 → 6.95（34 页）、.price-card .badge 2.89 → 7.25。 */
:root[data-theme="light"] .btn-primary{
  background:linear-gradient(135deg,#d9b756 0%,#c9a24a 52%,var(--bz-gold-hi) 100%) !important;
  color:#241d10 !important;
}
/* .price-card .badge 与 .plan .plan-badge 的声明**写在各页内联 <style> 里**
   （41 页逐字相同）。beautify.css 是最后一个 <link>，且这条多一个属性选择器，
   特异性 (0,3,0) > 内联的 (0,2,0)，所以不用 !important 也能覆盖。 */
:root[data-theme="light"] .price-card .badge,
:root[data-theme="light"] .plan .plan-badge{
  background:linear-gradient(135deg,#e6cf78,#c9a24a);
}
/* ★ 2026-10-05：`.nav-cta` 是同一个根因（style.css:147 也是 var(--gold)→var(--gold2)）。
   它**只在 ≥ 某断点才可见** —— 390 下 .nav-links 收进汉堡菜单，
   所以只扫 390 的审计完全看不到它。这条是靠「对局页状态审计」在 1440 下逮到的，
   量具教训：**同一套严格判据要在多个视口各扫一遍**，可见性本身是随视口变的。

   ★ 选择器必须照抄 :172 的 `.nav-links a.nav-cta:not(.nav-bold)` 的形状：
   那条的特异性是 (0,3,1)（`:not()` 里的类要计入），而 `:root[data-theme] .nav-cta`
   只有 (0,3,0) —— 第一版就写低了，实测颜色生效、背景没生效，只剩一半。 */
:root[data-theme="light"] .nav-links a.nav-cta:not(.nav-bold),
:root[data-theme="light"] .nav-links a.nav-cta.nav-bold{
  background:linear-gradient(135deg,#e6cf78,#c9a24a) !important;
  color:#241d10 !important;
}
:root[data-theme="light"] .btn-ghost{
  background:linear-gradient(160deg,#fffdf8,#f6eeda) !important;
  color:#241d10 !important;
}
:root[data-theme="light"] .btn-ghost:hover{
  color:#6f5410 !important;
  background:linear-gradient(160deg,rgba(212,175,55,.22),rgba(212,175,55,.08)) !important;
}

:root[data-theme="light"] .chapter th{color:#6f5410 !important}
:root[data-theme="light"] .chapter td{color:rgba(36,29,16,.88) !important}
:root[data-theme="light"] .chapter tbody tr:nth-child(even) td{background:rgba(168,128,31,.045)}

:root[data-theme="light"] .footer{
  background:linear-gradient(180deg,#f3ead6 0%,#ece0c6 100%) !important;
  border-top:1px solid rgba(168,128,31,.3) !important;
}
:root[data-theme="light"] .footer::before{
  background:radial-gradient(900px 240px at 50% 0%,rgba(168,128,31,.12),transparent 70%) !important;
}

:root[data-theme="light"] .t-card .before{background:rgba(200,30,45,.10) !important;color:#a81b28 !important;border-color:rgba(200,30,45,.30)}
:root[data-theme="light"] .t-card .after{background:rgba(5,150,110,.12) !important;color:#0a6b50 !important;border-color:rgba(5,150,110,.32)}

/* Hero 在浅色主题下同样保持深底浅字（照片背景本来就是暗的） */
:root[data-theme="light"] .hero .hero-box h1{color:#fff !important}
:root[data-theme="light"] .hero .hero-box p{color:rgba(255,255,255,.88) !important}

/* --------------------------------------------------------------------------
   3.2  高对比模式：进一步收紧边界与文字
   -------------------------------------------------------------------------- */
:root[data-hc="on"]{
  --bz-card-bd:rgba(212,175,55,.42);
  --bz-card-bd-h:rgba(245,215,110,.85);
  --bz-body:rgba(255,255,255,.94);
  --bz-body-dim:rgba(255,255,255,.82);
}
:root[data-theme="light"][data-hc="on"]{
  --bz-card-bg:#ffffff;
  --bz-card-bd:rgba(120,90,20,.5);
  --bz-body:rgba(22,17,10,.96);
  --bz-body-dim:rgba(22,17,10,.86);
}
:root[data-theme="light"][data-hc="on"] body::before{
  background:
    url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='152' height='152' viewBox='0 0 152 152'><g fill='none' stroke='%238a6c1c' stroke-width='1.2' opacity='0.07'><circle cx='76' cy='76' r='13'/><circle cx='76' cy='76' r='4.4'/></g></svg>")
      0 0/152px 152px repeat,
    linear-gradient(180deg,#ffffff 0%,#faf5ea 50%,#ffffff 100%) !important;
}
:root[data-theme="light"][data-hc="on"] .footer{background:#f6efe0 !important}
/* --------------------------------------------------------------------------
   3.2b 高对比模式 & hover 态：把「金色当背景 + 深色文字」这一族单独兜住
   --------------------------------------------------------------------------
   背景（第 10 轮实测，42 页 × light/dark × 390/1440 + hover/focus 真事件）：

   hc 把 --gold 从 #a8842a 调深到 #8a6c1c、--gold2 从 #78601a 调深到 #6f5410，
   目的是让**金色文字**在浅底上够亮。但同一个变量还被用作**按钮背景**配深色文字，
   那一侧就反过来了：

     选择器                      状态     普通浅色   hc 浅色
     .dr-newbtn / .hq-btn-primary 静止     4.90 ✓    3.46 ✗
     .dr-newbtn / .hq-btn-primary :hover   2.85 ✗    2.41 ✗
     .m2m-toast-hist-btn          :hover   4.90 ✓    3.70 ✗
     .m2m-toast-hist-btn          :focus   4.90 ✓    3.70 ✗
     .chapter th（双层卡片页）     静止     5.19 ✓    4.38 ✗

   注意 .dr-newbtn:hover 的 2.85 是**普通浅色下就已经不达标**的既有缺陷 —— 它只在
   :hover 出现，静态审计（只看加载后那一帧）永远看不见，是这轮新加 hover 探针才逮到的。

   修法：
     · 普通浅色：静止态 4.90 本来达标，**一行不动**；只把 hover 的文字改白，
       保留原来「悬停变深」的手感（深金 #78601a + 白字 = 6.02）。
     · hc：静止与 hover 都换成**浅金底 + 深字**（hc 的宗旨就是可读性优先）。
     · .chapter th：hc 下统一压深到 #654a10（单层卡片 6.69、双层卡片 5.10）。
   -------------------------------------------------------------------------- */

/* 普通浅色：只修 hover 的文字色，背景与静止态不动 */
:root[data-theme="light"] .dr-newbtn:hover,
:root[data-theme="light"] .hq-btn-primary:hover{color:#fff}

/* hc：金底 + 深字的按钮改成浅金底 */
:root[data-theme="light"][data-hc="on"] .dr-newbtn,
:root[data-theme="light"][data-hc="on"] .hq-btn-primary{
  background:linear-gradient(160deg,#e8cf86,#d9b756);
  color:#241d10;
}
:root[data-theme="light"][data-hc="on"] .dr-newbtn:hover,
:root[data-theme="light"][data-hc="on"] .hq-btn-primary:hover{
  background:linear-gradient(160deg,#f0dda0,#e8cf86);
  color:#241d10;
}
/* hc：全站浮动「toast 历史」按钮的 hover / 键盘焦点 */
:root[data-theme="light"][data-hc="on"] .m2m-toast-hist-btn:hover,
:root[data-theme="light"][data-hc="on"] .m2m-toast-hist-btn:focus-visible{
  background:linear-gradient(160deg,#e8cf86,#d9b756);
  color:#241d10;
}
/* hc：章节表头。双层 var(--card) 叠加把底色压暗后，原来的 #6f5410 只剩 4.38 */
:root[data-theme="light"][data-hc="on"] .chapter th{color:#654a10 !important}

/* --------------------------------------------------------------------------
   3.2d  .dr-next / .dr-btn-primary：与 .dr-newbtn **逐字同族**的「金底 + 深字」按钮。
   §3.2b 当时只覆盖了 .dr-newbtn / .hq-btn-primary / .m2m-toast-hist-btn，这两个漏了。

   实测（probe_el.js 定点 + audit 交互态驱动）：
     普通浅  静止 #a8842a/#241a05 = 4.90 ✓    hover #78601a/#241a05 = 2.85 ✗
     hc 浅   静止 #8a6c1c/#241a05 = 3.46 ✗    hover #6f5410/#241a05 = 2.41 ✗
     深色    静止 #d4af37/#241a05 = 8.15 ✓    hover #f5d76e/#241a05 = 11.0 ✓

   为什么十几轮都没被发现：
     .dr-next        要**答完一题**才由 js/drills-ui.js 插入 DOM；
     .dr-btn-primary 要**答完全部题目、进入结果页**才出现。
     ⇒ 静态面（加载后那一帧）永远看不到它们；只有把页面驱动到交互态才暴露。
     注意 2.85 这个数此前也出现在 .dr-newbtn:hover 上，是同一条根因（一个变量
     兼「金色文字」与「按钮底色」两个角色），只是当年漏了这两个兄弟。
   -------------------------------------------------------------------------- */
/* 普通浅色：hover 只换文字色（与 §3.2b 的 .dr-newbtn:hover 同法） */
:root[data-theme="light"] .dr-next:hover,
:root[data-theme="light"] .dr-btn-primary:hover{color:#fff}
/* hc 浅色：金底换浅金底（与 §3.2b 完全一致的色板） */
:root[data-theme="light"][data-hc="on"] .dr-next,
:root[data-theme="light"][data-hc="on"] .dr-btn-primary{
  background:linear-gradient(160deg,#e8cf86,#d9b756);
  color:#241d10;
}
:root[data-theme="light"][data-hc="on"] .dr-next:hover,
:root[data-theme="light"][data-hc="on"] .dr-btn-primary:hover{
  background:linear-gradient(160deg,#f0dda0,#e8cf86);
  color:#241d10;
}

/* --------------------------------------------------------------------------
   3.2g  .tp-btn-primary / .rv-btn-primary（免费工具箱 / 牌谱复盘 主按钮）：
   与 §3.2b / §3.2d **同一族** —— `background:var(--gold); color:#1a1206`。

   实测（audit.js 46 页 × 320px 静态 + 手工核算 hover）：
     普通浅  静止 #a8842a/#1a1206 = 5.29 ✓    hover #78601a/#1a1206 = 3.08 ✗
     hc 浅   静止 #8a6c1c/#1a1206 = 3.74 ✗    hover #6f5410/#1a1206 = 2.60 ✗
     深色    静止 #d4af37/#1a1206 = 8.81 ✓    hover #f5d76e/#1a1206 = 13.09 ✓

   ★ 为什么第 25 轮首验没发现：那一轮 hc 全站审计报 0，是因为 `AUDIT_URL_SUFFIX`
     只写了 `&hc=1`（被页面已有的查询串吃掉）⇒ **根本没进 hc**，是量具假阴性。
     第 26 轮用完整 `?bz=off&hc=1` 复跑，静止态立刻暴露 2 条（tools / revue 各 1）。
     hover 态则要 `hover-audit.js` 才看得见（静态审计只看加载后那一帧）。

   修法与 §3.2b / §3.2d 逐字一致：
     · 普通浅色：hover 只把文字改白（#78601a + 白 = 6.02）。
     · hc：静止与 hover 都换浅金底 + 深字（10.89 / 12.36）。
   -------------------------------------------------------------------------- */
/* 普通浅色：hover 只换文字色 */
:root[data-theme="light"] .tp-btn-primary:hover,
:root[data-theme="light"] .rv-btn-primary:hover{color:#fff}
/* hc 浅色：金底换浅金底（与 §3.2b 同色板） */
:root[data-theme="light"][data-hc="on"] .tp-btn-primary,
:root[data-theme="light"][data-hc="on"] .rv-btn-primary{
  background:linear-gradient(160deg,#e8cf86,#d9b756);
  border-color:#d9b756;
  color:#241d10;
}
:root[data-theme="light"][data-hc="on"] .tp-btn-primary:hover,
:root[data-theme="light"][data-hc="on"] .rv-btn-primary:hover{
  background:linear-gradient(160deg,#f0dda0,#e8cf86);
  border-color:#e8cf86;
  color:#241d10;
}

/* --------------------------------------------------------------------------
   3.2e  .dr-fb-link（反馈区「→ 回到《XX》深入学习」链接）：hover **方向反了**。
   原文把 hover 的 color 设成 var(--gold) —— 把静止态的深金 --gold2 换成
   亮金 --gold，在浅底上反而变浅，对比度是**下降**的。

   实测（hover-audit.js，CDP 真鼠标悬停，course-drills.html 驱动到反馈态）：
     普通浅  before #78601a/#eeded6 = 4.61 ✓  →  after #a8842a/#eeded6 = 2.68 ✗
     hc 浅   before #6f5410/#e8dbdb = 5.27 ✓  →  after #8a6c1c/#e8dbdb = 3.67 ✗

   修法：hover 改为**加深**（hover 更醒目才是正确方向，与 §3.2d 同思路）。
     普通浅 #6b5314 压 #eeded6 = 5.59 ✓     hc 浅 #5c4410 压 #e8dbdb = 6.81 ✓
   border-bottom-color 一并加深：这条虚线是「用颜色区分链接」的识别手段，
   1.4.11 要求非文本对比 ≥3，原 #a8842a 压 #eeded6 只有 2.68。
   深色下 --gold(#d4af37) 压 #171006 = 8.96 ✓，不动。
   -------------------------------------------------------------------------- */
:root[data-theme="light"] .dr-fb-link:hover{
  color:#6b5314;border-bottom-color:#6b5314;
}
:root[data-theme="light"][data-hc="on"] .dr-fb-link:hover{
  color:#5c4410;border-bottom-color:#5c4410;
}

/* --------------------------------------------------------------------------
   3.2f  .dr-btn（结果页次级按钮「返回总览」）：hover **方向反了**（同 §3.2e 族）。
   原文把 hover 的 color 设成 var(--gold2) —— 静止态文字是深灰褐 #5a523f，
   hover 换成 --gold2（浅色 #78601a / hc #6f5410），文字**变浅**了。
   AA 勉强通过，但余量薄到只剩 0.05，任何一次调色都会翻车。

   实测（hover-audit.js，CDP 真鼠标悬停，course-drills.html 驱动到结果页）：
     普通浅  before #5a523f/#e4e0d6 = 5.85 ✓  →  after #78601a/#e4e0d6 = 4.55 ✓（余量 0.05）
     hc 浅   before #2e2719/#d3d2d0 = 9.75 ✓  →  after #6f5410/#d3d2d0 = 4.69 ✓（余量 0.19）

   修法：hover 改为**加深**（与 §3.2d / §3.2e 同思路）。
     普通浅 #6b5314 压 #e4e0d6 = 5.55 ✓     hc 浅 #5c4410 压 #d3d2d0 = 6.07 ✓
   ★ 必须 :not(.dr-btn-primary) —— 主按钮的 class 是「dr-btn dr-btn-primary」，
     不排除就会被这条 (0,5,0) 覆盖掉 §3.2d 给它设的 color:#fff。
   只改 color；border-color 仍是 var(--gold2)（1.4.11 已达标，不动）。
   深色下 --gold2(#f5d76e) 压 #171006 约 12.9 ✓，不动。
   -------------------------------------------------------------------------- */
:root[data-theme="light"] .dr-btn:not(.dr-btn-primary):hover{color:#6b5314}
:root[data-theme="light"][data-hc="on"] .dr-btn:not(.dr-btn-primary):hover{color:#5c4410}


/* --------------------------------------------------------------------------
   3.3  入场动效
   实现要点：用独立的 `translate` 属性而不是 `transform` 做位移。
   transform 被 hover 的 translateY(-4px) 占用了，两者混在一个属性上会
   互相覆盖；`translate` 是独立属性，可以和 transform 叠加，互不干扰。

   生命周期：
     head 同步脚本打上 html.bz-js → 首帧前元素已是「待入场」态（不闪）
     DOMContentLoaded  → 给所有目标加 .bz-reveal，随即摘掉 html.bz-js
     IntersectionObserver → 进入视口时加 .bz-in
     兜底定时器 → 无论如何 2.5s 后全部显示
   -------------------------------------------------------------------------- */
html.bz-js :is(.module,.price-card,.t-card,.ch-card,.stat,.faq-item){
  opacity:0;
  translate:0 18px;
}
.bz-reveal:not(.bz-in){
  opacity:0;
  translate:0 18px;
}
.bz-reveal.bz-in{
  opacity:1;
  translate:0 0;
}
/* 兜底开关：只要 <html> 带上 .bz-done，所有内容立即完全显示。
   观察器出问题、脚本被拦截、或者浏览器不支持动画时，靠这条保证不留白屏。 */
html.bz-done :is(.module,.price-card,.t-card,.ch-card,.stat,.faq-item){
  opacity:1 !important;
  translate:none !important;
}

/* 组件过渡属性统一收口：补上 opacity / translate 两条 */
.module,.price-card,.t-card,.ch-card,.stat,.faq-item,.jumpnav a{
  transition-property:transform,border-color,box-shadow,background,color,opacity,translate,filter;
  transition-duration:var(--bz-dur),var(--bz-dur),var(--bz-dur),var(--bz-dur),var(--bz-dur),.6s,.6s,var(--bz-dur);
  transition-timing-function:var(--bz-ease);
}

@media (prefers-reduced-motion:reduce){
  html.bz-js :is(.module,.price-card,.t-card,.ch-card,.stat,.faq-item),
  .bz-reveal:not(.bz-in),
  .bz-reveal.bz-in{
    opacity:1 !important;
    translate:none !important;
  }
  .module:hover,.price-card:hover,.ch-card:hover,.stat:hover,.t-card:hover{transform:none !important}
  .module:hover .module-icon{transform:none !important}
  .module::before{transition:none !important}
}

/* --------------------------------------------------------------------------
   3.2c reduce 的**覆盖补全**（2026-10-05 第 11 轮实测）
   --------------------------------------------------------------------------
   第 11 轮用两种**行为**探针量了一遍 reduce（真鼠标悬停 + 加载后时间序列）：
     · 站点原有 28 个 reduce 块覆盖了「入场动画 + 5 张卡片 hover」，
       但**漏了 20 个 hover 位移**（.logo/.nav-cta/.btn-primary/.btn-ghost/
       .gl-card -5px/.ch-hl-swatch scale 1.12/.cc-fab -2px+1.04/.mjg-tile-live
       -8px … 全部实测仍在动）。
     · `html{scroll-behavior:smooth}`（style.css:16）**完全没有 reduce 覆盖**：
       course-tenpai 从顶部滚到页脚，scrollY 在 580ms 内经过 39 → 526 → 5419
       （index：38 → 492 → 6135），**reduce 与 no-preference 逐位相同**。
       长页面滚动数千像素，正是 WCAG 2.3.3 要管的那类运动。

   ⚠ **不能一律写 transform:none**：`.nav-top-cap.returning` 与
   `.rating-summary .rating-detail` 的 hover 里夹着**定位用的 translateX(-50%)**，
   一律 none 会把它们挪到错误位置（把「减少运动」修成「布局错位」）。
   这两个单独用它们自己的静止态 transform 覆盖。

   另：`:active` 的按压反馈（scale .94~.98）**有意不覆盖** —— 它是 <150ms 的
   触觉确认，不是持续位移；而且 `.nav-top-cap.returning:active` 同样夹着居中用的
   translateX(-50%)，覆盖的收益远小于弄错位置的风险。
   -------------------------------------------------------------------------- */
@media (prefers-reduced-motion: reduce){
  /* 平滑滚动关掉（style.css:16 同特异性、本文件靠后，加 !important 更稳） */
  html{scroll-behavior:auto !important}

  /* hover 位移归零。这些元素的静止态 transform 实测全是 none ⇒ 安全。 */
  .logo:hover,
  .nav-links a.nav-cta:not(.nav-bold):hover,
  .btn-primary:hover,
  .btn-ghost:hover,
  .jumpnav a:hover,
  .btn-cta-gold:hover,
  .vip-btn:hover,
  .vip-sect-lock:hover,
  .vip-sect-lock:hover .vsl-btn.semi,
  .gallery .gl-card:hover,
  .ch-hl-swatch:hover,
  .m2m-expand-all:hover,
  .tier-apply:hover,
  .cmp-adopt:hover,
  .m2m-preview-restore:hover,
  .coach-confirm-ok:hover,
  .chapter-coach .cc-fab:hover,
  .learn-ch:hover,
  .mjg-tile-live:hover,
  .mjg-tile-live:focus-visible,
  .nav-top-cap:not(.returning):hover{transform:none !important}

  /* 这两个的 hover 里夹着定位用的 translateX(-50%)：只去掉位移那一半 */
  .nav-top-cap.returning:hover{transform:translateX(-50%) !important}
  .rating-summary:hover .rating-detail,
  .rating-summary:focus-within .rating-detail{transform:translateX(-50%) !important}

  /* 下划线是**状态指示**，不能去掉 —— 只能让它瞬间出现，别「长出来」 */
  .nav-links a::after{transition:none !important}
}

/* --------------------------------------------------------------------------
   3.4  响应式微调
   -------------------------------------------------------------------------- */
@media (max-width:900px){
  .module-icon{min-width:48px;min-height:48px;padding:7px;border-radius:13px}
  .section-title::after{width:52px;margin-top:11px}
}
@media (max-width:640px){
  .hero .hero-box{padding:30px 20px !important}
  .section-title::after{width:44px;height:2.5px}
  .section-sub{font-size:14.5px !important}
  .module{padding:20px !important}
  .module-icon{min-width:44px;min-height:44px;padding:6px;border-radius:12px}
  .btn{padding:11px 18px}

  /* 宽表格：course-traces 的 .matrix 是 5 列中文速查表，th 又被写死
     white-space:nowrap，390px 下表格撑到 407px，把整页顶出横向滚动条
     （实测 vw=390 / scrollW=423，溢出 33px）。这是原站遗留 —— 对照实验
     （临时移开本文件）同样溢出，scrollW=417。

     处理：让表格自己变成横向滚动容器，而不是把整页顶宽。display:block 之后
     tbody/tr/td 的 display 值不变，浏览器仍会生成匿名表格盒，所以表格外观
     保持原样，只是外面多了一个可横向滚动的块。 */
  table.matrix{display:block;overflow-x:auto;max-width:100%;-webkit-overflow-scrolling:touch}
}
@media (max-width:420px){
  .module-icon{min-width:40px;min-height:40px}
  .logo-text{font-size:18px}
}

/* --------------------------------------------------------------------------
   3.5  打印：去掉装饰，只留内容
   -------------------------------------------------------------------------- */
@media print{
  /* ------------------------------------------------------------------------
     打印 = 黑字白纸（2026-10-05 第 11 轮补全）
     ------------------------------------------------------------------------
     实测：course-tenpai 在 print 下，**浅色主题 0 项不达标 / 深色主题 35 项不达标**
     （checked 489）。正文 rgba(255,255,255,.8) 在白纸上 = **1.00:1**、h1 1.14、
     金色 h2 1.42。根因：站点**默认主题就是深色**（:root 的 --text:#f0f0f5），
     而浏览器**默认不打印背景** ⇒ 白纸 + 近白字 = 一片空白。
     原 print 块只做了「隐藏装饰伪元素 + 卡片改白底」，一个字都没改颜色 ——
     白底卡片里的浅色文字反而更看不见。
     ------------------------------------------------------------------------ */

  /* 1) 黑字白纸。background 简写会一并清掉 body 的深色渐变。
     ----------------------------------------------------------------------
     ⚠ 通配为什么把 :root[data-theme] 写了**两遍**？—— 为了**抬特异性**，不是笔误。
     2026-10-05 第 11 轮实测：全站有 64 条带 !important 的裸 color 声明，
     其中 **53 条特异性高于 body * 的 (0,0,1)**。按特异性分档：
       (0,1,0)  .section-sub / .btn-primary / .nav-cta / .pf-ans …
       (0,1,1)  .chapter th / td
       (0,2,0)  .t-card .before / .after            （深色主题的徽标）
       (0,2,1)  .hero .hero-box h1 / p / li / small
       (0,3,0)  .hero .hero-box .sub
       (0,4,0)  :root[data-theme="light"] .t-card .before / .after
       (0,4,1)  :root[data-theme="light"] .hero .hero-box h1 / p
     ⇒ 只写 body * 会**一个都盖不住**（实测残留 8 项：index 5 + pricing 3）。
     :root[data-theme]:root[data-theme] body * = (0,4,1)，一次覆盖上表全部。
     ID 选择器（#chatInput / #micBtn / #compareBtn）通配永远压不过 ——
     实测它们**只存在于 CSS**，HTML 与 js/ 零引用（死 CSS），不影响打印。
     text-shadow 一并清掉：深色主题的 h1 带 rgba(0,0,0,.8) 阴影，黑字配黑阴影会糊。 */
  html,body{background:#fff !important}
  :root[data-theme]:root[data-theme] body,
  :root[data-theme]:root[data-theme] body *{color:#111 !important;text-shadow:none !important;
    -webkit-text-fill-color:currentColor !important}   /* 堵住 background-clip:text 的透明字 */

  /* 2) 补回两种有语义的强调色（纯黑白会丢掉标题层级与链接可辨性）。
     这几条也必须抬到与通配**同级或更高**，否则会被上面那条压掉。 */
  :root[data-theme]:root[data-theme] body .chapter h2,
  :root[data-theme]:root[data-theme] body .chapter h3,
  :root[data-theme]:root[data-theme] body .chapter h4,
  :root[data-theme]:root[data-theme] body .section-title{color:#6b4e0a !important}
  :root[data-theme]:root[data-theme] body a{color:#0b4a8f !important;text-decoration:underline}
  :root[data-theme]:root[data-theme] body strong,
  :root[data-theme]:root[data-theme] body b{color:#000 !important}
  /* 表头/单元格：既有规则带 !important 且特异性到 (0,4,1)
     （beautify.css:448/456 的 .chapter th/td、:867/869 的浅色变体、:956 的 hc 变体），
     所以这里必须**更高 + 靠后**才盖得住。 */
  :root[data-theme]:root[data-theme] .chapter th{color:#3a2c05 !important}
  :root[data-theme]:root[data-theme] .chapter td{color:#111 !important}

  /* 3) 隐藏交互壳：纸上点不了，只会占地方 */
  .nav,.nav-top-cap,.bz-totop,.m2m-toast-hist-btn,.m2m-toast,.m2m-pin-banner,
  .m2m-preview-bar,.m2m-layout-switch,.chapter-coach,.cc-fab,
  #navDrawer,#drawerOverlay,.drawer-overlay,#tocDrawer{display:none !important}

  /* 4) 装饰性伪元素与入场位移 */
  body::before,.footer::before,.module::before,.section-title::after{display:none !important}
  .bz-reveal{opacity:1 !important;transform:none !important;translate:none !important}

  /* 5) 卡片 / 表格改白底黑边，去掉阴影 */
  .module,.price-card,.t-card,.faq-item,.ch-card,.stat,.chapter table,th,td,
  .dr-area,.dr-qhead,.dr-tile,.mjg-tile{
    box-shadow:none !important;background:#fff !important;border-color:#bbb !important;
  }
  th{background:#f2efe6 !important}
  thead{display:table-header-group}   /* 跨页时重复表头 */

  /* 6) 别把卡片/表格/图切断在两页之间 */
  table,tr,img,.module,.price-card,.t-card,.faq-item,.dr-tile{break-inside:avoid}
  h1,h2,h3,h4{break-after:avoid}
}


/* ===== 页脚导航与联系方式（新增） ===== */
/* 注意：footer 的底色分主题 ——
   深色主题：深底（style.css 的 ::after 黑色遮罩 + 背景图）→ 用浅色文字
   浅色主题：本文件 803 行已把它改成浅米色底 → 必须换深色文字
   （实测：浅色主题下 audit 报 rgba(255,255,255,.78) 对比度仅 1.15） */
.footer-links{display:flex;flex-wrap:wrap;justify-content:center;gap:6px 18px;margin-top:14px;font-size:13px;line-height:1.6}
.footer-links a{color:rgba(255,255,255,.78);text-decoration:none;border-bottom:1px solid transparent;transition:color .2s,border-color .2s}
.footer-links a:hover{color:#e8c96a;border-bottom-color:rgba(232,201,106,.55)}
.footer-mail{font-size:13px;color:rgba(255,255,255,.72)}
.footer-mail a{color:#e8c96a;text-decoration:none}
.footer-mail a:hover{text-decoration:underline}

/* ==========================================================================
   WCAG 1.4.1 Use of Color —— 正文行内链接不能只靠颜色区分
   --------------------------------------------------------------------------
   实测（第 16 轮）：全站 42 页 × 6 配置，1242 个「正文行内链接」里 1230 个没有
   任何非颜色通道 —— 其中 1062 个链接的颜色与周围正文**完全相同**（ΔE=0），
   其余 168 个仅靠颜色、与正文对比最低 1.00:1（404.html 的「联系我们」）。
   根因：style.css:70 的 a{color:inherit;text-decoration:none}
   ⇒ 屏幕上正文链接和正文长得一模一样，只有鼠标悬停才分得出。
   （反证：beautify.css 里 @media print 早就补了下划线 ⇒ 这是 screen-only 的漏网。）

   修法：补一条下划线（非颜色通道），**不动配色** —— 不动颜色就不引入新的对比度风险。
   范围精确到「正文容器里没有 class 的 <a>」：
     · 卡片 / 按钮 / CTA / 导航一律带 class（btn、nav-cta、logo、ac-hub-card），
       被 :not([class]) 排除；
     · .chapter-nav 的「上一课 / 下一课」是带底色的卡片式链接（display:block），
       本就不属于「正文行内链接」，显式排除。
   ========================================================================== */
article.chapter a:not([class]):not(.chapter-nav a),
section.section a:not([class]),
.footer-mail a:not([class]){
  text-decoration:underline;
  text-decoration-color:currentColor;
  text-decoration-thickness:1px;
  text-underline-offset:2px;
}
.footer > p{color:rgba(255,255,255,.78)}

/* 浅色主题：footer 是浅米色底（#f3ead6），文字全部换成深色 */
:root[data-theme="light"] .footer-links a{color:#6f5410}
/* ★ 第 18 轮修：原 hover 色 #8a6c1c 压在页脚底 #f3ead6 上只有 4.14（< 4.5）——
   hover 把文字从深金 #6f5410 换成亮金，方向反了。改为加深 #4a3a0c = 9.23。
   （全站 44 页 × 5 个页脚链接；静态面测不出，只有 hover-audit.js 能报。） */
:root[data-theme="light"] .footer-links a:hover{color:#4a3a0c;border-bottom-color:rgba(74,58,12,.5)}
:root[data-theme="light"] .footer-mail{color:#6b6249}
:root[data-theme="light"] .footer-mail a{color:#6f5410}
:root[data-theme="light"] .footer > p{color:#6b6249}

:root[data-theme="light"][data-hc="on"] .footer-links a,
:root[data-theme="light"][data-hc="on"] .footer-mail,
:root[data-theme="light"][data-hc="on"] .footer > p{color:#4a3a0c}
:root[data-theme="light"][data-hc="on"] .footer-mail a{color:#6f5410}
@media(max-width:640px){
  .footer-links{gap:4px 12px;font-size:12px}
  .footer-mail{font-size:12px}
}

/* ===== 合伙人制度文档块 ===== */
.referral-doc{background:rgba(212,175,55,.05);border:1px solid rgba(212,175,55,.25);border-radius:12px;padding:18px 22px;margin-top:16px}
:root[data-theme="light"] .referral-doc{background:rgba(168,128,31,.05);border-color:rgba(168,128,31,.28)}

/* ==========================================================================
   移动端体验层  (mobile experience)
   --------------------------------------------------------------------------
   目标不是「能看」，而是「顺手」——手指点得准、输入不被放大、贴边不撞刘海、
   滚动不穿透。以下每条都对应一次实测发现，不是凭感觉加的。

   实测依据（390×844，deviceScaleFactor=2，Chrome CDP 设备仿真）：
     · 页脚导航链接 48×20px   —— 高度只有 20，远低于 44 的触摸目标下限
     · a.logo        128×32px —— 高度 32
     · #themeToggle / #hcToggle / #navHamburger 均为 38px（style.css 原值）
     · #navDrawerClose 32px、.m2m-toast-hist-btn 34px、.nav-top-cap 约 36px
     · 邀请链接输入框 font-size:13px —— iOS Safari 在 <16px 时会自动放大整页
     · .footer 在 ≤640px 断点用 padding:30px 16px 24px 覆盖掉了桌面版的
       env(safe-area-inset-bottom)，横屏/全面屏底部会贴到 home indicator
   ========================================================================== */

/* ---- 1. 点按手感 ---------------------------------------------------------- */
/* 去掉 iOS/Android 点击时那层灰色高亮块，改由各组件自己的 :active 反馈负责 */
a,button,summary,[role="button"],input,select,textarea,label{
  -webkit-tap-highlight-color:transparent;
}
/* manipulation 关掉双击缩放的等待，消除约 300ms 的点按延迟 */
a,button,summary,[role="button"]{touch-action:manipulation}
/* iOS 横屏时不要自作主张放大正文字号 */
html{-webkit-text-size-adjust:100%;text-size-adjust:100%}
/* 长链接/长单词不撑破卡片 */
.module,.price-card,.note,.hero-box,.referral-doc,.footer{overflow-wrap:break-word}

/* ---- 2. 汉堡图标（用 CSS 画三条线，不引外部图标）------------------------- */
.nav-burger{position:relative;display:block;width:18px;height:2px;border-radius:2px;background:currentColor}
.nav-burger::before,.nav-burger::after{
  content:"";position:absolute;left:0;width:18px;height:2px;border-radius:2px;background:currentColor;
}
.nav-burger::before{top:-6px}
.nav-burger::after{top:6px}

/* ---- 3. 导航抽屉 ---------------------------------------------------------- */
/* 关闭状态除了平移出屏，还要 visibility:hidden —— 否则它仍在无障碍树里，
   读屏用户会念到一串「看不见的」链接，Tab 也会跑进去。 */
#navDrawer{visibility:hidden;transition:transform .32s cubic-bezier(.34,1.56,.64,1),visibility .32s}
#navDrawer.open{visibility:visible}
/* 让链接列表吃掉剩余高度并自己滚动，底部留出 home indicator 的空间。
   注意 flex-wrap:nowrap 不能省：基础规则 .nav-links{flex-wrap:wrap} 是给桌面版
   横向排列用的，在抽屉里（flex-direction:column + 有高度约束）会退化成**多列**
   —— 实测 33 条链接被折成 2 列。必须显式 nowrap 才会变成单列纵向滚动。 */
#navDrawer .nav-links{
  flex:1;min-height:0;flex-wrap:nowrap;justify-content:flex-start;
  overscroll-behavior:contain;
}
.nav-drawer-sec{
  margin:14px 6px 4px;font-size:12px;font-weight:800;
  letter-spacing:.06em;color:var(--text-m);
}
.nav-drawer-sec:first-child{margin-top:2px}
/* 抽屉里的「当前页」标记（style.css 只给桌面版写了 .active） */
#navDrawer .nav-links a.active{
  background:linear-gradient(135deg,rgba(212,175,55,.22),rgba(212,175,55,.08));
  color:var(--gold2) !important;font-weight:700;
}
:root[data-theme="light"] #navDrawer .nav-links a.active{
  background:linear-gradient(135deg,rgba(168,128,31,.20),rgba(168,128,31,.07));
}
/* 遮罩不参与滚动手势，避免在遮罩上滑动时把后面的页面滚起来 */
#drawerOverlay{touch-action:none}

/* ---- 4. 邀请链接输入框 ---------------------------------------------------- */
/* 原来是一段内联样式：font-size:13px（触发 iOS 缩放）+ background:rgba(0,0,0,.3)
   （深色底，浅色主题下像一块补丁）。这里改成按主题走的类。 */
.ref-input{
  flex:1;min-width:200px;padding:12px 14px;border-radius:10px;font-size:16px;
  background:rgba(0,0,0,.3);border:1px solid var(--border-a);color:var(--gold2);
}
:root[data-theme="light"] .ref-input{
  background:rgba(0,0,0,.06);border-color:rgba(168,128,31,.35);color:#6f5410;
}
:root[data-theme="light"][data-hc="on"] .ref-input{color:#4a3a0c}
.referral-actions{display:flex;gap:8px;flex-wrap:wrap;margin-top:14px}

/* ---- 5. 移动端：触摸目标 / 安全区 / 输入字号 ------------------------------ */
@media(max-width:640px){

  /* -- 5.1 导航按钮：38px → 44px（iOS HIG 与 Material 的共同下限） -- */
  #themeToggle,#hcToggle,#navHamburger{width:44px !important;height:44px !important}
  #themeToggle{font-size:19px !important}
  #hcToggle{font-size:15px !important}
  .logo{min-height:44px;min-width:0;flex:0 1 auto;overflow:hidden}
  .logo-text{min-width:0;flex:0 1 auto}
  /* 320px 的窄屏（iPhone SE 一代）靠让标题收缩来避免整行溢出 */
  .nav-tools{margin-left:4px}
  .nav-tools{gap:4px}

  /* -- 5.2 抽屉：关闭按钮 32→44，底部避开 home indicator -- */
  #navDrawerClose{width:44px !important;height:44px !important;font-size:18px !important}
  #navDrawer .nav-links{padding-bottom:calc(18px + env(safe-area-inset-bottom,0px))}
  #navDrawer .nav-links a{min-height:44px;display:flex;align-items:center}

  /* -- 5.3 页脚：20px 高的小链接 → 44px，并找回被断点吃掉的 safe-area -- */
  .footer{padding-bottom:calc(24px + env(safe-area-inset-bottom,0px)) !important}
  .footer-links{gap:0 8px}
  .footer-links a{
    display:inline-flex;align-items:center;justify-content:center;
    min-height:44px;padding:0 10px;font-size:13px;
  }
  .footer-mail a{display:inline-flex;align-items:center;min-height:44px;padding:0 4px}

  /* -- 5.4 ↑Top 胶囊（nav-hide.js 动态创建）：约 36px → 44px -- */
  .nav-top-cap{min-height:44px;padding:11px 18px !important}
  .nav-top-cap.returning{bottom:calc(16px + env(safe-area-inset-bottom,0px))}

  /* -- 5.5 提示历史按钮 34→44 -- */
  .m2m-toast-hist-btn{width:44px !important;height:44px !important;font-size:17px !important}

  /* -- 5.6 邀请区的分享按钮：约 37px → 44px -- */
  .referral-actions .btn{min-height:44px;padding:11px 16px !important;font-size:14px !important}

  /* -- 5.6b 其余主按钮：.btn 的基础 padding(12px 22px) 实测只有 41px 高 -- */
  .btn{min-height:44px}

  /* -- 5.7 输入框字号：iOS Safari 对 <16px 的输入框会自动放大整个页面 -- */
  input:not([type="checkbox"]):not([type="radio"]):not([type="range"]),
  textarea,
  select{font-size:16px}
  .ref-input{font-size:16px}
  /* 交互计算页把表单字号写死成 14px（.field input,.field select），
     选择器优先级比上面的裸 select 高，必须同等优先级压过去
     （beautify.css 在页面内联 <style> 之后加载，同级即胜出）。 */
  .field input,.field textarea,.field select{font-size:16px}

  /* -- 5.8 章节上/下一页：实测 358×41，高度差 3px -- */
  .chapter-nav a{
    display:flex;align-items:center;justify-content:center;min-height:44px;
  }

  /* -- 5.9 折叠标题 <summary>：实测 312×24（「查看完整四步」「答案」）-- */
  /* 用 padding 而不是 flex：flex 会吃掉 <summary> 原生的三角标记。
     .faq-item summary 本身已 ≥44px，且已有自定义箭头，排除掉免得叠加内边距。 */
  details:not(.faq-item) > summary{
    min-height:44px;padding-top:10px;padding-bottom:10px;box-sizing:border-box;
  }

  /* -- 5.10 宽表格：让它自己横向滚动，而不是把整页撑宽 -- */
  /* 实测 course-scoring.html 里那张符数/翻数对照表最小内容宽度 562px，
     超过 390 的设备宽度后，浏览器会把**布局视口**整体撑到 578px 并缩放显示
     整页 —— 正文跟着一起变小，是手机端最伤可读性的一种溢出。
     给 table 加 display:block + overflow-x:auto 后，行/单元格仍会由浏览器生成
     匿名表格盒正常渲染，但多出来的宽度变成表内滚动条。
     （站点原本有一套 .tbl-cards 卡片化方案，但那需要 mobiletables.js 参与，
       40 个页面都没加载它；这条是不依赖脚本的兜底。
       ⚠ 2026-10-03 第 2 轮：mobiletables.js 已被删除（41 页零加载，且已有下面这条
       不依赖脚本的兜底）。别再去找那个文件。） */
  .chapter table{
    display:block;overflow-x:auto;overflow-y:hidden;
    max-width:100%;-webkit-overflow-scrolling:touch;
  }

  /* -- 5.11 训练器控制按钮：.dr-newbtn 39px、.hq-btn 41px -- */
  .dr-newbtn,.hq-btn{
    display:inline-flex;align-items:center;justify-content:center;min-height:44px;
  }
}

/* ==========================================================================
   移动端体验层的「能力查询」副本（横屏手机 / 平板）
   --------------------------------------------------------------------------
   上面那一整套 44px 规则写在 @media(max-width:640px) 里，判据是**宽度**。
   但**横屏手机的宽度是 667 ~ 844**，够不到那个断点 —— 于是又退回
   38×38 的导航按钮、20px 高的页脚链接。实测 667×375 横屏下
   .nav-tools button 仍是 38×38、.footer-links a 仍是 20px 高。

   正确判据是「能力」而不是「宽度」：pointer:coarse 表示主指针是手指，
   hover:none 表示没有悬停能力 —— 合起来就是「这是触摸设备」。
   这条查询和设备宽度无关，所以横屏手机、竖屏平板都能命中。

   这里只放**与宽度无关**的部分（触摸目标尺寸、输入框字号）。
   抽屉相关的规则不搬过来：抽屉本身只在 ≤640px 存在，横屏走的是桌面导航。

   顺带解决一个 iOS 的老问题：Safari 在 iPad 上同样会因为输入框字号 < 16px
   而放大整页，和 iPhone 一样。
   ========================================================================== */
@media (hover:none) and (pointer:coarse){
  #themeToggle,#hcToggle,#navHamburger{width:44px !important;height:44px !important}
  .footer-links a{display:inline-flex;align-items:center;justify-content:center;min-height:44px;padding:0 10px}
  .footer-mail a{display:inline-flex;align-items:center;min-height:44px;padding:0 4px}
  .nav-top-cap{min-height:44px;padding:11px 18px !important}
  .m2m-toast-hist-btn{width:44px !important;height:44px !important}
  .btn{min-height:44px}
  .referral-actions .btn{min-height:44px}
  .chapter-nav a{display:flex;align-items:center;justify-content:center;min-height:44px}
  details:not(.faq-item) > summary{min-height:44px;padding-top:10px;padding-bottom:10px;box-sizing:border-box}
  .dr-newbtn,.hq-btn{display:inline-flex;align-items:center;justify-content:center;min-height:44px}
  input:not([type="checkbox"]):not([type="radio"]):not([type="range"]),textarea,select{font-size:16px}
  .ref-input{font-size:16px}
  .field input,.field textarea,.field select{font-size:16px}
}

/* ==========================================================================
   浅色主题：深色硬编码面板的可读性修复
   --------------------------------------------------------------------------
   三个交互页（course-reading / drills / heqie-trainer）把「内嵌面板」的底色
   写死成 rgba(0,0,0,.22~.28)，那是按深色主题设计的。切到浅色主题后，半透明黑
   叠在米色底上变成**中灰块**，面板里用的 --text-m / var(--green) / 硬编码 #ff9ca4
   在中灰上全部不达标（WCAG AA 正文需 4.5:1）。

   实测（浅色 @1440，audit.js 输出）：
     1.52:1  span「他家副露：」   #ff9ca4 on rgb(238,222,214)
     2.48:1  .rd-item.rd-gen       var(--green) on rgb(159,183,169)
     2.58:1  .rd-col em            var(--text-m) on rgb(172,169,162)
     2.87:1  .rd-cl-lb/.rd-none/.rd-mn  var(--text-m) on rgb(181,178,171)
     2.98:1  .rd-item.rd-suji      var(--gold2) on rgb(188,182,164)
     3.18:1  .dr-tab-*             var(--gold2) on rgb(195,188,167)
     2.97:1  .hq-stat-n            var(--gold2) on rgb(186,182,170)

   做法：浅色主题下把这些面板换成「浅色内嵌底」，面板内的弱化文字改用 --text-d。
   深色主题完全不受影响（所有规则都限定在 [data-theme="light"]）。
   ========================================================================== */

/* --- 1) 面板底色：中灰 → 浅内嵌底 ---------------------------------------- */
/* 只改「里面装文字」的面板。.rd-river 里只有牌面（无文字），
   原设计用深底正是为了让米色牌凸显出来，改浅反而削弱辨识度 —— 所以保持不动，
   和 drills.html 的 .dr-hand 牌桌一致。 */
:root[data-theme="light"] .rd-cl,
:root[data-theme="light"] .rd-summary{background:rgba(23,16,6,.055)}
:root[data-theme="light"] .rd-tile{box-shadow:0 2px 5px rgba(120,90,20,.22)}
:root[data-theme="light"] .dr-tabs{background:rgba(23,16,6,.05)}
:root[data-theme="light"] .hq-stat{background:rgba(23,16,6,.05)}

/* --- 2) 面板内的弱化文字：--text-m(#8a826e, 3.4:1) → --text-d(#5a523f, 6.9:1) --- */
:root[data-theme="light"] .rd-desc,
:root[data-theme="light"] .rd-cl-lb,
:root[data-theme="light"] .rd-none,
:root[data-theme="light"] .rd-mn,
:root[data-theme="light"] .dr-tab,
:root[data-theme="light"] .hq-stat-l{color:var(--text-d)}

/* 牌河面板在浅色主题下仍是深灰「桌面」（见上面的说明），所以压在它上面的
   「N巡」巡目标签不能跟着用 --text-d —— 实测深灰底上只有 3.29:1。
   改用与牌面数字同一个近黑色，实测 6.83:1。 */
:root[data-theme="light"] .rd-col em{color:#2a2110}

/* --- 3) 牌河安全度色标：浅底上的深色版本 --------------------------------- */
/* 这三个色标在深色主题里用的是亮色（--green 亮薄荷 / --gold2 / --orange），
   叠在浅色 chip 底上只有 3.5~4.1:1。这里换成同色系的深色版本，
   实测（浅色 @1440）：
     .rd-gen  #076247 on rgb(205,212,200) → 4.87:1  ✓（原 #0b7a5c 3.52:1）
     .rd-no   #8a4708 on rgb(229,216,197) → 5.01:1  ✓（原 #a55a10 3.67:1）
     .rd-suji #6b5314 on rgb(220,211,191) → 4.93:1  ✓（原 #78601a 4.05:1） */
:root[data-theme="light"] .rd-gen,
:root[data-theme="light"] .rd-item.rd-gen{color:#076247}
:root[data-theme="light"] .rd-item.rd-gen{
  background:rgba(11,122,92,.10);border-color:rgba(11,122,92,.35);
}
:root[data-theme="light"] .rd-suji,
:root[data-theme="light"] .rd-item.rd-suji{color:#6b5314}
:root[data-theme="light"] .rd-item.rd-suji{
  background:rgba(168,128,31,.12);border-color:rgba(168,128,31,.38);
}
:root[data-theme="light"] .rd-no,
:root[data-theme="light"] .rd-item.rd-no{color:#8a4708}
:root[data-theme="light"] .rd-item.rd-1suji{
  background:rgba(23,16,6,.045);border-color:rgba(180,140,50,.35);
}
/* 粉：硬编码 #ff9ca4 是深色底专用，浅底换成同色系深红 */
:root[data-theme="light"] .rd-dang,
:root[data-theme="light"] .rd-melds>span:first-child{color:#b3261e}
:root[data-theme="light"] .rd-item.rd-dang{
  background:rgba(179,38,30,.09);border-color:rgba(179,38,30,.32);
}

/* ==========================================================================
   浅色主题：半透明「白/黑」内嵌面的统一修正
   --------------------------------------------------------------------------
   站内交互组件大量使用两种硬编码半透明面：
     · rgba(255,255,255,.04~.10) —— 深色底上的「浅色浮层」（进度轨、字母徽标、键帽）
     · rgba(0,0,0,.22~.28)       —— 深色底上的「下沉面」（计算条、键值面板）
   深色主题下这两类都正常。切到浅色主题后：
     · 白色浮层比周围**更白** → 轨道/徽标与背景糊在一起，直接看不见。
       这类问题对比度检测**查不出来**（浅底 + 深字反而对比度更高），只有截图能发现。
     · 黑色下沉面 → 变成中灰块，上面的 --text-m 只有 2.9:1，读不清。
   统一改成「深色低透明度」的内嵌面，浅色主题下的层级关系才成立。
   注意：其中一部分类由 JS 运行时生成（drills-ui.js / probability-ui.js 等），
   静态 HTML 里查不到，是按 CSS 定义逐个对照修的。
   ========================================================================== */

/* 1) 首页进度条轨道（写在内联 style 上，只能用属性选择器 + !important 命中） */
:root[data-theme="light"] [style*="background:rgba(255,255,255,0.08)"]{
  background:rgba(23,16,6,.10) !important;
}

/* 2) 白色浮层 → 深色内嵌面 */
:root[data-theme="light"] .dr-bar,
:root[data-theme="light"] .dr-progress,
:root[data-theme="light"] .dr-opt-letter,
:root[data-theme="light"] .dr-opt-l,
:root[data-theme="light"] .kbd,
:root[data-theme="light"] .dr-calc span,
:root[data-theme="light"] .pu-insufficient{background:rgba(23,16,6,.07)}

/* 3) 黑色下沉面 → 浅内嵌面 */
:root[data-theme="light"] .dr-calc,
:root[data-theme="light"] .pu-kv{background:rgba(23,16,6,.05)}

/* 4) 弱化徽标：--text-m(#8a826e, 3.4:1) → --text-d(#5a523f, 6.9:1) */
:root[data-theme="light"] .dr-badge-dim,
:root[data-theme="light"] .hq-badge-dim{color:var(--text-d)}

/* 5) 状态徽标/结论文字：深色底专用的亮色在浅底上读不了 */
/*    #7ab6ff 亮蓝 → #1f6fd0；#f59c3c 亮橙 → #a85510；
       var(--red)#e63946 on 浅粉底 3.25:1 → #b3261e；
       var(--gold2)#8a6c1c on 浅黄底 4.28:1 → #6f5410 */
:root[data-theme="light"] .dr-badge-blue{color:#1f6fd0}
:root[data-theme="light"] .pu-warning .pu-verdict-text{color:#a85510}
:root[data-theme="light"] .pu-critical .pu-verdict-text{color:#b3261e}
:root[data-theme="light"] .pu-watch .pu-verdict-text{color:#6f5410}

/* ---------------------------------------------------------------------------
   6) 全站复测后仍卡在门槛下的三处小字
   ---------------------------------------------------------------------------
   这三处都在**页面内联 <style>** 里（不是 style.css），用 var(--green) /
   var(--gold2)。上面那段变量覆盖已经把亮绿 #06d6a0 从 1.65:1 提到 4.08:1、
   亮金 #f5d76e 从 2.4:1 提到 4.38:1，但都还差最后一点点（门槛 4.5）。

   为什么不动全局变量：--green 在 4 处被当**背景色**用
   （如 .dr-opt.dr-ok .dr-opt-letter{background:var(--green);color:#062}），
   再压深就会变成「深字压深底」——把一处修好、另一处弄坏。
   所以这里按元素定点压深，色相不变。

   实测：
     .bg-ex-ok .bg-ex-badge  #067a5c on rgb(206,232,215) → 4.08   → #056b51 5.00 ✓
     .mid-star               #78601a on rgb(225,219,206) → 4.38   → #6b5314 5.30 ✓
   #6b5314 与浅色主题下 .rd-suji 用的是同一个值，色板保持一致。
   --------------------------------------------------------------------------- */
:root[data-theme="light"] .bg-ex-ok .bg-ex-badge{color:#056b51}
:root[data-theme="light"] .mid-star{color:#6b5314}
/* 第三处是**伪元素**（::before），2026-10-05 第 10 轮补上 —— 量具原来遍历
   querySelectorAll，伪元素一个都测不到，所以前几轮一直没发现它。

   ⚠ 这一批补丁的第一版把选择器写成了 .price-card，**打错了目标**：
     pricing.html 里根本没有 .price-card 容器，它用的是 .plans / .plan
     （第二段内联 <style>，位置在所有 <link> **之后**）；页内那份
     .price-card 规则是从别的页抄过来的死代码。所以第一版写完复测仍是
     4.45 —— 规则没命中任何元素。**改完必须复测，规则「写进去了」不等于
     「生效了」。**

   真正失败的是：
     pricing.html  .plan li::before{content:"\2713"} 的 ✓ 用 var(--green)
       #067a5c on rgb(239,235,225) → 4.45（普通浅色）
       #067a5c on rgb(232,231,230) → 4.31（高对比模式）
   .price-card 那一支（index.html / checkout.html 各有一份同样的内联规则）
   是同一个 var(--green) 模式，一并收进同一条规则，改用与上面两处同一个
   #056b51（实测：pricing 5.46 / 5.27，index+checkout 6.40 / 5.46）。 */
:root[data-theme="light"] .price-card li::before,
:root[data-theme="light"] .plan li::before{color:#056b51}

/* ---------------------------------------------------------------------------
   7) 听牌训练页的听牌形徽标（course-tenpai.html 的页面内联样式）
   ---------------------------------------------------------------------------
   .tp-g-worst 的字色是**写死的浅粉 #ff9ca4**（深色主题专用），压在同样浅的
   粉底上只有 1.43:1 —— 和痕迹逆向页的 .win / .tr-tag 是同一个毛病：
   深色底专用的亮色被硬编码，浅色主题下就废了。改用 #b3261e，实测 4.68:1。

   .tp-g-best 用 var(--green)，上面第 6 段已经把它压到 #067a5c，但在这种
   偏绿的浅底上仍只有 4.08；这里再压一档到 #056b51（与 .bg-ex-badge 同值），
   实测 5.34:1。

   .tp-g-mid（var(--gold2) #78601a on rgb(239,232,210)）实测 4.92:1，达标，不动。
   --------------------------------------------------------------------------- */
:root[data-theme="light"] .tp-g-worst{color:#b3261e}
:root[data-theme="light"] .tp-g-best{color:#056b51}

/* ---------------------------------------------------------------------------
   8) 页脚顶边线：原版写成了不存在的变量
   ---------------------------------------------------------------------------
   style.css:520 是 `.footer{...;border-top:1px solid var(--222);...}`。
   `--222` **从未定义、也没有兜底值**，所以这条 shorthand 整条非法被丢弃 ——
   `border-top-style` 回到初始值 `none`，**页脚顶边线一直不存在**。

   变量名说明作者本意就是字面量 `#222`；但浅色主题的页脚是近白底
   （beautify.css 里已改成 #ffffff→#faf5ea 的浅渐变），照搬 #222 会变成一道黑杠。
   所以改用全站统一的 `--border`（深色 rgba(212,175,55,.15) / 浅色 rgba(180,140,50,.25)），
   色相和站点其它分隔线一致，也自动跟随主题。

   注意必须重写整条 shorthand：只补 `border-top-color` 没用，
   因为 style 已经被前面的非法声明打回 `none` 了。
   --------------------------------------------------------------------------- */
.footer{border-top:1px solid var(--border)}

/* ---------------------------------------------------------------------------
   9) 全站 41 页复测：课程页内嵌面与语义色（第三批）
   ---------------------------------------------------------------------------
   实测（@390，audit.js 全站扫描）：

   浅色主题 7 条：
     2.42:1  .mn-template b      var(--gold2) on rgb(167,164,157)
     3.12:1  .mn-template        var(--text-d) on rgb(167,164,157)
     4.45:1  .pf-ans             #067a5c on rgb(239,235,225)   （endgame / pushfold）
     4.23:1  .tr-minimal b       #067a5c on rgb(220,233,219)
     4.41:1  .tr-note            #6b6249 on rgb(225,219,206)
     4.03:1  .lq-tech-num        #c62828 on rgb(238,213,206)
   深色主题 1 条：
     4.33:1  .tr-note            #8e8e99 on rgb(50,43,31)

   ① .mn-template 是「深色硬编码面」的又一个漏网（与第 2 段同源）：
      course-revue.html:48 写死 background:rgba(0,0,0,.3) —— 那是深色主题的
      下沉面。浅色主题下它叠在 .key 的金底上变成灰块 rgb(167,164,157)，
      里面的 --gold2 掉到 2.42、--text-d 掉到 3.12（全站最低的一处）。
      换成与其它内嵌面一致的「深色低透明度」即可，文字颜色不用动。
   --------------------------------------------------------------------------- */
:root[data-theme="light"] .mn-template{background:rgba(23,16,6,.06)}
/* 换底后 .mn-template 里的 --gold2(#78601a) 仍有 4.46（差 0.04），
   再压一档到 #6b5314 —— 与 .rd-suji / .mid-star 同一个深金，实测 5.30。 */
:root[data-theme="light"] .mn-template b{color:#6b5314}

/* ② .pf-ans / .tr-minimal b 用 var(--green)：第 6 段已把亮绿压到 #067a5c，
      但在偏绿/偏亮的浅底上仍差一点（4.45 / 4.23）。再压一档到 #056b51
      —— 与第 6、7 段的 .bg-ex-badge / .tp-g-best 同值，色板保持一致。
      注意 .pf-ans 的页面内联带 !important，必须同样带 !important 才盖得住。 */
:root[data-theme="light"] .pf-ans{color:#056b51 !important}
:root[data-theme="light"] .tr-minimal b{color:#056b51}

/* ③ .tr-note 用 var(--text-m)：浅底 4.41、深底 4.33，**两个主题都差一点**。
      不能动 --text-m（全站大量弱化文字共用它），按元素定点压深 / 提亮。
      浅色取 #4a4230（站内已有的深档），深色取 #a9a9b4。 */
:root[data-theme="light"] .tr-note{color:#4a4230}
:root:not([data-theme="light"]) .tr-note{color:#a9a9b4}

/* ④ .lq-tech-num 用 var(--red)：浅色主题的 --red(#c62828) 压 12% 红底只有
      4.03。它是页面内联样式，这里定点加深到 #b01c1c（实测 4.97）。
      深色主题的 --red 已提亮为 #f0626d，实测达标，不覆盖。
      选择器用 :not([data-theme="dark"]) 是为了把「JS 未执行、无 data-theme」
      的默认态一并覆盖（那时走 :root 的 --red:#e63946，比 #c62828 更亮）。 */
:root:not([data-theme="dark"]) .lq-tech-num{color:#b01c1c}
/* ---------------------------------------------------------------------------
   12) 浅色主题：「交互后才出现」的状态 —— 第 18 轮补测
   ---------------------------------------------------------------------------
   为什么前 17 轮一条都没报：audit.js 一直跑在**静态加载后**的页面上。演练 / 何切 /
   读牌这些组件在未作答时根本不在 DOM 里 —— 扫不到不是「没问题」，是「没渲染」。
   第 18 轮补了驱动探针（_r18_pre_states.js：进分类 → 故意答错 → 出反馈），
   同一批页面立刻从 5 处失败涨到 12 处。这一节修的就是那 12 处。

   实测（浅色 @1440，驱动到「答错」状态后）：

   A. 硬编码 #ff9ca4（深色主题专用的浅粉）压在浅底上：
        1.52  .dr-fb-no .dr-fb-head   on rgb(238,222,214)   (course-drills)
        1.61  .dr-fb-head.no          on rgb(247,228,214)   (drills)
        1.63  .dr-melds-lbl           on rgb(247,229,216)   (drills)
        1.61  .hq-fb-head.no          on rgb(247,228,214)   (heqie-trainer)
        1.73  .dr-wrongbox h3         on rgb(249,237,228)   (course-drills)
        1.85  .dr-reset-btn           on rgb(250,246,236)   (course-drills)
      改用第 7 段 .tp-g-worst 用的同一个同色系深红 #b3261e。
      .pu-warn-inline b 是同一处硬编码色（容器是 rgba(230,57,70,.07) 浅红底），
      静态加载不渲染，一并按同一值改。

   B. 半透明深色下沉面 rgba(0,0,0,.24~.26) 在浅色主题下变成中灰块，
      压在里面的 --text-d 掉到 4.5 以下：
        3.55  .dr-fb-tip / .hq-fb-tip    on rgb(187,173,163)
        3.37  .dr-reason（父 .dr-fb-reasons, rgba(0,0,0,.26)）
      换成与第 2/3 段一致的浅色内嵌底，文字色不动。
      ★ 牌河 / 手牌面板（.dr-river / .dr-hand / .hq-hand / .rd-river / .mid-hand /
        .bg-tiles）**故意保持深底**（让米色牌凸显出来），底色不动 —— 这六个面板
        第 18 轮实测全部达标（6.45~15.3）。但 .dr-river 里的「N巡」用的是
        --text-m，实测只有 2.46：course-reading 的同类 .rd-col em 早已改成
        #2a2110，这里照抄同值。

   C. ★ 一处**优先级事故**（不是漏改，是改过头）：
      第 2 段写的 `:root[data-theme="light"] .dr-opt-l` 权重 (0,3,0)，
      压过了 drills.html 的 `.dr-opt-no .dr-opt-l` (0,2,0) ⇒ 「答错」选项的字母块
      背景被强制换成浅灰，而 color:#fff 留着 ⇒ **白字压浅灰 1.21:1**。
      同一处覆盖还把「答对」态的实心绿块也打回了浅灰块 —— 它恰好仍达标，
      所以静态扫描看不见，只有把答对/答错两个状态并排打出来才看得见。
      修法不是加 :where()（那会让它反过来输给页面内联 (0,1,0) 的基础规则），
      而是补两条同权重、位置更靠后的状态规则，把实心底色还回去。

   D. .dr-badge-blue：文字已按第 5 段改成 #1f6fd0，但它的底是 rgba(74,158,255,.14)
      浅蓝微光，叠出来 rgb(224,231,231) ⇒ 只有 3.94。同色相再压深一档到 #1a5fb8。
   --------------------------------------------------------------------------- */

/* A. #ff9ca4 → #b3261e（深色底专用浅粉 → 同色系深红） */
:root[data-theme="light"] .dr-fb-no .dr-fb-head,
:root[data-theme="light"] .dr-fb-head.no,
:root[data-theme="light"] .hq-fb-head.no,
:root[data-theme="light"] .dr-melds-lbl,
:root[data-theme="light"] .dr-wrongbox h3,
:root[data-theme="light"] .dr-reset-btn,
:root[data-theme="light"] .pu-warn-inline b{color:#b3261e}

/* B. 深色下沉面 → 浅色内嵌底（文字色不动） */
:root[data-theme="light"] .dr-fb-tip,
:root[data-theme="light"] .hq-fb-tip,
:root[data-theme="light"] .dr-fb-reasons{background:rgba(23,16,6,.05)}
/* 牌河仍是深底（见说明），只把压在上面的巡目字换成近黑 —— 与 .rd-col em 同值 */
:root[data-theme="light"] .dr-river-n{color:#2a2110}

/* C. 把「答对 / 答错」的实心字母块还回来 */
:root[data-theme="light"] .dr-opt-ok .dr-opt-l{background:#067a5c;color:#fff}
:root[data-theme="light"] .dr-opt-no .dr-opt-l{background:#b71c1c;color:#fff}

/* D. 蓝色徽标同色相再压深一档 */
:root[data-theme="light"] .dr-badge-blue{color:#1a5fb8}

/* E. 「已收藏」的星标：浅色主题下渐变用的是暗金→褐（--gold #a8842a → --gold2
      #78601a），墨色星压在暗端只有 3.04。渐变两端对墨色分别是 5.23 / 3.04 ——
      暗端不够。改用站内 .ch-act:hover 已经在用的亮金渐变（同一个 color:#1a1405），
      实测 8.72 / 12.84。
      ★ 为什么前几轮没报：桌面端 .ch-act 是 visibility:hidden（悬停才显），
        audit.js 正确地把它排除掉了；只有 ≤640 的移动端它是常显的。
        再加上「必须已收藏」才出金底 —— 两个条件同时满足才暴露。 */
:root[data-theme="light"] .ch-fav[aria-pressed="true"]{
  background:linear-gradient(135deg,#d4af37,#f5d76e);
  border-color:#d4af37;
}

/* F. 演练总览卡的「正确率」：.dr-lv3 用 var(--green)（浅色 #067a5c），
      压在卡底 rgb(239,235,225) 上 4.45 —— 差 0.05。
      再压一档到 #056b51（与第 6 段 .bg-ex-badge / 第 7 段 .tp-g-best 同值）。 */
:root[data-theme="light"] .dr-lv3 .dr-card-pct{color:#056b51}

/* H. 两个搜索框的可视边界 —— 1.4.11 要求 UI 组件边界 ≥3:1。
      .sp-input（search.html，第 18 轮新加）与 .nav-ch-search（导航下拉里）用的都是
      `border:1px solid var(--border-a)` + `background:var(--card)`：
      浅色 --border-a = rgba(180,140,50,.45) 叠在控件底上合成 rgb(180,140,50)，
      对控件底 1.38、对页面底 1.53 —— **远低于 3**。
      控件填充 var(--card) 与页面底色几乎同色（实测差约 1.06）⇒ 边框是识别这个
      输入框的唯一视觉手段，所以必须 ≥3:1。
      沿用第 14 轮给 .field input 定的同一个 #8a6c1c（实测 3.98 / 4.42）。
      ★ .sp-input 是本轮新加的表单控件 —— 全站表单控件数因此从 15 涨到 16
        （course-probability 14 + index 1 + search 1），而第 14 轮那条边界修复
        是按 .field 选择器写的，新控件不在其中，所以漏了。 */
:root[data-theme="light"] .sp-input,
:root[data-theme="light"] .nav-ch-search{border-color:#8a6c1c}

/* H2. 同一对搜索框的**深色版** —— 上面那条只改了浅色。
      深色 --border-a = rgba(212,175,55,.35)，叠在控件底 rgb(20,16,11) 上
      合成约 rgb(81,72,26) ⇒ 对控件底只有 1.91、对页面底 2.04。
      深色下同样必须不透明：取 #a8842a（与浅色 #8a6c1c 同色相、亮一档，
      也正是站点 --gold 的浅色取值），对控件底 5.47、对页面底 5.72。
      ★ 第 18 轮第一次修 H 时只写了 :root[data-theme="light"] 一条 ——
        深色那份当时从没测过：那一轮的深色全站审计因本地服务被回收而全军覆没
        （9 页全是 chrome-error），是这一轮才第一次真正跑通的。 */
:root[data-theme="dark"] .sp-input,
:root[data-theme="dark"] .nav-ch-search{border-color:#a8842a}

/* H3. ★ 把 .nav-ch-search 的「聚焦边框变金」还回去 —— 上面那条边界修复的越界副作用。
      H 段为修 1.4.11 边界给 .nav-ch-search 钉了恒定 border-color（(0,3,0)），
      于是它压过 style.css:1507 原有的
          .nav-ch-search:focus{border-color:var(--gold2)}     (0,2,0)
      ⇒ 聚焦时边框**不再变金**。
      （合规不受影响：焦点指示由 beautify.css:104 的全局
        `:focus-visible{outline:2px solid var(--gold2)}` 兜底，实测浅 4.90 / 深 12.15。
        但那是原设计的**第二**通道，不该被边界修复顺带抹掉。）
      修法同 G 段：补一条特异性更高 (0,4,0) 的 focus 规则，位置在本段之后。
      实测：浅色聚焦边框 #78601a 对控件底 4.94、深色 #f5d76e 对控件底 12.35，都不影响边界判据。 */
:root[data-theme="light"] .nav-ch-search:focus,
:root[data-theme="dark"] .nav-ch-search:focus{border-color:var(--gold2)}

/* H4. ★ 第 19 轮：两个搜索框的 **placeholder 颜色** —— 从没人写过。
      .sp-input 在 search.html 里自己写了 ::placeholder 规则 color:var(--text-d)（实测
      浅 6.47 / 深 5.95 / hc 11.98 ✓），但 .nav-ch-search（44 页每一页的导航下拉里）
      **一条规则都没有** ⇒ 回退到 Chrome 的 UA 默认 #757575。那个灰是给白底设计的，
      压在站点的暖纸底 rgb(228,220,204) 上只有 **3.39**（hc 3.18 / 深 3.36）—— 全部 < 4.5。
      同一个变量、同一套底色，与 .sp-input 对齐即可。
      实测（pseudo-audit.js）：浅 6.47 / 深 5.95 / hc 11.98。 */
.nav-ch-search::placeholder{color:var(--text-d)}

/* ---------------------------------------------------------------------------
   10) 移动端：下拉选择框的触摸高度
   ---------------------------------------------------------------------------
   course-probability.html 的三个 <select>（#wrBase / #npBase / #npAlpha）
   实测 320x43 —— 差 1px 够不到 44px 的触摸目标下限。
   它们的高度由 padding + 16px 字号撑出来，加 min-height 比调 padding 稳。
   （全站其它交互控件实测已全部 ≥44px，见移动端体验层。）
   --------------------------------------------------------------------------- */
@media (max-width: 640px) {
  select { min-height: 44px; }
}

/* ---------------------------------------------------------------------------
   11) 长页体验：回到顶部按钮
   ---------------------------------------------------------------------------
   背景：pricing 移动端约 25 屏、index 约 21 屏（844px 视口），滚到底再回顶
        要连划二十多次。全站原本没有任何回顶入口（只有 js/nav-hide.js:497
        的 window.scrollTo(0,0)，那是点导航「首页」时的行为，不是按钮）。

   位置（实测，不是推算）：CDP 在 390 / 1440 两档列出「右侧固定元素」，
        全站只有 .m2m-toast-hist-btn 一个（style.css:2319，bottom:56px，
        移动 44px→占位 56~100，桌面 34px→占位 56~90）。
        ⇒ 本按钮放它上方：桌面 bottom:104（占位 104~148）、
          移动 bottom:112（占位 112~156），与 toast 按钮留 12~14px 间隙。
        style.css 里另有 #tocBtn（移动，bottom:18）与 .m2m-layout-switch
        （bottom:14）、.m2m-expand-all（左侧），但实测**都不渲染**：
        #tocBtn 在 41 个 HTML 里根本没有对应元素，后两者由
        mobiletables.js 生成而该脚本 41 页都没加载（该文件已于 2026-10-03
        第 2 轮删除）。所以不构成冲突。

   配色：--bg2 在浅色主题下**没有**被重定义（仍是 #221a0b），照抄 toast
        按钮的写法会得到「深底深字」。所以浅色主题单独给值。
        实测对比度：深色 var(--gold2)#f5d76e on var(--bg2)#221a0b = 12.15:1；
                    浅色 #78601a on #fff = 6.02:1；hover 态 #1a1405 on #d4af37 = 8.71:1。
   --------------------------------------------------------------------------- */
.bz-totop{position:fixed;right:14px;bottom:104px;z-index:940;
  width:44px;height:44px;padding:0;border-radius:50%;cursor:pointer;
  display:flex;align-items:center;justify-content:center;
  border:1px solid var(--border-a,rgba(212,175,55,.35));
  background:var(--bg2,#221a0b);color:var(--gold2,#f5d76e);
  box-shadow:0 6px 18px rgba(0,0,0,.28);
  opacity:0;visibility:hidden;transform:translateY(8px);
  transition:opacity .18s ease,transform .18s ease,visibility .18s,
             background .15s,border-color .15s}
.bz-totop.is-on{opacity:1;visibility:visible;transform:none}
.bz-totop:hover,.bz-totop:focus-visible{
  background:var(--gold,#d4af37);color:#1a1405;border-color:var(--gold);outline:none}
.bz-totop:active{transform:scale(.94)}
.bz-totop svg{width:20px;height:20px;display:block;
  fill:none;stroke:currentColor;stroke-width:2.4;stroke-linecap:round;stroke-linejoin:round}
/* 浅色主题：--bg2 不会自动变浅，必须显式给（见上方配色说明） */
:root[data-theme="light"] .bz-totop{
  background:#fff;color:#78601a;border-color:rgba(168,128,31,.4);
  box-shadow:0 6px 18px rgba(120,90,20,.18)}
:root[data-theme="light"] .bz-totop:hover,
:root[data-theme="light"] .bz-totop:focus-visible{
  background:var(--gold,#d4af37);color:#1a1405;border-color:var(--gold)}

/* G. 回到顶部按钮（.bz-totop）的焦点指示 —— 1.4.11 要求指示器 ≥3:1。
      ★★ 这条规则**必须**紧跟在下面 `.bz-totop:hover,.bz-totop:focus-visible`
         那条之后 —— 第一次修（第 18 轮）把它写在了文件前半段的第 9 段附近，
         而那条原有规则里含 `outline:none`、特异性同为 (0,2,0) 却位置更靠后
         ⇒ 同特异性后写者胜 ⇒ 新加的 outline 被静默吃掉，**浅色深色都没生效**。
         当时只跑了浅色就宣布通过，而浅色那份汇总的真实值是 focusFlagged:1。
         教训：写了修复不等于修复生效 —— 必须验证它真的赢了层叠。
      它原本只靠「底色变金」当指示，两个主题都不够：
        浅色：金 #d4af37 对米白页底 rgb(250,246,236) 只有 1.88；
              探针采到的候选是那颗静态投影 rgba(120,90,20,.18) → 1.29
        深色：金 #d4af37 对 rgb(28,20,7) 有 8.90，但探针采到的是静态投影
              rgba(0,0,0,.28) → 1.05，同样不达标（深色报出 6 处）
      ⇒ 两个主题都补一条真正的环。用 var(--gold2)：它本身就是跟主题走的对比色，
        浅色 #78601a 对米白 5.9、深色 #f5d76e 对 rgb(28,20,7) 12.15，
        不必按主题特判。 */
.bz-totop:focus-visible{outline:2px solid var(--gold2);outline-offset:2px}
@media(max-width:640px){.bz-totop{right:10px;bottom:112px}}
@media(prefers-reduced-motion:reduce){
  .bz-totop{transition:none}
  .bz-totop.is-on{transform:none}
}
@media print{.bz-totop{display:none !important}}

/* ---------------------------------------------------------------------------
   12) 移动端：短卡片网格改 2 列（长页压缩）
   ---------------------------------------------------------------------------
   背景：pricing 移动端 30.5 屏、index 21.4 屏（844px 视口）。长度由内容量
        决定，但其中「短卡片」网格在 390px 下被排成 1 列 —— 8 张卡就吃掉
        2,200px，只为重复一遍下面马上要详述的名字。

   做法：新增 .grid-2 工具类，只在 @media(max-width:640px) 下把列数固定为 2。
        **不是全站 .grid 一刀切** —— 长文本网格必须保持 1 列（见下方排除清单）。

   为什么必须 !important：
        pricing.html 的「★ 枢轴」网格带内联
        style="grid-template-columns:repeat(auto-fit,minmax(280px,1fr))"，
        index.html 的「选择你的路径」同理。**内联样式默认压过外部 CSS**，
        外部规则要生效只能带 !important。

   排除清单（实测判据 = 每张卡的平均正文字数，>50 字挤成 2 列会严重折行）：
        index「学习主线·八个里程碑」 78 字/卡（且每卡带一个按钮）
        index「贯穿全程·练习与环境」  81 字/卡
        index「学员战绩」            175 字/卡
        index「选择你的路径」         价格卡，带权益列表
        ⇒ 以上一律保持 1 列。已逐屏截图确认 2 列下难看。

   收益（390×844，实测 scrollHeight，light / dark 同值）：
        pricing  25,750 → 24,156 px（30.51 → 28.62 屏，-6.2%）
        index    18,081 → 16,955 px（21.42 → 20.09 屏，-6.2%）
        两页 scrollWidth 均 == 390，零横向溢出。
        （对照实验：把 .grid-2 的选择器去掉重测，数字回到改前值 ⇒ 差值确由本规则产生。）
   --------------------------------------------------------------------------- */
@media (max-width: 640px) {
  .grid.grid-2 { grid-template-columns: repeat(2, minmax(0, 1fr)) !important; gap: 12px !important; }
}


/* ===========================================================================
   .tile-suit —— 牌面花色后缀（万 / 筒 / 索）
   ---------------------------------------------------------------------------
   2026-10-03 新增。修一处「题面无法作答」的缺陷：
     drills.html 的 mj-drill-ui.js 原来写 NUM_CN[n-1] + TILE_LABEL[suit][0]，
     heqie-trainer.js 原来写 TILE_LABEL[suit][n-1] ——
     而 TILE_LABEL.m/p/s 都是 ["1".."9"]，于是数牌只渲染出一个数字：
       · 三合一训练器 → 每张牌都带一个多余的 "1"（一1 / 五1 / 九1）
       · 何切练习器   → 只有数字，完全看不出花色
     两处都改为「中文数字 + 花色名」，花色用本类做视觉降级。
   本文件在页面末尾加载，晚于 <head> 里的页面内联样式，故能稳定覆盖。
   --------------------------------------------------------------------------- */
.dr-tile .tile-suit,
.hq-tile .tile-suit {
  font-style: normal;
  font-size: .6em;
  font-weight: 700;
  line-height: 1;
  margin-left: 1px;
  opacity: .68;
  vertical-align: .08em;
}
/* 小尺寸牌（手牌缩略 / 受入列表）再压一点，避免与主数字挤在一起 */
.dr-hand-sm .dr-tile .tile-suit,
.hq-uke-list .hq-tile .tile-suit { font-size: .58em; margin-left: 0; }

/* ==== MJG-BEGIN ==== */
/* ===========================================================================
   实战对局（mahjong-game.html + js/mahjong-game-ui.js）
   ---------------------------------------------------------------------------
   牌面视觉沿用 drills / heqie-trainer 的「象牙牌 + 中文数字 + 花色后缀」，
   但本页的牌不依赖任何页面内联样式，全部在这里定义 —— 换页复用不会掉样式。

   布局：桌面是 3 列 × 3 行牌桌网格（对家在上 / 上家左 / 下家右 / 自己下），
         窄屏改成纵向流式（上家与下家并排一行、手牌换行成两排）。
   主题：牌桌绒面用局部变量 --felt1/--felt2，深浅主题各给一套；
         牌本身固定象牙色（与真实麻将牌一致），两个主题下都不需要反转。
   --------------------------------------------------------------------------- */

.mjg-app { max-width: 1080px; margin: 0 auto 22px; }

/* ---------- 牌 ---------- */
.mjg-tile {
  position: relative; display: inline-flex; align-items: center; justify-content: center;
  width: 44px; height: 60px; border-radius: 7px; flex: none;
  background: linear-gradient(170deg, #fdfbf3, #e8e2d0);
  border: 1.5px solid #cfc6ad;
  box-shadow: 0 2px 6px rgba(0, 0, 0, .3);
  font-size: 19px; font-weight: 800; color: #2a2110;
  user-select: none; -webkit-user-select: none;
  transition: transform .12s ease, box-shadow .12s ease, border-color .12s ease;
}
.mjg-tile-n { display: inline-flex; align-items: baseline; line-height: 1; }
.mjg-tile.mjg-yao { color: #b3261e; }
.mjg-tile-sm { width: 30px; height: 42px; font-size: 14px; border-radius: 5px; border-width: 1px; box-shadow: 0 1px 3px rgba(0, 0, 0, .28); }
.mjg-tile-xs { width: 24px; height: 34px; font-size: 12px; border-radius: 4px; border-width: 1px; box-shadow: 0 1px 2px rgba(0, 0, 0, .25); }

/* 可点的手牌：抬高 + 高亮。触摸目标就是牌本身（桌面 44×60，窄屏 42×57） */
.mjg-tile-hand { cursor: pointer; }
.mjg-tile-live:hover, .mjg-tile-live:focus-visible {
  transform: translateY(-8px);
  border-color: var(--gold2);
  box-shadow: 0 8px 16px rgba(0, 0, 0, .42), 0 0 0 2px rgba(212, 175, 55, .45);
  outline: none;
}
.mjg-tile-live:active { transform: translateY(-3px); }
.mjg-tile-drawn { border-color: var(--gold2); box-shadow: 0 0 0 2px rgba(212, 175, 55, .4), 0 2px 6px rgba(0, 0, 0, .3); }

/* 牌背
   ★ 原来是一层纯色渐变 —— 缩小到 22~30px 后就是一块平面绿矩形，像占位符。
   真牌背是「圆角 + 顶部受光 + 中心凹槽」，所以这里叠三层：
   ① 顶部一道高光（模拟牌的上边缘受光）
   ② 主体两段渐变（上浅下深，做出圆柱感）
   ③ 内层凹槽（.mjg-back-i）用更亮的描边 + 极淡的渐变，别再用纯色块 */
.mjg-back {
  background:
    linear-gradient(180deg, rgba(255, 255, 255, .16), rgba(255, 255, 255, 0) 46%),
    linear-gradient(168deg, #4e8467 0%, #2d5743 58%, #24432f 100%);
  border-color: #1b3527;
  box-shadow: 0 2px 5px rgba(0, 0, 0, .34), inset 0 1px 0 rgba(255, 255, 255, .2);
}
.mjg-back-i {
  width: 58%; height: 58%; border-radius: 3px;
  border: 1px solid rgba(255, 255, 255, .26);
  background: linear-gradient(155deg, rgba(255, 255, 255, .16), rgba(255, 255, 255, .02) 70%);
  box-shadow: inset 0 1px 1px rgba(0, 0, 0, .18);
}
.mjg-kan-back {
  background:
    linear-gradient(180deg, rgba(255, 255, 255, .16), rgba(255, 255, 255, 0) 46%),
    linear-gradient(168deg, #5a7280 0%, #364a56 58%, #293a44 100%);
  border-color: #22313a;
}

/* 立直宣言牌横放（真牌桌上就是把这张转 90°）；最新一张打出的牌加红圈 */
.mjg-river .mjg-tile.mjg-rot { transform: rotate(-90deg); z-index: 2; }
.mjg-river .mjg-tile.mjg-last { box-shadow: 0 0 0 2px rgba(230, 57, 70, .75), 0 2px 6px rgba(0, 0, 0, .35); }

/* ---------- 顶栏 ---------- */
.mjg-bar { display: flex; align-items: center; justify-content: space-between; gap: 10px; flex-wrap: wrap; margin-bottom: 10px; }
.mjg-bar-l, .mjg-bar-r { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.mjg-badge {
  display: inline-flex; align-items: center; padding: 5px 11px; border-radius: 999px;
  background: rgba(212, 175, 55, .16); border: 1px solid var(--border-a);
  color: var(--gold2); font-size: 13px; font-weight: 700; white-space: nowrap;
}
.mjg-badge-dim { background: var(--card); border-color: var(--border); color: var(--text-d); }
.mjg-dora-wrap { display: inline-flex; align-items: center; gap: 5px; }
.mjg-dora-label { font-size: 12px; color: var(--text-m); margin-right: 2px; }

/* ---------- 按钮 ---------- */
.mjg-btn {
  appearance: none; cursor: pointer; font: inherit; font-size: 14px; font-weight: 700;
  /* 触摸目标下限 44×44（本项目移动端量化标准）。**高和宽都要写**：
     · min-height: 46 —— 实测按钮渲染高度正好等于 min-height（padding 撑不满），
       贴着 44 写会因为边框/取整变成 43，所以留 2px 余量。
     · min-width: 46 —— 「碰 / 杠 / 过」这类单字按钮原来只有 41px 宽
       （高度 46 达标、**宽度不达标**，实测 41×46）。加 min-width 后 46×46。
     宽按钮（立直 156px、荣和 54px）不受 min-width 影响。
     ★ 2026-10-04：原来只写了 min-height，注释还误把底线写成 42 —— 宽这一维漏了。 */
  padding: 11px 16px; min-height: 46px; min-width: 46px; border-radius: 10px;
  background: var(--card-h); color: var(--text); border: 1px solid var(--border-a);
  transition: transform .1s ease, background .15s ease, border-color .15s ease;
}
.mjg-btn:hover { transform: translateY(-1px); border-color: var(--gold2); }
.mjg-btn:active { transform: translateY(0); }
.mjg-btn:focus-visible { outline: 2px solid var(--gold2); outline-offset: 2px; }
.mjg-btn-primary { background: linear-gradient(160deg, var(--gold2), var(--gold)); color: #1a1408; border-color: transparent; }
/* ★ 2026-10-05：浅色主题的 --gold2 被本文件 :665 改成 #78601a（墨金），
   近黑字压上去只有 3.04:1。照抄同一文件里 .mjg-wind-dealer 的浅色做法
   （淡金底 + 深棕字），两个色标都换掉，最差端留足余量。 */
[data-theme="light"] .mjg-btn-primary {
  background: linear-gradient(160deg, #f7e6a8, #e6cf78);
  color: #4a3a08;
}
/* ★ 2026-10-05：白字压在渐变亮端 #e63946 上只有 4.17:1（两个主题共用这条规则，
   所以 light/dark 都不达标）。把亮端压暗到 #cf2f3c，暗端不变。 */
.mjg-btn-riichi { background: linear-gradient(160deg, #cf2f3c, #b3261e); color: #fff; border-color: transparent; }
.mjg-btn-kan { background: linear-gradient(160deg, #3f6b53, #274b39); color: #eaf6ef; border-color: transparent; }
.mjg-btn-call { background: linear-gradient(160deg, #3a4a6b, #26334d); color: #e8eefc; border-color: transparent; }
.mjg-btn-ghost { background: transparent; color: var(--text-d); }

/* ---------- 牌桌 ---------- */
.mjg-table {
  --felt1: #17392c; --felt2: #0d271d; --felt-line: rgba(255, 255, 255, .07);
  display: grid; gap: 8px;
  grid-template-columns: minmax(0, 1fr) minmax(150px, 210px) minmax(0, 1fr);
  grid-template-areas:
    "top   top    top"
    "left  center right"
    "self  self   self";
  padding: 14px; border-radius: var(--r-lg);
  background:
    repeating-linear-gradient(45deg, var(--felt-line) 0 2px, transparent 2px 6px),
    linear-gradient(160deg, var(--felt1), var(--felt2));
  border: 1px solid rgba(0, 0, 0, .25);
  box-shadow: inset 0 0 60px rgba(0, 0, 0, .35), var(--shadow);
}
[data-theme="light"] .mjg-table {
  --felt1: #eaf1e5; --felt2: #d6e3d0; --felt-line: rgba(23, 16, 6, .045);
  border-color: rgba(23, 16, 6, .1);
  box-shadow: inset 0 0 50px rgba(120, 90, 20, .08), var(--shadow);
}
.mjg-seat-top { grid-area: top; }
.mjg-seat-left { grid-area: left; }
.mjg-seat-right { grid-area: right; }
.mjg-seat-self { grid-area: self; }
.mjg-center {
  grid-area: center; display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 4px; text-align: center; padding: 10px 8px; border-radius: var(--r);
  background: rgba(0, 0, 0, .16); border: 1px solid rgba(255, 255, 255, .07);
}
[data-theme="light"] .mjg-center { background: rgba(255, 255, 255, .5); border-color: rgba(23, 16, 6, .08); }
.mjg-c-round { font-size: 22px; font-weight: 800; color: var(--gold2); letter-spacing: 1px; }
.mjg-c-sub { font-size: 12px; color: var(--text-d); line-height: 1.5; }
[data-theme="dark"] .mjg-center .mjg-c-sub { color: #cfe3d6; }
.mjg-c-dora b { color: var(--gold2); }
/* 牌山进度条：纯数字「余 69 张」新手没概念，一根条一眼看出这局打到哪了 */
.mjg-c-wall {
  width: 100%; max-width: 152px; height: 4px; border-radius: 2px;
  background: rgba(255, 255, 255, .14); overflow: hidden; margin: 3px 0 2px;
}
[data-theme="light"] .mjg-c-wall { background: rgba(23, 16, 6, .12); }
.mjg-c-wall i {
  display: block; height: 100%; border-radius: 2px;
  background: linear-gradient(90deg, var(--gold2), var(--gold));
  transition: width .3s ease;
}

/* 座位块 */
.mjg-seat { display: flex; flex-direction: column; gap: 6px; min-width: 0; }
.mjg-pinfo { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; font-size: 13px; }
.mjg-wind {
  display: inline-flex; align-items: center; justify-content: center;
  width: 24px; height: 24px; border-radius: 6px; flex: none;
  background: var(--card-h); border: 1px solid var(--border-a);
  color: var(--gold2); font-weight: 800; font-size: 13px;
}
.mjg-wind-dealer { background: linear-gradient(160deg, var(--gold2), var(--gold)); color: #1a1408; border-color: transparent; }
.mjg-pname { font-weight: 700; color: var(--text); }
[data-theme="dark"] .mjg-table .mjg-pname { color: #f2f7f3; }
.mjg-pscore { font-variant-numeric: tabular-nums; color: var(--text-d); }
[data-theme="dark"] .mjg-table .mjg-pscore { color: #c3d8ca; }
.mjg-tag { font-size: 11px; font-weight: 700; padding: 2px 7px; border-radius: 999px; }
.mjg-tag-dealer { background: rgba(212, 175, 55, .22); color: var(--gold2); }
/* ★ 2026-10-05 对局页「运行时元素」对比度修正（第 4 批）。
   和 2026-10-04 那批的区别：那批修的是**加载帧就在 DOM 里**的元素，
   这批修的是**只在运行时状态才进 DOM** 的 —— 立直徽章只在有人立直时才出现，
   危险度徽章只在教练面板展开时才出现。上一轮的量具只测「加载后那一帧」，
   所以它们从来没被看见过（那批修了同族的 .mjg-wind / .mjg-legend-red，
   恰好漏掉了这一批，原因就是可见性差异）。
   量具：工作区 _mj_audit_strict.js（底层渐变取**最差**色标 + opacity 参与合成）
        + _mj_enum_mjg.js（4 个运行时状态 × 双主题）。 */
.mjg-tag-riichi { background: rgba(230, 57, 70, .2); color: #ff8b95; }
[data-theme="light"] .mjg-tag-riichi { color: #9c1f2a; }   /* 修前 4.34 */
.mjg-tag-tenpai { background: rgba(6, 214, 160, .18); color: #0f9b78; }
/* 原来 light/dark 共用 #0f9b78 —— 淡绿底上 2.72、深绿底上 2.48，两边都不够 */
[data-theme="light"] .mjg-tag-tenpai { color: #055f47; }   /* 修前 2.72 */
[data-theme="dark"] .mjg-tag-tenpai { color: #5fe0bb; }    /* 修前 2.48 */
.mjg-tag-turn { background: rgba(255, 255, 255, .16); color: var(--text-d); }
[data-theme="light"] .mjg-tag-turn { background: rgba(23, 16, 6, .08); }
/* 深色下 --text-d(#9a9aa5) 压在半透明白底上只有 2.77；浅色下同一套是达标的 */
[data-theme="dark"] .mjg-tag-turn { color: var(--text); }   /* 修前 2.77 */
.mjg-tag-you { background: var(--gold2); color: #1a1408; margin-left: 6px; }

/* ★ 2026-10-04 浅色主题对比度修正。
   审计（_tools/audit.js，WCAG 公式）在 mahjong-game.html 浅色下报 3 处不达标：
     span.mjg-wind.mjg-wind-dealer 「东」 3.04（需 4.5）
     span 「红圈」（图例）            3.49（需 4.5）
     span.mjg-wind 「西」             4.34（需 4.5）
   根因：浅色主题的 --gold/--gold2 是「深金」，而徽章文字仍是深色 #1a1408 —— 深压深。
   修法：浅色下把「金底徽章」翻成「淡金底 + 深棕字」，风牌与「你」标签改用深棕。
   深色主题不变（亮金底 + 深字，本来就达标）。 */
[data-theme="light"] .mjg-wind { color: #6b4f10; }
[data-theme="light"] .mjg-wind-dealer {
  background: linear-gradient(160deg, #f7e6a8, #e6cf78);
  color: #4a3a08;
}
[data-theme="light"] .mjg-tag-you { background: #e6cf78; color: #4a3a08; }
.mjg-legend-red { color: #ff8b95; font-weight: 700; }
[data-theme="light"] .mjg-legend-red { color: #a81f2b; }

/* 副露（吃/碰/杠）的底板
   ★ 原来只有 rgba(23,16,6,.06) 一层几乎看不见的底色 —— 结果副露的牌和手牌连成一片，
   看截图时会以为「手牌有 17 张」（其实是 9 张副露 + 4 张手牌）。
   副露和手牌是两种性质的东西（副露已经定型、不能再打），必须一眼分得开。 */
.mjg-melds { display: flex; gap: 8px; flex-wrap: wrap; }
.mjg-meld {
  display: inline-flex; gap: 2px; padding: 4px 5px; border-radius: 8px;
  background: rgba(0, 0, 0, .22);
  border: 1px solid rgba(255, 255, 255, .09);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .06);
}
[data-theme="light"] .mjg-meld {
  background: rgba(23, 16, 6, .1);
  border-color: rgba(23, 16, 6, .13);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .55);
}

/* ★ 2026-10-04：必须显式写 width:100%。
   座位改成 align-items:center/flex-end/flex-start 之后，.mjg-opphand 作为 flex item
   的宽度不再是 stretch 而是 fit-content；而它内部的牌是 flex:1 1 0; min-width:0，
   在 fit-content 容器里 flex-basis 0 会让牌宽塌缩到 0 —— 实测上家/下家 13 张牌背
   从 338px 掉到 88px（只剩 gap），看起来像一排虚线。
   写死 100% 后：对家 902px 容器 + 牌居中；上家/下家 338px 容器 + 牌等比均分。
   ★ justify-content:center 写在基础规则里（不是只给对家）：
   桌面端上家/下家的牌是 flex:1 占满容器，center 不生效；
   但窄屏单列堆叠时牌是固定宽度，此时需要 center —— 否则 13 张牌背挤在左边、
   右边空出几百像素（768 平板竖屏下尤其明显）。 */
.mjg-opphand { display: flex; gap: 3px; flex-wrap: nowrap; width: 100%; justify-content: center; }
/* ★ 行间距必须单独给（row-gap），不能跟列间距共用 gap：
   受入数字是 .mjg-uke 绝对定位在牌下方（bottom:-14px），它不占布局高度。
   手牌排成两行时（手机 390px、或窄桌面 14 张），行间距 = 牌高 + gap，
   而 gap 原来只有 3~5px —— 数字正好落在下一行牌的顶边上，看起来像被压住。
   桌面 1 行时看不出这个问题，只有真机截图才会暴露。 */
.mjg-hand { display: flex; column-gap: 5px; row-gap: 16px; flex-wrap: wrap; align-items: flex-end; }
.mjg-selfwrap { display: flex; flex-direction: column; gap: 6px; }
.mjg-gap { display: inline-block; width: 12px; flex: none; }
.mjg-handhint { font-size: 12px; color: var(--text-m); }
[data-theme="dark"] .mjg-table .mjg-handhint { color: #a9c3b3; }
.mjg-handhint-on { color: #ff8b95; font-weight: 700; }
[data-theme="light"] .mjg-handhint-on { color: #b3261e; }

/* ---------- 牌河 ----------
   ★ 真麻将的牌河是「6 张一行」的方阵，不是一条长句子。
   原来写的是 flex + flex-wrap + max-width:100%：在 902px 宽的对家/自己座位里，
   12~13 张弃牌会一路铺满整行（实测牌河框 902px、1 行），
   读不出「打了几张、顺序如何、谁打过什么」——而这正是读牌要看的。
   改成固定 6 列的网格；宽度用 fit-content，让它只占牌实际需要的宽度，
   再给一块淡淡的底板把它和手牌分开（否则弃牌和手牌会糊成一片）。 */
.mjg-river {
  display: grid; grid-template-columns: repeat(6, auto);
  gap: 3px; justify-content: start;
  width: fit-content; max-width: 100%;
}
.mjg-river:not(.mjg-river-empty) {
  padding: 4px; border-radius: 8px;
  background: rgba(0, 0, 0, .1);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .04);
}
[data-theme="light"] .mjg-river:not(.mjg-river-empty) {
  background: rgba(23, 16, 6, .055);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .5);
}
.mjg-river-empty { min-height: 4px; }

/* 上家/下家所在的那一列只有 ~338px，13 张 30px 牌背要 426px —— 放不下就会折成 2 行，
   而「对家」是 1 行，两边不一致，看起来像渲染坏了。
   让牌背在这一列里等比收缩（flex:1 + aspect-ratio），保证四家都是一行。
   ★ 不写死像素：写死只在某一个视口宽度下成立，换个宽度又会折行。 */
@media (min-width: 861px) {
  .mjg-seat-left .mjg-opphand .mjg-tile,
  .mjg-seat-right .mjg-opphand .mjg-tile {
    flex: 1 1 0; min-width: 0;
    width: auto; height: auto; aspect-ratio: 30 / 42;
  }
}

/* ---------- 座位内容朝向中央区 ----------
   ★ 2026-10-04：对家与自己家横跨整个 902px，子元素默认 stretch 到全宽、内容靠左 ——
   实测对家的暗牌(426px)与牌河(167px)全堆在左边，右侧空出 400~500px，
   整张桌子看起来像没渲染完；上家的牌河也离中央区 179px，四家读起来不对称。
   让内容朝中央区摆放：上下两家居中，左右两家贴向中央。
   （左右两列的暗牌是 flex:1 撑满的，不受 align-items 影响；动的只有名字/牌河/副露。） */
.mjg-seat-top, .mjg-seat-self { align-items: center; }
.mjg-seat-left { align-items: flex-end; }
.mjg-seat-right { align-items: flex-start; }

/* ---------- 提示条 ---------- */
.mjg-banner {
  margin: 10px 0; padding: 10px 14px; border-radius: var(--r);
  background: var(--card); border: 1px solid var(--border);
  color: var(--text-d); font-size: 13px; font-weight: 600;
}
.mjg-banner-live { background: rgba(212, 175, 55, .14); border-color: var(--border-a); color: var(--gold2); }

/* ---------- 操作区 ---------- */
.mjg-actions { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin: 12px 0; min-height: 44px; }
.mjg-wait { display: inline-flex; align-items: center; gap: 8px; font-size: 13px; color: var(--text-d); }
.mjg-callinfo { font-size: 13px; color: var(--text-d); margin-right: 4px; }
.mjg-callinfo b { color: var(--gold2); }
.mjg-dot { width: 8px; height: 8px; border-radius: 50%; background: var(--gold2); animation: mjgBlink 1.1s ease-in-out infinite; }
@keyframes mjgBlink { 0%, 100% { opacity: .25; } 50% { opacity: 1; } }

/* ============================================================
   教练式练习系统（2026-10-04 新增）
   难度选择器 / 教练面板 / 逐张受入 / 危险度 / 即时反馈 / 复盘 / 发牌动画
   ============================================================ */

/* ---------- 练习强度选择器 ---------- */
.mjg-levels {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  margin: 0 0 12px; padding: 10px 12px;
  background: var(--card); border: 1px solid var(--border); border-radius: var(--r);
}
.mjg-lv-label { font-size: 12px; font-weight: 700; color: var(--text-m); letter-spacing: .5px; }
.mjg-lv {
  font: inherit; font-size: 13px; font-weight: 700; cursor: pointer;
  /* 原来是 38px —— 低于本项目 44×44 的触摸目标下限。
     实测 49×38，而且这是**移动端全站扫描里唯一的不达标元素**（4 个 chip 全中）。
     难度切换（入门/牌效/读牌/实战）是练习系统的高频操作，必须给足。
     46 = 44 + 2px 余量，跟 .mjg-btn 保持一致。 */
  padding: 8px 14px; min-height: 46px;
  background: transparent; color: var(--text-d);
  border: 1px solid var(--border-a); border-radius: 999px;
  transition: background .16s, color .16s, border-color .16s;
}
.mjg-lv:hover { background: var(--card-h); color: var(--text); }
.mjg-lv-on { background: var(--gold2); color: #1a1408; border-color: transparent; }
[data-theme="light"] .mjg-lv-on { background: #e6cf78; color: #4a3a08; }
.mjg-lv-desc { flex: 1 1 220px; min-width: 180px; font-size: 12.5px; color: var(--text-m); line-height: 1.55; }

/* ---------- 教练面板 ---------- */
.mjg-coach {
  margin: 12px 0; padding: 12px 14px;
  background: var(--card); border: 1px solid var(--border-a); border-radius: var(--r);
}
.mjg-coach-head { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin-bottom: 8px; }
.mjg-coach-title { font-size: 13px; font-weight: 800; color: var(--gold2); letter-spacing: .5px; }
.mjg-coach-sh { font-size: 13px; color: var(--text-d); }
.mjg-coach-sh b { color: var(--text); font-size: 15px; }
.mjg-peek { margin-left: auto; }
.mjg-coach-best {
  font-size: 14px; color: var(--text); margin-bottom: 6px;
  padding: 8px 10px; border-radius: 8px;
  background: rgba(212, 175, 55, .12); border: 1px solid rgba(212, 175, 55, .3);
}
.mjg-coach-best b { color: var(--gold2); font-size: 16px; }
[data-theme="light"] .mjg-coach-best { background: rgba(168, 132, 42, .12); }
.mjg-coach-why { font-size: 12.5px; line-height: 1.65; color: var(--text-d); margin-bottom: 8px; }

.mjg-coach-list { display: flex; flex-wrap: wrap; gap: 6px; }
.mjg-coach-item {
  display: inline-flex; align-items: center; gap: 4px;
  padding: 4px 7px; border-radius: 7px;
  background: rgba(0, 0, 0, .14); border: 1px solid transparent;
}
[data-theme="light"] .mjg-coach-item { background: rgba(23, 16, 6, .06); }
.mjg-coach-item-best { border-color: var(--gold2); background: rgba(212, 175, 55, .18); }
[data-theme="light"] .mjg-coach-item-best { background: rgba(168, 132, 42, .16); }
.mjg-ci-txt { font-size: 11px; color: var(--text-m); }
/* 浅色主题：--text-m(#6b6249) 压在明细条底(rgb(227,218,195))上实测只有 4.36:1，
   11px 小字要 4.5 —— 差 0.14 卡在线上。明细文字改用 --text-d(#5a523f) ≈ 6.1:1。
   深色主题的 --text-m 本来就够（那边是深底浅字），所以只在浅色下覆盖。 */
[data-theme="light"] .mjg-ci-txt { color: var(--text-d); }
.mjg-ci-n { font-size: 11px; font-variant-numeric: tabular-nums; color: var(--text-d); min-width: 20px; text-align: right; }
/* 「退一步」标记：打出这张会让向听退回，所以不画受入条（跨向听比长短会误导）。
   文字色同样在浅色下用 --text-d，理由与上面的 .mjg-ci-txt 一致。 */
.mjg-ci-worse { font-size: 10px; font-weight: 700; color: var(--text-m); white-space: nowrap; }
[data-theme="light"] .mjg-ci-worse { color: var(--text-d); }
.mjg-coach-item-worse { border-color: rgba(255, 255, 255, .06); }
[data-theme="light"] .mjg-coach-item-worse { background: rgba(23, 16, 6, .035); }
/* 深色主题：金底明细条上的中灰小字压不住 —— 实测 .mjg-ci-txt 3.56、
   .mjg-ci-n 4.14，都要 4.5。桌面上（绒布底 rgb(23,57,44)）的受入数字同理只有 3.91。
   这三处一律换成亮色前景，不靠调底色（调底色会牵动「推荐牌」的视觉权重）。 */
[data-theme="dark"] .mjg-coach-item-best .mjg-ci-txt,
[data-theme="dark"] .mjg-coach-item-best .mjg-ci-n { color: #f2e6bd; }
[data-theme="dark"] .mjg-uke { color: #d7dbd0; }
.mjg-ukebar { display: inline-block; width: 30px; height: 5px; border-radius: 3px; background: rgba(255, 255, 255, .12); overflow: hidden; }
[data-theme="light"] .mjg-ukebar { background: rgba(23, 16, 6, .12); }
.mjg-ukebar i { display: block; height: 100%; background: var(--green); }

/* ---------- 手牌上的受入标注 ---------- */
.mjg-tilewrap { position: relative; display: inline-block; }
.mjg-uke {
  position: absolute; left: 50%; bottom: -14px; transform: translateX(-50%);
  font-size: 10px; font-weight: 800; font-variant-numeric: tabular-nums;
  color: var(--text-m); white-space: nowrap; pointer-events: none;
}
.mjg-tile.mjg-best { box-shadow: 0 0 0 2px var(--gold2), 0 4px 12px rgba(212, 175, 55, .35); }
/* 会让向听退回的牌：数字前带「↓」，靠箭头区分，不靠压暗颜色。
   为什么不用更浅的字色做「压暗」：这是 10px 小字，底色是深绿绒布，
   对比度余量本来就不够 —— 实测把字色压到 #9a9585 只剩 4.23:1（要 4.5），
   属于「为了弱化而把它变得读不清」。所以这里只换字重，不动颜色。 */
/* 「退步」标记：数字前画一个实心下三角。
   为什么不用字符「↓」：10px 下它是细竖线 + 小箭头，笔画宽度和数字「1」几乎一样，
   紧贴数字写出来「↓84」会被读成「184」；加大间距也救不回来（实测 3px 仍会混）。
   用 CSS 画三角形有两个好处：形状与任何数字笔画都不会混，且不依赖字体里有没有这个字形。 */
.mjg-uke-worse { font-weight: 600; }
.mjg-uke-worse::before {
  content: ""; display: inline-block; vertical-align: middle;
  width: 0; height: 0;
  border-left: 3px solid transparent;
  border-right: 3px solid transparent;
  border-top: 5px solid currentColor;
  margin-right: 3px;
}
.mjg-tile.mjg-safe-3 { box-shadow: inset 0 -3px 0 var(--green); }
.mjg-tile.mjg-safe-2 { box-shadow: inset 0 -3px 0 #7fd6a8; }
.mjg-tile.mjg-safe-1 { box-shadow: inset 0 -3px 0 #e0b84c; }
.mjg-tile.mjg-safe-0 { box-shadow: inset 0 -3px 0 var(--red); }

/* ---------- 危险度徽章 ---------- */
.mjg-safety {
  font-size: 10px; font-weight: 800; padding: 1px 5px; border-radius: 999px;
  border: 1px solid transparent;
}
.mjg-safety-3 { background: rgba(6, 214, 160, .2); color: #0f9b78; border-color: rgba(6, 214, 160, .45); }
.mjg-safety-2 { background: rgba(6, 214, 160, .12); color: #0f9b78; border-color: rgba(6, 214, 160, .3); }
.mjg-safety-1 { background: rgba(224, 184, 76, .18); color: #8a6c1c; border-color: rgba(224, 184, 76, .45); }
.mjg-safety-0 { background: rgba(230, 57, 70, .16); color: #b3261e; border-color: rgba(230, 57, 70, .4); }
[data-theme="dark"] .mjg-safety-1 { color: #e0b84c; }
[data-theme="dark"] .mjg-safety-0 { color: #ff8b95; }
/* ★ 2026-10-05：这一族原来只给了 safety-0/1 的深色覆盖，浅色一个都没有，
   而 safety-2/3 连深色都没有 —— 于是 light 三个（2.29/2.38/3.37）、
   dark 三个（2.31/2.69/4.22）全不达标。同族的 .mjg-tag-tenpai 用同一组色。
   实测修前 → 修后见 WORKSTATE.md。 */
[data-theme="light"] .mjg-safety-3,
[data-theme="light"] .mjg-safety-2 { color: #055f47; }   /* 2.29 / 2.38 */
[data-theme="dark"] .mjg-safety-3,
[data-theme="dark"] .mjg-safety-2 { color: #5fe0bb; }    /* 2.31 / 2.69 */
[data-theme="light"] .mjg-safety-1 { color: #6b4f10; }   /* 3.37 */
[data-theme="dark"] .mjg-safety-1 { color: #f0cc63; }    /* 4.22 */
[data-theme="light"] .mjg-safety-0 { color: #9c1f2a; }   /* 3.88 */

/* ---------- 即时反馈 ---------- */
.mjg-fb { font-size: 13px; line-height: 1.6; }
.mjg-fb-good { color: var(--green); font-weight: 700; }
.mjg-fb-mid { color: #c99a2e; }
.mjg-fb-bad { color: var(--red); font-weight: 700; }
[data-theme="light"] .mjg-fb-mid { color: #8a6c1c; }

/* ---------- 复盘 ---------- */
.mjg-review {
  margin-top: 14px; padding: 12px 14px; border-radius: var(--r);
  background: rgba(212, 175, 55, .08); border: 1px solid var(--border-a);
}
[data-theme="light"] .mjg-review { background: rgba(168, 132, 42, .08); }
.mjg-rv-head {
  display: flex; align-items: center; gap: 8px;
  font-size: 14px; font-weight: 800; color: var(--gold2); margin-bottom: 8px;
}
.mjg-rv-grade {
  display: inline-flex; align-items: center; justify-content: center;
  width: 28px; height: 28px; border-radius: 8px;
  font-size: 16px; font-weight: 900; color: #1a1408;
}
.mjg-rv-S { background: #f5d76e; }
.mjg-rv-A { background: #9fe6b8; }
.mjg-rv-B { background: #a9d4f5; }
.mjg-rv-C { background: #f5d0a9; }
.mjg-rv-D { background: #f5a9a9; }
.mjg-rv-worst { font-size: 13px; line-height: 1.65; color: var(--text); margin-top: 6px; }
.mjg-rv-worst b { color: var(--gold2); }
.mjg-rv-tip { font-size: 12.5px; color: var(--text-m); margin-top: 6px; }

/* ---------- 发牌动画 ---------- */
/* ★ 浮层的「开关」一律靠 .hidden，但作者样式里的 display 会压过 UA 的
   [hidden]{display:none} —— .mjg-deal 设了 display:flex，于是
   `elDeal.hidden = true` 完全无效：深色遮罩 + backdrop-filter:blur(3px)
   会一直盖在牌桌上，整局看起来都是糊的（截图实测发虚，就是它）。
   凡是靠 .hidden 开关的浮层，这里统一兜一条 [hidden] 规则。
   为什么加 !important：这条是「关掉」的兜底，必须比任何布局规则都硬；
   将来谁再给这些容器加 display，也不会把开关弄坏。 */
.mjg-deal[hidden],
.mjg-coach[hidden],
.mjg-result[hidden],
.mjg-banner[hidden] { display: none !important; }
.mjg-deal {
  position: fixed; inset: 0; z-index: 60; cursor: pointer;
  display: flex; align-items: center; justify-content: center;
  background: rgba(10, 8, 4, .72); backdrop-filter: blur(3px);
}
.mjg-deal-card {
  max-width: min(92vw, 620px); padding: 20px 22px;
  background: var(--bg); border: 1px solid var(--border-a); border-radius: var(--r-lg);
  box-shadow: var(--shadow); animation: mjgDealIn .22s ease-out;
}
@keyframes mjgDealIn { from { opacity: 0; transform: translateY(10px) scale(.98); } to { opacity: 1; transform: none; } }
.mjg-deal-title { font-size: 15px; font-weight: 800; color: var(--gold2); text-align: center; letter-spacing: 1px; }
.mjg-deal-dice { display: flex; align-items: center; justify-content: center; gap: 8px; margin: 10px 0 14px; }
.mjg-die {
  display: inline-flex; align-items: center; justify-content: center;
  width: 34px; height: 34px; border-radius: 8px;
  background: #fdfaf2; color: #241d10;
  font-size: 17px; font-weight: 900; font-variant-numeric: tabular-nums;
  box-shadow: 0 2px 0 rgba(0, 0, 0, .25);
  animation: mjgDice .5s ease-out;
}
@keyframes mjgDice {
  0% { transform: rotate(-18deg) scale(.6); opacity: 0; }
  60% { transform: rotate(8deg) scale(1.08); }
  100% { transform: none; opacity: 1; }
}
.mjg-deal-sum { font-size: 12px; color: var(--text-m); margin-left: 4px; }
.mjg-deal-rows { display: flex; flex-direction: column; gap: 7px; }
.mjg-deal-row { display: flex; align-items: center; gap: 8px; }
.mjg-deal-who {
  flex: none; width: 62px; font-size: 12px; font-weight: 700; color: var(--text-m);
  text-align: right;
}
.mjg-deal-me { color: var(--gold2); }
.mjg-deal-tiles { display: flex; gap: 2px; flex-wrap: nowrap; min-height: 34px; }
.mjg-deal-tile { opacity: 0; animation: mjgDealTile .26s ease-out forwards; }
@keyframes mjgDealTile {
  from { opacity: 0; transform: translateY(-14px) rotate(-6deg); }
  to { opacity: 1; transform: none; }
}
.mjg-deal-skip { font-size: 11.5px; color: var(--text-m); text-align: center; margin-top: 14px; }

@media (prefers-reduced-motion: reduce) {
  .mjg-deal-tile, .mjg-die { animation: none; opacity: 1; }
}
@media (prefers-reduced-motion: reduce) {
  .mjg-dot { animation: none; opacity: .8; }
  .mjg-tile, .mjg-btn { transition: none; }
}

/* ---------- 结算 ---------- */
.mjg-result {
  margin: 12px 0; padding: 16px 18px; border-radius: var(--r-lg);
  background: var(--card); border: 1px solid var(--border-a); box-shadow: var(--shadow);
}
.mjg-res-title { font-size: 17px; font-weight: 800; color: var(--gold2); margin-bottom: 10px; }
.mjg-res-hand { display: flex; gap: 4px; flex-wrap: wrap; align-items: center; margin-bottom: 10px; }
.mjg-res-line { font-size: 14px; color: var(--text-d); margin: 4px 0; }
.mjg-res-big { font-size: 16px; color: var(--text); }
.mjg-res-big b { color: var(--gold2); }
.mjg-res-dim { font-size: 12px; color: var(--text-m); }
.mjg-res-yaku { display: flex; gap: 6px; flex-wrap: wrap; margin: 8px 0; }
.mjg-yaku {
  display: inline-flex; align-items: baseline; gap: 5px; padding: 4px 10px; border-radius: 999px;
  background: rgba(212, 175, 55, .14); border: 1px solid var(--border-a);
  font-size: 12px; color: var(--text-d);
}
.mjg-yaku b { color: var(--gold2); }
.mjg-res-final { margin-top: 14px; padding-top: 12px; border-top: 1px solid var(--border); }
/* 分享卡（第 25 轮新增：纯前端 Canvas 战绩图） */
.mjg-res-actions { margin-top: 14px; }
.mjg-share-btn { display: inline-flex; align-items: center; gap: 8px; min-height: 44px; padding: 10px 18px; border: 1px solid rgba(212,175,55,.45); border-radius: 10px; background: rgba(212,175,55,.10); color: var(--gold2); font: inherit; font-size: 14px; cursor: pointer; }
.mjg-share-btn:hover { background: rgba(212,175,55,.20); border-color: var(--gold); }
.mjg-share-mask { position: fixed; inset: 0; z-index: 200; display: flex; align-items: center; justify-content: center; padding: 20px; background: rgba(0,0,0,.72); }
.mjg-share-dialog { max-width: min(92vw, 460px); max-height: 92vh; overflow: auto; background: var(--card-h); border: 1px solid var(--border-a); border-radius: 16px; padding: 20px; }
.mjg-share-title { margin: 0 0 12px; font-size: 17px; color: var(--gold2); }
.mjg-share-img { display: block; width: 100%; max-width: 340px; margin: 0 auto; border-radius: 10px; border: 1px solid var(--border-a); }
.mjg-share-actions { display: flex; flex-wrap: wrap; gap: 10px; margin-top: 16px; justify-content: center; }
.mjg-share-btn2 { display: inline-flex; align-items: center; justify-content: center; min-height: 44px; padding: 10px 16px; border: 1px solid var(--border-a); border-radius: 10px; background: rgba(212,175,55,.08); color: var(--gold2); font: inherit; font-size: 14px; cursor: pointer; text-decoration: none; }
.mjg-share-btn2:hover { background: rgba(212,175,55,.18); border-color: var(--gold); }
.mjg-share-hint { margin: 12px 0 0; font-size: 13px; color: var(--text-d); text-align: center; min-height: 18px; }
.mjg-res-rank {
  display: grid; grid-template-columns: 52px 1fr auto auto; gap: 10px;
  font-size: 13px; color: var(--text-d); padding: 5px 8px; border-radius: 8px;
}
.mjg-rank-me { background: rgba(212, 175, 55, .14); color: var(--text); font-weight: 700; }

/* ---------- 统计 / 日志 ---------- */
.mjg-foot { display: grid; grid-template-columns: minmax(150px, 230px) minmax(0, 1fr); gap: 12px; margin-top: 12px; }
/* 统计改成小卡片格：原来是一列「标签 + 数字」的纯文字，占着 180px 却显得又空又散。
   改成两列卡片后数字有层级（数字比标签大一号、金色），扫一眼就能读到。
   ★ 标签用 --text-m 而不是更浅的色 —— 卡片底上再浅就不达标了（这条被审计盯着）。 */
.mjg-stats { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 6px; align-content: start; }
.mjg-stat {
  display: flex; flex-direction: column; gap: 1px;
  padding: 7px 10px; border-radius: 9px;
  background: var(--card); border: 1px solid var(--border);
  font-size: 11.5px; line-height: 1.35; color: var(--text-m);
}
.mjg-stat b {
  color: var(--gold2); font-size: 16px; line-height: 1.15;
  font-variant-numeric: tabular-nums;
}
.mjg-log {
  max-height: 168px; overflow-y: auto; padding: 10px 12px; border-radius: var(--r);
  background: var(--card); border: 1px solid var(--border);
  font-size: 12.5px; line-height: 1.7; color: var(--text-d);
}
.mjg-logline { white-space: pre-wrap; word-break: break-word; }

/* ---------- 窄屏 ----------
   坑：`.mjg-tile` / `.mjg-tile-sm` / `.mjg-tile-xs` 都是单类选择器，特异性相同，
   谁在后面谁赢。第一版只在 @media 里写了 `.mjg-tile{...}`，于是 ≤520px 时
   所有牌（含宝牌指示牌、对手牌河）全被放大到 42×57，牌桌一下变得又长又挤。
   所以下面每一档尺寸都显式重写，不靠继承。 */
@media (max-width: 860px) {
  /* 手机上四边牌桌无法成立，改成纵向流式：中央信息 → 对家 → 上家 → 下家 → 自己 */
  .mjg-table {
    display: grid; grid-template-columns: minmax(0, 1fr); gap: 10px; padding: 11px;
    grid-template-areas: "center" "top" "left" "right" "self";
  }
  .mjg-tile { width: 44px; height: 58px; font-size: 18px; }
  .mjg-tile-sm { width: 28px; height: 38px; font-size: 13px; }
  .mjg-tile-xs { width: 22px; height: 30px; font-size: 11px; }
  /* 单列堆叠后「贴向中央」失去意义（四家都在同一列里），改成**整体居中** ——
     否则每个座位横跨全宽、内容全堆在左边，右侧空出一大片（768 平板竖屏最明显）。
     fit-content 在这里是安全的：flex-wrap 容器的 fit-content = min(max-content, 可用宽度)，
     不会因为「所有牌排一行的宽度」而把容器撑破。 */
  .mjg-seat-top, .mjg-seat-left, .mjg-seat-right, .mjg-seat-self { align-items: center; }
  /* 对手暗牌只表示「还剩几张」，压到最小，避免 13 张牌背占掉整行 */
  .mjg-opphand .mjg-tile { width: 24px; height: 33px; }
  .mjg-opphand .mjg-tile-sm { width: 24px; height: 33px; }
  .mjg-foot { grid-template-columns: 1fr; }
  .mjg-log { max-height: 130px; }
  /* 练习系统：窄屏下教练面板的明细改成可换行的紧凑排布 */
  .mjg-lv-desc { flex-basis: 100%; min-width: 0; }
  .mjg-coach-list { gap: 5px; }
  .mjg-deal-who { width: 48px; font-size: 11px; }
  .mjg-deal-tiles { gap: 1px; }
}
/* 平板档（521~860px）：座位已经单列堆叠、每行横跨全宽，24px 的牌背只占 312px，
   两侧各留 ~190px 空白，看着很空。这一档可用宽度 ≥ 499px，
   13~14 张 30px 牌背（420~459px）放得下，所以放大一档。
   ★ 必须夹在 521 下限：≤520 时可用宽度只有 ~336px，30px 会撑破 nowrap 容器。 */
@media (min-width: 521px) and (max-width: 860px) {
  .mjg-opphand .mjg-tile, .mjg-opphand .mjg-tile-sm { width: 30px; height: 42px; }
}
@media (max-width: 520px) {
  /* 手牌保持 44×58：390px 视口下每行正好 7 张（7×47=329 ≤ 336 可用宽度），
     14 张排两行。触摸目标不缩水，这是刻意的取舍 —— 宁可多一行也不让牌变小。 */
  .mjg-tile { width: 44px; height: 58px; font-size: 18px; }
  .mjg-tile-sm { width: 26px; height: 36px; font-size: 12px; }
  .mjg-tile-xs { width: 21px; height: 29px; font-size: 11px; }
  .mjg-opphand .mjg-tile, .mjg-opphand .mjg-tile-sm { width: 22px; height: 31px; }
  .mjg-hand { column-gap: 3px; row-gap: 16px; }
  .mjg-gap { width: 0; }
  .mjg-bar { gap: 6px; }
  .mjg-badge { font-size: 12px; padding: 4px 9px; }
  .mjg-btn { font-size: 13px; padding: 9px 13px; }
  .mjg-actions { gap: 6px; }
  .mjg-res-rank { grid-template-columns: 44px 1fr auto; }
  .mjg-res-rank .mjg-res-dim { display: none; }
  /* 练习系统 */
  .mjg-lv { padding: 8px 11px; font-size: 12.5px; }
  .mjg-levels { padding: 9px 10px; gap: 6px; }
  .mjg-uke { bottom: -12px; font-size: 9px; }
  .mjg-coach { padding: 10px 11px; }
  .mjg-coach-best { font-size: 13px; }
  .mjg-coach-best b { font-size: 15px; }
  .mjg-ukebar { width: 22px; }
  .mjg-deal-card { padding: 15px 13px; }
  .mjg-deal-who { width: 40px; font-size: 10px; }
  .mjg-deal-tile.mjg-tile-sm { width: 18px; height: 25px; }
  .mjg-deal-tiles { min-height: 25px; }
  .mjg-die { width: 28px; height: 28px; font-size: 15px; }
}

/* ---------- 超窄屏（≤380px）：对手暗牌不再顶破牌桌 ----------
   ★ 2026-10-04 新修。原状态：≤520px 档把对手暗牌写死成 22px，
     13 张 + 12×3px gap = 322px；而可用宽度 = 视口 − 56px
     （app padding 16×2 + 座位 padding 12×2）。
     实测溢出（左/右各这么多，因为 .mjg-opphand 是 nowrap + justify-content:center）：
       320px → 容器 264 / ±29px ；340 → 284 / ±19 ；354 → 298 / ±12 ；
       360 → 304 / ±9 ；375 → 319 / ±2 ；378 起才放得下（322）。
     溢出部分被 html>body 的 overflow-x:hidden 裁掉 —— 所以**看不到横滚条**，
     但视觉上牌背贴到屏幕两边、顶破牌桌圆角（≤377px 全中，含 360/375 两个主流宽度）。
     ★ 解法复用桌面端（≥861px）那一招：让牌背在容器内等比收缩。
       这里容器是 width:100%（**不是** fit-content），所以 flex:1 1 0 不会塌缩到 0
       —— 正是「fit-content 才塌缩」这条判据的安全侧。
       max-width 兜住上限：到 380px 以上牌背不会被反过来拉大。 */
@media (max-width: 380px) {
  .mjg-opphand .mjg-tile, .mjg-opphand .mjg-tile-sm {
    flex: 1 1 0; min-width: 0; max-width: 22px;
    width: auto; height: auto; aspect-ratio: 22 / 31;
  }

  /* 发牌卡：牌背同样在超窄屏冲出卡片（320px 实测右溢 32px，四行牌背
     全被屏幕右边缘切掉）。成因同源 —— .mjg-deal-tiles 是 nowrap，
     13 张写死 18px + gap 12×2px = 258px，而卡片内容宽只有 268px，
     再减 .mjg-deal-who(40) 与 row 的 gap(8) 只剩 220px。
     实测溢出：320→32px、360→16px、375→1px；vw ≥ 376 才放得下。
     ★ 这里**不能**照抄对手暗牌那招：.mjg-deal 是 justify-content:center 的
       flex 容器，卡片的宽度是 **fit-content** —— 直接给牌背加 flex:1 1 0
       会让 min-content 变成 0，卡片跟着塌缩（实测 289px → 142px，牌区 260 → 68）。
       所以先把卡片变成**确定宽度**（width:92vw，等于它原来的 max-width 上限），
       牌背的 flex 才有确定的可用空间可分配。这样对任意窄宽度都成立，
       不是只对某一个断点成立。 */
  .mjg-deal-card { width: 92vw; }
  .mjg-deal-tiles { flex: 1 1 0; min-width: 0; }
  .mjg-deal-tile.mjg-tile-sm {
    flex: 1 1 0; min-width: 0; max-width: 18px;
    width: auto; height: auto; aspect-ratio: 18 / 25;
  }
}
/* ---------- 说明区折叠（.mjg-doc，配合 mahjong-game-ui.js 末尾的收起逻辑） ----------
   结构：HTML 里 8 个 h2 说明区包在 <details class="mjg-doc" open> 里，open 写死 ——
   无 JS / 桌面 / 打印机全展开，行为与折叠改造前完全一致（渐进增强）。
   桌面：summary 只去掉浏览器默认三角，视觉零变化（标题样式仍由 .chapter h2 提供）。
   触摸设备：JS 把 open 全部收起，说明区变成一列卡片手风琴 ——
   390px 下全页从约 7900px 缩到牌桌 + 8 行标题，牌桌成为绝对主角。 */
.mjg-doc > summary {
  list-style: none;
  cursor: default;              /* 桌面端 JS 已禁 toggle，不给「可点」的假暗示 */
}
.mjg-doc > summary::-webkit-details-marker { display: none; }
.mjg-doc > summary h2 { cursor: default; }

@media (hover:none) and (pointer:coarse) {
  .mjg-doc {
    border: 1px solid var(--border);
    border-radius: 14px;
    background: var(--card);
    margin: 12px 0;
    overflow: hidden;
  }
  /* summary = 大触摸目标（≥44px）：卡片头 = 金字标题 + 旋转箭头 */
  .mjg-doc > summary {
    display: flex; align-items: center; justify-content: space-between;
    gap: 10px; min-height: 44px; padding: 12px 16px;
    cursor: pointer; touch-action: manipulation;
    -webkit-tap-highlight-color: transparent;
  }
  .mjg-doc > summary h2 {
    margin: 0;                  /* 覆盖 .chapter h2 的 36px/14px，卡片头自己控制留白 */
    font-size: 18px; line-height: 1.35;
  }
  /* 箭头做成小圆钮（金淡底 + 描边）：390px 实测纯字符 ▾ 太弱，
     视觉上认不出「可折叠」——圆钮是手风琴通用的可点击暗示 */
  .mjg-doc > summary::after {
    content: "▾"; flex: none;
    display: inline-flex; align-items: center; justify-content: center;
    width: 30px; height: 30px; border-radius: 50%;
    background: rgba(212, 175, 55, .12);
    border: 1px solid var(--border-a);
    color: var(--gold2); font-size: 16px; line-height: 1;
    transition: transform .25s ease, background-color .15s ease;
  }
  .mjg-doc > summary:active::after { background: rgba(212, 175, 55, .25); }
  .mjg-doc[open] > summary::after { transform: rotate(180deg); }
  /* 展开态分隔线：深色主题用 --border-a（35% 金，深底上可辨）；
     浅色米白底上 35% 金仍然太淡（390px 实测视觉不可见），
     换成导航细金线同款深金棕（视觉精修轮已验证过可见性） */
  .mjg-doc[open] > summary { border-bottom: 1px solid var(--border-a); }
  :root[data-theme="light"] .mjg-doc[open] > summary {
    border-bottom-color: rgba(150, 110, 25, .35);
  }
  /* 展开后的正文：左右留白与卡片头对齐（上下间距沿用 p/ul/table 自带 margin） */
  .mjg-doc > *:not(summary) { margin-left: 16px; margin-right: 16px; }
  .mjg-doc > *:last-child { margin-bottom: 14px; }
  .mjg-doc > table { margin-left: 0; margin-right: 0; }  /* 表格本来就要满宽圆角，不吃左右白 */

}
/* ==== MJG-END ==== */

/* ==========================================================================
   第 14 轮 · WCAG 1.4.11 非文本对比度（图形对象与界面组件的可视边界）
   --------------------------------------------------------------------------
   全站 42 页 × 浅/深双主题 × 1440 实测，两类不达标：

   ① 表单控件的**可视边界**
        浅色 --border-a = rgba(180,140,50,.45) 叠在控件底 #efe7d6 上 → 1.45:1
        深色 --border-a = rgba(212,175,55,.35) 叠在控件底 #221a0b 上 → 2.13:1
      ★ 为什么必须修边界，而不是「反正每个控件都有 label」：
        控件的填充色 var(--bg2) 与页面底色只差约 1.1:1
        （浅色 #f2ecdf vs #f6f1e7），**边框是识别这个控件的唯一视觉手段**
        ⇒ 按 1.4.11 必须 ≥3:1（取「vs 控件自身底色」与「vs 页面底色」的较小者）。
      ★ 只覆盖表单控件，**不动** --border-a 本身：它另外被 40+ 处卡片边框引用，
        卡片不是 UI 组件、不属 1.4.11 范围，改它属于超范围改动。

   ② 牌桌上牌面（.dr-tile / .hq-tile）的**焦点指示**
        浅色 .dr-hand / .hq-hand 底是 rgba(0,0,0,.32)，叠在米白页面上合成
        rgb(169,165,154) 中灰（L=0.373）；全局 :focus-visible 环用
        var(--gold2)=#78601a → 对中灰只有 2.44:1。
      ★ 中灰底上「亮环」永远到不了 3:1（对纯白也只有 2.48:1）⇒ 只能换深环。
        实测 #1a1405（本站墨色）对中灰 7.45:1、对米白页底 15.7:1。
      ★ 只改浅色：深色主题下同一批牌实测已达标（桌面接近纯黑，亮金环 7+）。
   ========================================================================== */

/* ① 表单控件边界（深色 + 无 data-theme 时的兜底） */
:root .field input,
:root .field select,
:root .field textarea,
:root .ref-input { border-color: #b8952f; }        /* vs 深色控件底 min 5.60:1 */

/* ① 浅色覆盖（特异性更高，不看文件顺序） */
:root[data-theme="light"] .field input,
:root[data-theme="light"] .field select,
:root[data-theme="light"] .field textarea { border-color: #8a6c1c; }   /* vs 浅色控件底 min 4.02:1 */
/* ⚠ 浅色的 .ref-input **不在这里** —— 它的边框由 beautify.css:755 那条
   `:where(:root[data-theme="light"]) input[readonly]{border-color:... !important}`
   决定，!important 压过本块任何非 important 规则（已就地改色）。 */

/* ② 牌桌上牌面的焦点环（仅浅色） */
:root[data-theme="light"] .dr-tile:focus-visible,
:root[data-theme="light"] .hq-tile:focus-visible { outline-color: #1a1405; }

/* ==== R14-END ==== */
/* ==========================================================================
   第 15 轮 · 精致化精修（REFINE）  2026-10-17
   --------------------------------------------------------------------------
   目标：不改品牌观感（暗金 + 红褐），把「细节」做扎实 —— 统一圆角与描边、
   加强卡片的层次与边界、精修按钮/表单的交互态。

   为什么要动这几处：
     · 圆角参差：按钮 11px（本文件）／图标 15px／卡片无显式值（跟随 style.css
       的 --r=12px）／价格卡内联 16px —— 同屏出现 4 种圆角，是「拼凑感」的来源。
     · 浅色卡片「发飘」：--bz-card-bd 只有 rgba(168,128,31,.28)，叠在暖白底上
       边界几乎看不见；投影也只剩一层极淡的扩散，卡片像浮在空中。
       修法不是加粗边框（会变廉价），而是「边界 + 内描边高光 + 双层投影」一起给。
     · 表单控件无 hover/focus 反馈（原站只做了边框对比度，没做交互态）。

   原则：只做视觉，不动结构/内容；动效 respect prefers-reduced-motion；
        所有金色文字的深浅一律沿用 --gold2（浅 #78601a / 深 #f5d76e），
        保证不拉低任何一处对比度。
   ========================================================================== */
/* ==== REFINE-BEGIN ==== */

/* --- 1. 统一圆角 / 描边 / 投影令牌 --------------------------------------- */
:root{
  --bz-r-xs:7px;
  --bz-r-sm:10px;
  --bz-r-md:13px;
  --bz-r-lg:17px;
  --bz-r-xl:22px;

  /* 深色：边界略提亮，投影加一层贴地暗影 + 内描边高光，卡片才有实体感 */
  --bz-card-bd:rgba(212,175,55,.22);
  --bz-card-sh:
    0 1px 2px rgba(0,0,0,.30),
    0 12px 28px -16px rgba(0,0,0,.65),
    inset 0 1px 0 rgba(255,255,255,.075),
    inset 0 0 0 1px rgba(255,255,255,.04);
}
/* 浅色：边界 .28 → .36（可见但不厚重），投影用暖棕而不是灰黑，避免「脏」 */
:root[data-theme="light"]{
  --bz-card-bd:rgba(168,128,31,.36);
  --bz-card-sh:
    0 1px 2px rgba(120,90,20,.07),
    0 8px 18px -12px rgba(120,90,20,.28),
    0 22px 46px -28px rgba(120,90,20,.42),
    inset 0 1px 0 rgba(255,255,255,.9),
    inset 0 0 0 1px rgba(255,255,255,.55);
}

/* --- 2. 卡片：统一圆角 ------------------------------------------------ */
/* 原来是「按钮 11 / 卡 12 / 价格卡 16 / 图标 15」四种；收成一套后，
   整页看过去才会像一个设计系统，而不是几个组件拼在一起。 */
.module,
.price-card,
.faq-item,
.t-card,
.ch-card,
.stat{
  border-radius:var(--bz-r-lg) !important;
}

/* 卡片顶部一抹常驻金线：给「定制感」，与 hover 扫过的 ::before 不冲突
   （::before 是 2px 高、hover 才展开；这条是 1px 高、静止就在） */
.module::after,
.price-card::after{
  content:'';position:absolute;left:16%;right:16%;top:0;height:1px;
  background:linear-gradient(90deg,transparent,var(--bz-gold-line-a),transparent);
  pointer-events:none;
}

/* --- 3. 按钮：统一圆角 + 焦点环贴身 ------------------------------------ */
.btn,
.btn-cta-gold,
.price-card .btn,
.guarantee .btn{
  border-radius:var(--bz-r-md) !important;
}
.nav-cta{border-radius:var(--bz-r-sm) !important}
.btn-primary:focus-visible,
.btn-ghost:focus-visible,
.nav-cta:focus-visible{outline-offset:2px}

/* --- 4. 区块标题：装饰线精修（略放宽 + 中心提亮） ---------------------- */
.section-title::after{
  width:78px;
  background:linear-gradient(90deg,transparent,var(--gold) 18%,var(--bz-gold-hi) 50%,var(--gold) 82%,transparent);
}

/* --- 5. 表单控件：圆角统一 + hover / focus ----------------------------- */
.field input,
.field select,
.field textarea,
.ref-input{
  border-radius:var(--bz-r-sm) !important;
  transition:border-color var(--bz-dur) var(--bz-ease),
             box-shadow var(--bz-dur) var(--bz-ease),
             background-color var(--bz-dur) var(--bz-ease);
}
.field input:hover,
.field select:hover,
.field textarea:hover{
  border-color:var(--bz-card-bd-h) !important;
}
.field input:focus,
.field select:focus,
.field textarea:focus{
  box-shadow:0 0 0 3px rgba(212,175,55,.16);
}

/* --- 6. 网格节奏：18 → 20px，卡片之间多一口气 ------------------------- */
.grid{gap:20px}

/* --- 7. 徽章统一胶囊形 ------------------------------------------------ */
.price-card .badge,
.plan .plan-badge{
  border-radius:99px !important;
}

/* --- 无障碍：新增的过渡在「减弱动效」下同样关掉 ----------------------- */
@media (prefers-reduced-motion:reduce){
  .field input,
  .field select,
  .field textarea,
  .ref-input{transition:none !important}
}

/* --- 8. 页面专属卡片：接入同一套卡片令牌 ------------------------------- */
/* 各页内联 <style> 里另起了一套卡片类（价格页 .plan、工具箱 .tp-hub-card /
   .tp-panel、视频清单 .vitem），边框用的是更淡的 var(--border)=.15，
   在浅底上几乎看不见 —— 和通用卡片不是一套观感。这里一并接到 --bz-card-*。 */
.plan,
.tp-hub-card,
.tp-panel,
.vitem{
  background:var(--bz-card-bg) !important;
  border:1px solid var(--bz-card-bd) !important;
  box-shadow:var(--bz-card-sh);
  border-radius:var(--bz-r-lg) !important;
  transition:transform var(--bz-dur) var(--bz-ease),
             border-color var(--bz-dur) var(--bz-ease),
             box-shadow var(--bz-dur) var(--bz-ease);
}
.plan:hover,
.tp-hub-card:hover,
.tp-panel:hover,
.vitem:hover{
  border-color:var(--bz-card-bd-h) !important;
  box-shadow:var(--bz-card-sh-h);
}

/* 页面专属表单控件（工具箱 .tp-select / .tp-input）：圆角 + hover / focus */
.tp-select,
.tp-input{
  border-radius:var(--bz-r-sm) !important;
  transition:border-color var(--bz-dur) var(--bz-ease),
             box-shadow var(--bz-dur) var(--bz-ease),
             background-color var(--bz-dur) var(--bz-ease);
}
.tp-select:hover,
.tp-input:hover{border-color:var(--bz-card-bd-h) !important}
.tp-select:focus,
.tp-input:focus{box-shadow:0 0 0 3px rgba(212,175,55,.16)}

/* 反作弊页 .ac-hub-card（链接卡片，基础样式在页面内联 <style>）：
   圆角 11px / 深色压暗底 / 浅色 .28 边框 —— 接到统一令牌上。
   hover 的 translateY(-2px) 上浮是内联的，不动；底色沿用既定反馈色
   （深色金染 .07、浅色 #f8f1de，即原 840 行那条规则的值）。 */
.ac-hub-card{
  background:var(--bz-card-bg) !important;
  border:1px solid var(--bz-card-bd) !important;
  box-shadow:var(--bz-card-sh);
  border-radius:var(--bz-r-lg) !important;
}
.ac-hub-card:hover{
  border-color:var(--bz-card-bd-h) !important;
  box-shadow:var(--bz-card-sh-h);
  background:rgba(212,175,55,.07) !important;
}
:root[data-theme="light"] .ac-hub-card:hover{
  background:#f8f1de !important;
}

@media (prefers-reduced-motion:reduce){
  .plan,
  .tp-hub-card,
  .tp-panel,
  .vitem,
  .ac-hub-card,
  .tp-select,
  .tp-input{transition:none !important}
}

/* ==== REFINE-END ==== */
/* ==== MOBILE-PERF-BEGIN ==== */
/* 触摸设备「丝滑层」：把费 GPU 的效果降级，换滚动帧率
   --------------------------------------------------------------------------
   判据用 hover:none and pointer:coarse（与上面触摸目标层同一判据），
   横屏手机 / 平板同样命中，不受 640px 宽度断点限制。

   为什么只降这两类（都有实测依据，不是凭感觉）：
     · .nav 是 position:sticky —— 滚动时**每一帧**都要重算 backdrop-filter
       模糊，是移动端掉帧的头号来源（低端安卓尤其明显）；
     · REFINE 层给卡片叠了「多层外阴影 + inset 内高光」，合成层面积大、
       重绘贵，长列表滚动时同样掉帧。
   两处都**不改边框 / 圆角 / 配色**，只换与滚动性能直接相关的渲染方式，
   视觉识别度保持不变（卡片仍靠边框与圆角区分层级）。 */

@media (hover:none) and (pointer:coarse){

  /* 1. 黏性导航：玻璃拟态 → 同色系实色（只提高不透明度，色相不变） */
  .nav,
  .nav.nav-hidden{
    -webkit-backdrop-filter:none !important;
    backdrop-filter:none !important;
    background:rgba(var(--nav-glass-base), .95) !important;
    /* 实色化后丢掉了毛玻璃自带的「模糊分界」：深色主题下导航与页面底色
       明度很接近，滚动时容易糊在一起。补一条细金线 + 浅投影重新拉开层次。 */
    box-shadow:0 1px 0 rgba(212,175,55,.14), 0 6px 18px rgba(0,0,0,.30) !important;
  }
  :root[data-theme="light"] .nav,
  :root[data-theme="light"] .nav.nav-hidden{
    /* 浅色米白底上 14% 金线几乎被吃掉：换更深的金棕 + 提高不透明度 */
    box-shadow:0 1px 0 rgba(150,110,25,.30), 0 6px 18px rgba(120,90,20,.12) !important;
  }
  /* 噪点纹理是配「半透明玻璃」用的：实色底上看不出，却多一层合成 */
  .nav::before{display:none}

  /* 2. 卡片投影：多层 → 单层浅影（边框/圆角不动） */
  .module,.price-card,.faq-item,.t-card,.ch-card,.stat,
  .plan,.tp-hub-card,.tp-panel,.vitem,.ac-hub-card{
    box-shadow:0 1px 3px rgba(0,0,0,.18) !important;
  }
  :root[data-theme="light"] .module,
  :root[data-theme="light"] .price-card,
  :root[data-theme="light"] .faq-item,
  :root[data-theme="light"] .t-card,
  :root[data-theme="light"] .ch-card,
  :root[data-theme="light"] .stat,
  :root[data-theme="light"] .plan,
  :root[data-theme="light"] .tp-hub-card,
  :root[data-theme="light"] .tp-panel,
  :root[data-theme="light"] .vitem,
  :root[data-theme="light"] .ac-hub-card{
    box-shadow:0 1px 3px rgba(120,90,20,.16) !important;
  }

  /* 3. 浮层：去掉模糊（开关动画更顺，也不增加常驻合成层） */
  .vip-modal,
  .coach-confirm-mask,
  .lang-menu,
  .m2m-pin-banner{
    -webkit-backdrop-filter:none !important;
    backdrop-filter:none !important;
  }

  /* 4. 安全区：配合 viewport-fit=cover（脚本 sync_viewport.py 全站补上）。
        竖屏时这几个值都是 0、完全无副作用；横屏刘海 / PWA 全屏时才生效。
        注意 fixed/sticky 元素按 viewport 定位，不受 body padding 影响，
        所以导航要单独再补一次。 */
  .nav{
    padding-top:env(safe-area-inset-top,0px);
    padding-left:env(safe-area-inset-left,0px);
    padding-right:env(safe-area-inset-right,0px);
  }
  body{
    padding-left:env(safe-area-inset-left,0px);
    padding-right:env(safe-area-inset-right,0px);
  }
}
/* ==== MOBILE-PERF-END ==== */
