/* ==========================================================================
   四站统一设计令牌（登录 / 管理 / 听写 / 打字 共用同一份）
   --------------------------------------------------------------------------
   换肤只改 <html> 上的属性，业务 CSS 不用动：
     皮肤五套   data-theme = "verdant"(青竹新绿,默认) | "neon"(深空霓虹) | "amber"(星舰琥珀)
                           | "cherry"(樱花漫舞)       | "nebula"(星河紫梦)
     主题两种   data-mode  = "light"(浅色主题,默认)   | "dark"(深色主题)
     兼容旧值   "mint"(银河薄荷) / "bamboo"(竹青绿) → 均映射到青竹新绿（两套已合并）
     游戏场景   body[data-scene="game"] → 叠加霓虹高对比
   ========================================================================== */

/* ---------------------------------------------------------------- 樱花漫舞（2026-09-24 定稿）
   全档统一走 Tailwind pink 色阶，避免混进 rose 系的玫红：
     亮档 --hue-primary = pink-300 #F9A8D4（早先 #FB7185 是 rose，偏玫红不像粉）
     浅色主题的 --primary 取深档 —— **必须也是 pink 家族**，
     早先用 #9D174D(rose-700) 时顶栏/按钮/选中态全变深玫红，观感上仍是「红」不是「粉」。
     现取 pink-600 #DB2777：白底对比度 4.83 ≥ AA 4.5，且色相明确偏粉。 */
[data-theme="cherry"] {
  --hue-primary:       #F9A8D4;
  --hue-primary-light: #FCE7F3;
  --hue-primary-dark:  #DB2777;
  --hue-accent:        #38BDF8;
  --hue-accent-dark:   #0369A1;
  --hue-success:       #4ADE80;
  --hue-success-dark:  #15803D;
  --hue-warn:          #FCD34D;
  --hue-warn-dark:     #B45309;
  --hue-danger:        #F87171;
  --hue-danger-dark:   #B91C1C;
  --hue-deep:          #2B0A1C;
  --hue-panel:         #3D1128;
  --hue-raise:         #58203E;
  --hue-line:          #58203E;
  --hue-text:          #FFF1F6;
  --hue-text-dim:      #D9A3B8;
}

/* ---------------------------------------------------------------- 星河紫梦（2026-09-24 定稿） */
[data-theme="nebula"] {
  --hue-primary:       #A78BFA;
  --hue-primary-light: #DDD6FE;
  --hue-primary-dark:  #6D28D9;
  --hue-accent:        #FCD34D;
  --hue-accent-dark:   #B45309;
  --hue-success:       #86EFAC;
  --hue-success-dark:  #15803D;
  --hue-warn:          #FBBF24;
  --hue-warn-dark:     #B45309;
  --hue-danger:        #FCA5A5;
  --hue-danger-dark:   #B91C1C;
  --hue-deep:          #1B0B33;
  --hue-panel:         #2A1250;
  --hue-raise:         #3F1E6E;
  --hue-line:          #3F1E6E;
  --hue-text:          #F5F3FF;
  --hue-text-dim:      #B8A9DF;
}

/* ---------------------------------------------------------------- 方案 A 深空霓虹 */
[data-theme="neon"] {
  --hue-primary:       #22D3EE;
  --hue-primary-light: #67E8F9;
  --hue-primary-dark:  #0E7490;
  --hue-accent:        #F472B6;
  --hue-accent-dark:   #BE185D;
  --hue-success:       #4ADE80;
  --hue-success-dark:  #15803D;
  --hue-warn:          #FBBF24;
  --hue-warn-dark:     #B45309;
  --hue-danger:        #FB7185;
  --hue-danger-dark:   #BE123C;
  --hue-deep:          #0B1026;
  --hue-panel:         #151B3D;
  --hue-raise:         #2A3466;
  --hue-line:          #2A3466;
  --hue-text:          #E2E8F0;
  --hue-text-dim:      #94A3B8;
}

/* ---------------------------------------------------------------- 方案 B 星舰琥珀 */
[data-theme="amber"] {
  --hue-primary:       #FBBF24;
  --hue-primary-light: #FDE68A;
  --hue-primary-dark:  #B45309;
  --hue-accent:        #38BDF8;
  --hue-accent-dark:   #0369A1;
  --hue-success:       #A3E635;
  --hue-success-dark:  #4D7C0F;
  --hue-warn:          #FB923C;
  --hue-warn-dark:     #C2410C;
  --hue-danger:        #F87171;
  --hue-danger-dark:   #B91C1C;
  --hue-deep:          #17102B;
  --hue-panel:         #241841;
  --hue-raise:         #3B2C63;
  --hue-line:          #3B2C63;
  --hue-text:          #F5F3FF;
  --hue-text-dim:      #A99FC4;
}

/* ---------------------------------------------------------------- 青竹新绿（默认推荐，2026-09-24 定稿）
   由「银河薄荷 #2DD4BF（偏青）」与「竹青绿 #34D399（偏绿）」综合而来：
   主色取两者中点 #2ED3B0，既保留薄荷的清爽、又有竹青的护眼感，两套正式合并为一套。
   ⚠️ 旧的 mint / bamboo 两个 key 已废弃，但老用户 localStorage 里可能还存着，
      各站 restoreTheme() 的白名单会把它们兜底回默认（= 本套），不会白屏。 */
[data-theme="verdant"] {
  --hue-primary:       #2ED3B0;
  --hue-primary-light: #A7F3E4;
  --hue-primary-dark:  #0B6E5C;
  --hue-accent:        #818CF8;
  --hue-accent-dark:   #4338CA;
  --hue-success:       #86EFAC;
  --hue-success-dark:  #15803D;
  --hue-warn:          #FCD34D;
  --hue-warn-dark:     #B45309;
  --hue-danger:        #FCA5A5;
  --hue-danger-dark:   #B91C1C;
  --hue-deep:          #08251F;
  --hue-panel:         #0F3A31;
  --hue-raise:         #1A5548;
  --hue-line:          #1A5548;
  --hue-text:          #ECFDF9;
  --hue-text-dim:      #8FB8AF;
}

/* 兼容旧 key：老用户 localStorage 里若还是 mint / bamboo，直接映射到本套，观感不跳变 */
[data-theme="mint"],
[data-theme="bamboo"] {
  --hue-primary:       #2ED3B0;
  --hue-primary-light: #A7F3E4;
  --hue-primary-dark:  #0B6E5C;
  --hue-accent:        #818CF8;
  --hue-accent-dark:   #4338CA;
  --hue-success:       #86EFAC;
  --hue-success-dark:  #15803D;
  --hue-warn:          #FCD34D;
  --hue-warn-dark:     #B45309;
  --hue-danger:        #FCA5A5;
  --hue-danger-dark:   #B91C1C;
  --hue-deep:          #08251F;
  --hue-panel:         #0F3A31;
  --hue-raise:         #1A5548;
  --hue-line:          #1A5548;
  --hue-text:          #ECFDF9;
  --hue-text-dim:      #8FB8AF;
}

/* 默认主题 = 青竹新绿（不写 data-theme 时生效）
   必须用 :root:not([data-theme])，否则会反向覆盖上面显式指定的主题 */
:root:not([data-theme]) {
  --hue-primary: #2ED3B0; --hue-primary-light: #A7F3E4; --hue-primary-dark: #0B6E5C;
  --hue-accent: #818CF8;  --hue-accent-dark: #4338CA;
  --hue-success: #86EFAC; --hue-success-dark: #15803D;
  --hue-warn: #FCD34D;    --hue-warn-dark: #B45309;
  --hue-danger: #FCA5A5;  --hue-danger-dark: #B91C1C;
  --hue-deep: #08251F; --hue-panel: #0F3A31; --hue-raise: #1A5548; --hue-line: #1A5548;
  --hue-text: #ECFDF9; --hue-text-dim: #8FB8AF;
}

/* ================================================================ 深色模式 */
[data-mode="dark"] {
  --bg:          var(--hue-deep);
  --bg-soft:     var(--hue-panel);
  --surface:     var(--hue-panel);
  --surface-2:   var(--hue-raise);
  --border:      var(--hue-line);
  --text:        var(--hue-text);
  --text-dim:    var(--hue-text-dim);
  --primary:     var(--hue-primary);
  --primary-light: var(--hue-primary-light);
  --primary-dark:  var(--hue-primary-dark);
  --on-primary:  var(--hue-deep);
  --accent:      var(--hue-accent);
  --success:     var(--hue-success);
  --warn:        var(--hue-warn);
  --danger:      var(--hue-danger);
}

/* ================================================================ 浅色模式（默认） */
[data-mode="light"] {
  --bg:          #F8FAFC;
  --bg-soft:     #F1F5F9;
  --surface:     #FFFFFF;
  --surface-2:   #F1F5F9;
  --border:      #E2E8F0;
  --text:        #1E293B;
  --text-dim:    #64748B;
  /* 浅底上用深色档，保证正文对比度 */
  --primary:     var(--hue-primary-dark);
  --primary-light: var(--hue-primary);
  --primary-dark:  var(--hue-primary-dark);
  --on-primary:  #FFFFFF;
  --accent:      var(--hue-accent-dark);
  --success:     var(--hue-success-dark);
  --warn:        var(--hue-warn-dark);
  --danger:      var(--hue-danger-dark);
}

/* ================================================================ 游戏场景：叠加霓虹高对比 */
[data-scene="game"] {
  --primary:   #22D3EE;
  --accent:    #F472B6;
  --success:   #4ADE80;
  --warn:      #FBBF24;
  --danger:    #FB7185;
  --on-primary:#0B1026;
}
[data-scene="game"][data-mode="light"] {
  --primary:   #0E7490;
  --accent:    #BE185D;
  --success:   #15803D;
  --warn:      #B45309;
  --danger:    #BE123C;
  --on-primary:#FFFFFF;
}

/* ================================================================ 顶栏（四站共用）
   浅色：主色渐变 + 白字；深色：改用深色底 + 亮字，
   否则「亮主色底 + 白字 / 深主色底 + 黑字」都会看不清。 */
[data-mode="dark"] .app-header{
  background:linear-gradient(135deg,var(--hue-deep) 0%,var(--hue-panel) 100%);
  color:var(--hue-text);
}
[data-mode="dark"] .app-header h1{color:var(--hue-text)}
[data-mode="dark"] .user-badge{background:rgba(255,255,255,.14);color:var(--hue-text)}
/* ⚠️ 本文件的 :hover 规则全部上提到文末「@media (hover:hover)」集中块 ——
   触屏点一下 hover 态会「粘住」不消失（手指离开后仍高亮），只有真·悬停设备才该有 hover。 */

/* ================================================================ 字体与像素质感 */
:root {
  /* 像素字体只用于标题 / 数字 / 英文，正文仍用系统字体 */
  --font-display: 'Press Start 2P', 'Silkscreen', ui-monospace, 'Courier New', monospace;
  --font-body: -apple-system, BlinkMacSystemFont, 'PingFang SC', 'Microsoft YaHei', 'Segoe UI', sans-serif;
  --font-mono: ui-monospace, 'SFMono-Regular', 'Consolas', monospace;

  /* 圆角：常规 UI 统一（以听写站为基准）；像素元素单独用 --pixel-radius */
  --radius:      12px;
  --radius-sm:   8px;
  --radius-lg:   16px;
  --pixel-radius: 4px;
  --pixel-step:  4px;

  /* 阴影（听写站原值，tokens 里没有，四站共用） */
  --shadow:    0 1px 3px rgba(0,0,0,.1), 0 1px 2px rgba(0,0,0,.06);
  --shadow-md: 0 4px 6px -1px rgba(0,0,0,.1), 0 2px 4px -1px rgba(0,0,0,.06);

  /* ---- 兼容旧命名：听写站/管理端原本用这套，业务 CSS 不用改名 ---- */
  --card:        var(--surface);
  --text-muted:  var(--text-dim);
  --warning:     var(--warn);

  /* ---- 统一字号阶梯 ---- */
  --fs-xs: 12px;
  --fs-sm: 13px;
  --fs-md: 14px;
  --fs-lg: 16px;
  --fs-xl: 20px;

  /* ---- 统一控件尺寸 ---- */
  --ctl-h:    32px;   /* 输入框 / 下拉（旧命名，保留兼容） */
  --btn-h:    34px;   /* 按钮（旧命名，保留兼容；新样式一律用下面三档） */
  --side-w:   210px;  /* 左侧菜单宽度 */
  --header-h: 64px;   /* 顶栏高度 */

  /* ---- 2026-09-25 第二十九轮：按钮高度三档，四站共用 ----
     sm 32：表格内 / 工具栏紧凑按钮　md 40：常规按钮　lg 48：主操作 / 登录大按钮
     ⚠️ 用法：min-height + line-height:1.2 成对写 —— 站点 CSS 继承了 body 的 line-height:1.6，
        不压到 1.2 的话内容本身就超过 min-height，高度统一会失效。
     ⚠️ ≤720px 一律被下面 @media 里的 44px 覆盖（选择器已提权到 html .btn）。 */
  --ctl-h-sm: 32px;
  --ctl-h-md: 40px;
  --ctl-h-lg: 48px;
  --ctl-fs-sm: 12.5px;
  --ctl-fs-md: 14px;
  --ctl-fs-lg: 16px;
}

/* ================================================================ 统一基线排版
   注意：只设 body（不设 html），避免改动 rem 基准（1rem 仍 = 16px），
   防止听写站大量 1rem 系字号被整体缩放。 */
body {
  font-family: var(--font-body);
  font-size: var(--fs-md);   /* 14px —— 打字站原值，听写站由 16px 拉齐 */
  line-height: 1.6;
  /* 2026-11-03：换肤 / 明暗切换时背景与文字平滑过渡，不再硬切跳变。
     只过渡 body 自身两属性，不波及站点内元素的样式切换。 */
  transition: background-color .25s ease, color .25s ease;
}


/* ================================================================ 用户端版式（听写助手 / 打字助手共用）
   两站 HTML 结构一致（#mainApp > .app-header / .side-sec / .side-field / .side-item），
   样式统一放在这里，站点业务 CSS 不再各自维护一份，避免两站样式漂移。
   用 #mainApp 限定作用域：管理端 / 登录站也有 .app-header，不受这段影响。 */
#mainApp .app-header{
  position:sticky;top:0;z-index:100;
  display:flex;align-items:center;justify-content:space-between;
  padding:16px 20px;
  background:linear-gradient(135deg,var(--primary-dark) 0%,var(--primary) 100%);
  color:var(--on-primary);
  box-shadow:var(--shadow-md);
}
#mainApp .app-header h1{
  margin:0;font-size:1.25rem;font-weight:700;letter-spacing:.5px;
  color:var(--on-primary);
}
#mainApp .user-badge{
  display:flex;align-items:center;gap:8px;
  background:rgba(255,255,255,.15);border-radius:999px;
  padding:7px 14px;cursor:pointer;transition:background .2s;
  font-size:.82rem;font-weight:600;color:inherit;
}
@media (min-width:1024px){
  #mainApp .app-header{padding:18px 32px}
  #mainApp .app-header h1{font-size:1.4rem}
}
/* 深色：用户端顶栏换深色底 + 亮字（否则「亮主色底 + 白字」对比度不足） */
[data-mode="dark"] #mainApp .app-header{
  background:linear-gradient(135deg,var(--hue-deep) 0%,var(--hue-panel) 100%);
  color:var(--hue-text);
}
[data-mode="dark"] #mainApp .app-header h1{color:var(--hue-text)}
[data-mode="dark"] #mainApp .user-badge{background:rgba(255,255,255,.14);color:var(--hue-text)}

/* ---- 左侧菜单：分组 / 字段 / 条目 ---- */
#mainApp .side-sec{margin-bottom:14px}
#mainApp .side-sec-title{
  font-size:var(--fs-xs);font-weight:700;color:var(--text-dim);
  letter-spacing:.5px;margin:0 0 8px 4px;
}
#mainApp .side-field{margin-bottom:8px}
#mainApp .side-field label{display:block;font-size:var(--fs-xs);color:var(--text-dim);margin-bottom:3px}
#mainApp .side-field select{
  width:100%;height:var(--ctl-h);padding:0 8px;font-size:var(--fs-sm);min-width:0;
  border:1.5px solid var(--border);border-radius:var(--radius-sm);
  background:var(--surface);color:var(--text);outline:none;font-family:inherit;
}
#mainApp .side-field select:focus{border-color:var(--primary)}
#mainApp .side-field select:disabled{opacity:.5}
#mainApp .side-hint{font-size:var(--fs-xs);color:var(--text-dim);margin:2px 0 0 2px;line-height:1.5}
#mainApp .side-item{
  display:flex;align-items:center;gap:8px;
  padding:9px 10px;border-radius:var(--radius-sm);
  font-size:var(--fs-sm);font-weight:600;color:var(--text-dim);
  cursor:pointer;transition:all .18s;margin-bottom:2px;
}
#mainApp .side-item.active{background:var(--primary);color:var(--on-primary)}
#mainApp .side-item .si-ico{flex:none}
#mainApp .side-item.si-cur{opacity:.55;cursor:default}
/* .side-item:hover / .si-cur:hover 见文末 @media(hover:hover) 集中块 */

/* ================================================================ 全站加载遮罩（四站共用）
   HTML 结构（四站一致，仅 emoji 与文案不同）：
     <div class="loading-screen" id="loadingScreen">
       <div class="ls-emoji">📚</div>
       <div class="spinner"></div>
       <div class="loading-text" id="loadingText">正在初始化…</div>
     </div>
   显隐 API：showLoading(text) / hideLoading() —— 先加 .fading 做 opacity 过渡，
             250ms 后再加 .hidden 真正 display:none（不再硬切）。 */
.loading-screen{
  position:fixed;inset:0;z-index:9999;
  display:flex;flex-direction:column;align-items:center;justify-content:center;gap:16px;
  background:linear-gradient(135deg,var(--primary-dark),var(--primary));
  color:#fff;opacity:1;transition:opacity .25s ease;
}
.loading-screen .ls-emoji{font-size:3rem;line-height:1}
.loading-screen .spinner{
  width:48px;height:48px;border:4px solid rgba(255,255,255,.3);
  border-top-color:#fff;border-radius:50%;animation:spin 1s linear infinite;
}
@keyframes spin{to{transform:rotate(360deg)}}
.loading-screen .loading-text{font-size:1rem;opacity:.9}
.loading-screen.fading{opacity:0;pointer-events:none}
.loading-screen.hidden{display:none}
/* 遮罩随机粒子（2026-09-24 第七轮任务4）：showLoading() 每次随机「下落」或「上升」一种，
   DOM 由各站 showLoading() 内联生成（.ls-particles 容器懒创建），hideLoading() 清空 */
.loading-screen .ls-particles{position:absolute;inset:0;overflow:hidden;pointer-events:none}
.loading-screen .ls-p{position:absolute;top:0;left:var(--left);font-size:var(--size);
  will-change:transform,opacity;animation:ls-fall var(--dur) ease-in var(--delay) both}
.loading-screen .ls-p.rise{animation-name:ls-rise;animation-timing-function:ease-out}
@keyframes ls-fall{from{transform:translate(0,-10vh) rotate(0)}
                   to{transform:translate(var(--dx),110vh) rotate(var(--dr));opacity:0}}
@keyframes ls-rise{from{transform:translate(0,110vh) scale(.6);opacity:0}
                   20%{opacity:1}
                   to{transform:translate(var(--dx),-10vh) scale(1);opacity:0}}
@media (prefers-reduced-motion: reduce){.loading-screen .ls-particles{display:none}}
/* 深色模式：主色在深色档是亮色，白字压不住 → 改深底 + 亮字 */
[data-mode="dark"] .loading-screen{
  background:linear-gradient(135deg,var(--hue-deep) 0%,var(--hue-panel) 100%);
  color:var(--hue-text);
}
[data-mode="dark"] .loading-screen .spinner{
  border-color:rgba(255,255,255,.25);border-top-color:var(--hue-primary);
}
@media (prefers-reduced-motion:reduce){
  .loading-screen{transition:none}
  .loading-screen .spinner{animation-duration:2s}
}

/* ================================================================ 原生控件统一美化（四站共用）
   问题：系统 select / checkbox 是灰白原生样式，混在主题色里很突兀（审计发现 30 处）。
   做法：appearance:none 抹掉原生外观，再用主题变量重画。
   ⚠️ 只改外观不改结构，onchange / checked 等所有 JS 行为完全不变。 */

/* ---- select：自定义箭头（内联 SVG 随 --text-dim 变色，不依赖外部资源） ---- */
select{
  appearance:none;-webkit-appearance:none;-moz-appearance:none;
  padding-right:30px !important;           /* 给箭头留位 */
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath fill='%2364748B' d='M1 1.5 6 6.5 11 1.5'/%3E%3C/svg%3E");
  background-repeat:no-repeat;
  background-position:right 10px center;
  background-size:11px;
  cursor:pointer;
}
/* 深色主题：箭头换成浅色，否则深底上看不见 */
[data-mode="dark"] select{
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath fill='%2394B8C7' d='M1 1.5 6 6.5 11 1.5'/%3E%3C/svg%3E");
}
select:disabled{opacity:.5;cursor:not-allowed}

/* ---- checkbox：统一 18×18，勾用主题主色 ---- */
input[type="checkbox"]{
  appearance:none;-webkit-appearance:none;-moz-appearance:none;
  width:18px;height:18px;flex:none;
  border:2px solid var(--border);border-radius:4px;
  background:var(--surface);cursor:pointer;
  vertical-align:middle;position:relative;
  transition:background .15s,border-color .15s;
}
input[type="checkbox"]:checked{
  background:var(--primary);border-color:var(--primary);
}
input[type="checkbox"]:checked::after{
  content:'';position:absolute;left:4px;top:1px;
  width:5px;height:9px;
  border:solid var(--on-primary);border-width:0 2px 2px 0;
  transform:rotate(45deg);
}
input[type="checkbox"]:focus-visible{outline:2px solid var(--primary);outline-offset:2px}

/* ================================================================ 触摸目标下限（移动端）
   审计发现：按钮 26~30px、inline 链接 16~19px，低于移动端 44px 可点标准。
   只在粗指针设备（触屏）放大，不改动 PC 视觉。 */
@media (pointer:coarse){
  button,.btn,.side-item,.op-group button{
    min-height:44px;
  }
  /* 行内小链接（如「全选」「忘记密码」）：不改高度，改可点区域 padding */
  .select-all-link,.login-hint,.side-hint a{
    display:inline-block;padding:8px 6px;margin:-8px -6px;
  }
  /* ⚠️ 2026-09-25 删除：这里原有一条 `button.btn-sm{min-height:36px}`（元素+类，权重 0,1,1），
     高于下方 ≤720px 块里的 `.btn-sm`（权重 0,1,0），导致触屏设备上所有小按钮被压回 36px，
     与同排 44px 的 input / select 不齐（词库页搜索框 44、旁边筛选按钮 36）。
     小按钮同样要求 44px 命中区，故删掉例外，统一走 44。 */

  /* ⚠️ 2026-10-14 补齐（PC / 移动端不统一的真凶之一）：
     上面那条是**元素选择器** `button`（权重 0,0,1），而站点 CSS 在 theme.css 之后加载，
     里面的 `.btn-sm{min-height:var(--ctl-h-sm)}` 是**类选择器**（0,1,0）→ 把它压回 32px。
     结果：**触屏但宽度 >720px** 的设备（安卓平板横屏、触控笔记本）上小按钮仍是 32px，
     而手机（≤720px，走下面 `html .btn-sm` 提权到 0,1,1）是 44px —— 两端不一致。
     这里同样用 html 前缀提权压回去，与 ≤720px 块保持同一套选择器。 */
  html .btn-sm,html .btn-outline,html .btn-primary,
  html .btn-danger,html .btn-success,html .btn-warning{
    min-height:44px;
  }
  /* 顶栏小按钮同样豁免，理由同 ≤720px 块 */
  html .app-header button,html .header-right button,html .app-header .btn{min-height:0}

  /* 播报引擎徽章（听写助手「正在播报」标题旁）：可见胶囊保持小尺寸（不撑大布局），
     命中区用透明伪元素外扩到 44px —— 与下方「复选框命中区」同一套做法：
     伪元素不占布局，不需要负 margin 抵消，视觉完全不动。
     ⚠️ 徽章自带 position:relative（见听写站 .tts-badge），否则这里定位会跑到祖先上。 */
  html .tts-badge::before{
    content:'';position:absolute;left:0;right:0;top:50%;
    transform:translateY(-50%);height:44px;background:transparent;
  }
}

/* ================================================================ 字号下限
   审计发现 11.2~11.8px 的标签 / badge 在小屏偏挤，统一抬到 12px。 */
.stat-label,.badge,.side-hint,.sys-tip,.form-group label,.side-field label{
  font-size:max(12px,var(--fs-xs));
}

/* ================================================================ 移动端：底部 Tab Bar + 侧栏转抽屉
   问题（2026-09-24 实测）：移动端侧栏竖着堆下来 687~780px，占屏 89%~100%，
   首屏可见内容只有 0~90px —— 打开页面一屏全是导航，看不到任何内容。
   方案：主功能收进底部 Tab Bar（固定 56px），侧栏改成「更多」抽屉（默认收起，可滚动）。
   ⚠️ 抽屉就是原来那个 #sidebar，不复制 DOM —— 所有 select 的 id 保持唯一，onchange 全部照旧生效。 */

#tabbar{
  display:none;                 /* PC 不显示，仅 ≤720px 打开 */
  position:fixed;left:0;right:0;bottom:0;z-index:900;
  background:var(--surface);border-top:1px solid var(--border);
  box-shadow:0 -2px 10px rgba(0,0,0,.08);
  padding-bottom:env(safe-area-inset-bottom,0);   /* iPhone 底部安全区 */
}
#tabbar .tab-item{
  flex:1;display:flex;flex-direction:column;align-items:center;justify-content:center;
  gap:2px;height:56px;min-height:56px;cursor:pointer;
  color:var(--text-dim);font-size:12px;font-weight:600;
  -webkit-tap-highlight-color:transparent;
}
#tabbar .tab-item .tab-ico{font-size:20px;line-height:1}
#tabbar .tab-item.active{color:var(--primary)}

/* ================================================================ 焦点可见（键盘可达性）
   四站 input/select 多处 outline:none 但缺少替代焦点指示，键盘用户无视觉反馈。
   统一加 :focus-visible 描边（鼠标点击时不显示，键盘 Tab 时显示）。 */
:focus-visible{outline:2px solid var(--primary);outline-offset:2px}
button:focus-visible,a:focus-visible,
input:focus-visible,select:focus-visible,textarea:focus-visible,
[tabindex]:focus-visible,[role="button"]:focus-visible{
  outline:2px solid var(--primary);outline-offset:2px;
}

/* 抽屉顶部的小横条：点它 = 收起抽屉（PC 不显示） */
.sheet-handle{display:none}
@media (max-width:720px){
  .sheet-handle{
    display:flex;align-items:center;justify-content:center;
    height:20px;margin:-6px -10px 8px;cursor:pointer;flex:none;
    -webkit-tap-highlight-color:transparent;
  }
  .sheet-handle::before{
    content:'';width:38px;height:4px;border-radius:2px;background:var(--border);
  }
}

@media (max-width:720px){
  /* 侧栏 → 底部抽屉
     ⚠️ 选择器加 html 前缀提权：两站的站点 CSS（听写内联 <style> / 打字 app.css）
        都在 theme.css 之后加载，同权重的 `#sidebar{position:sticky}` 会把抽屉按回文档流。 */
  html #sidebar{
    position:fixed;left:0;right:0;bottom:0;top:auto;
    width:100%;height:auto;min-height:0;max-height:70vh;overflow-y:auto;
    /* ⚠️ min-height:0 必须显式写：两站站点 CSS 都有 min-height:calc(100vh - 顶栏)，
       而 CSS 规范里 min-height 优先级高于 max-height，不归零的话抽屉会被撑到几乎满屏。 */
    z-index:950;
    transform:translateY(100%);transition:transform .25s ease;
    border-right:none;border-top:1px solid var(--border);
    border-radius:16px 16px 0 0;
    box-shadow:0 -6px 24px rgba(0,0,0,.2);
    padding-bottom:16px;
  }
  html #sidebar.sheet-open{transform:translateY(0)}
  /* 抽屉遮罩：独立元素，点它关闭（比 ::before 稳定，不会出现层叠问题） */
  #sheetMask{
    display:block;position:fixed;inset:0;z-index:940;
    background:rgba(0,0,0,.4);
    opacity:0;pointer-events:none;transition:opacity .25s ease;
  }
  #sheetMask.show{opacity:1;pointer-events:auto}
  #tabbar{display:flex}
  /* 主内容给 Tab Bar 让位，否则最后一块内容被挡住 */
  .app-main{padding-bottom:72px}
  .app-body{padding-bottom:0}

  /* ================================================================ 触摸目标 ≥44px（WCAG 2.5.5）
     2026-09-25：实测移动端 select/input/按钮普遍 32~36px，远低于 44px 推荐下限。
     顶栏 emoji 按钮（外观/改密/退出）豁免——它们已用 padding 撑到 ~32px 且排成一行，
     强制 44 会破坏顶栏 flex 布局。 */
  /* ⚠️ 选择器加 html 提权（0,1,1）：站点 CSS 在 theme.css 之后加载，
     下面这条若不提权，会被站点里新加的 `.btn{min-height:var(--ctl-h-md)}` 压掉。 */
  html button,html .btn,html .btn-login,html .btn-primary,html .btn-danger,html .btn-success,html .btn-warning,html .btn-outline,html .btn-sm,
  input[type=text],input[type=password],input[type=number],input[type=email],input[type=tel],input[type=search],input[type=url],
  select,textarea,
  #mainApp .user-badge,#mainApp .side-field select,#mainApp .side-field input,
  .select-all-link,.tts-select,.sheet-handle,
  .modal-box button,.modal-overlay button{
    min-height:44px;
  }
  /* 顶栏小按钮豁免：emoji + 短文字，padding 已够，强制 44 反而撑破布局 */
  .app-header button,.header-right button,.app-header .btn{min-height:0}
}
/* 关掉动画偏好时不做位移过渡 */
@media (prefers-reduced-motion:reduce){
  html #sidebar{transition:none}
}

/* ================================================================ 表格响应式卡片（≤720px）
   用法：<table data-responsive> + 每个 <td data-label="字段名">
   窄屏下 thead 隐藏，每行变一张卡，每个单元格变成「字段名: 值」的一行。
   ⚠️ 只改 display，不动 DOM 结构，所有 onclick / id 都保持有效。 */
@media (max-width:720px){
  table[data-responsive]{min-width:0 !important;}
  table[data-responsive] thead{display:none}
  table[data-responsive] tbody,
  table[data-responsive] tr{display:block;width:100%}
  table[data-responsive] tr{
    border:1px solid var(--border);border-radius:var(--radius-sm);
    padding:10px 12px;margin-bottom:10px;background:var(--surface);
  }
  table[data-responsive] td{
    display:flex;align-items:flex-start;justify-content:space-between;gap:12px;
    border:none;padding:5px 0;text-align:right;white-space:normal;
  }
  table[data-responsive] td[data-label]::before{
    content:attr(data-label);flex:none;
    color:var(--text-dim);font-size:12px;font-weight:600;text-align:left;
  }
  /* 操作列：按钮组在卡片里换行铺满，保证 44px 可点 */
  table[data-responsive] td[data-label="操作"]{display:block;text-align:left;padding-top:8px}
  table[data-responsive] td[data-label="操作"]::before{margin-bottom:6px;display:block}
  table[data-responsive] .op-group{display:flex;flex-wrap:wrap;gap:8px}
  table[data-responsive] .op-group .btn{flex:1 1 auto;min-height:44px}
}

/* ================================================================ hover 只在真·悬停设备生效
   2026-09-25：触屏点一下 hover 态会「粘住」（手指离开后高亮仍在），
   所以本文件的 :hover 规则集中收在这里，只给鼠标 / 触控板设备。
   ⚠️ 新增 hover 规则请一并放进来，不要再散写到各段。 */
@media (hover:hover){
  [data-mode="dark"] .user-badge:hover{background:rgba(255,255,255,.26)}
  #mainApp .user-badge:hover{background:rgba(255,255,255,.25)}
  [data-mode="dark"] #mainApp .user-badge:hover{background:rgba(255,255,255,.26)}
  #mainApp .side-item:hover{background:var(--bg-soft);color:var(--text)}
  #mainApp .side-item.si-cur:hover{background:transparent;color:var(--text-dim)}
}
/* ≤720px 表格卡片：去掉桌面 hover 底色（同理只在真 hover 设备需要） */
@media (max-width:720px) and (hover:hover){
  table[data-responsive] tr:hover td{background:transparent}
}

/* ================================================================ 复选框命中区（触屏）
   2026-09-25 版（已作废）：content-box + padding:13px + margin:-10px。
   ⚠️ 事故（2026-09-27「移动端复选按钮超大」）：appearance:none 重画后，padding 区域
      同样会被 background / border 填实 → 可见框从 18×18 涨到 18+13×2+2×2 = **48×48**，
      且 ::after 画的勾以 padding box 为原点、被顶到左上角。命中区是够大了，视觉却崩了。
   ✅ 现行做法：命中区用**透明伪元素**外扩，可见框与勾完全不动（仍是 18×18 居中）。
      ::before 与 ::after（勾）同为 input 的伪元素，项目本来就在用 ::after 画勾，
      浏览器支持面一致；万一某浏览器不渲染伪元素，只是降级回 18px 命中区，视觉不受影响。
   ⚠️ 伪元素不占布局，所以不需要负 margin 抵消（这也是它比 padding 方案安全的地方）。
   ⚠️ inset:-13px = (44-18)/2，向四周各外扩 13px；父级若有 overflow:hidden 会被裁掉。 */
@media (pointer:coarse){
  input[type="checkbox"]::before{
    content:'';position:absolute;inset:-13px;border-radius:8px;
    background:transparent;   /* 只为扩大点击命中区，不可见 */
  }
  /* 含复选框的 label 整行可点：打字助手 4 处（隐藏文本/语音播报/显示键位图/手型引导）、
     听写助手筛选弹窗与竖屏提示「不再提示」都命中这条。check-item 的复选框是 label 的
     兄弟节点（且 display:none），不会被 :has(>) 选中，不受影响。 */
  label:has(> input[type="checkbox"]){
    min-height:44px;
  }
}
