/* ============================================================================
   pages-practice.css —— 原 pages.css 的第 3/6 段（2026-09-19 拆分）

   原文件 3,696 行，把六种板块的样式装在了一起（《模型档位与代码质量_操作准则》
   §5 点名的技术债）。现按文件自己的 ===== 横幅拆成六段，index.html 按
   原顺序引入 —— 层叠顺序与拆分前完全一致（拆分脚本做过逐行相等校验）：

     1 pages-login.css → 2 pages-store.css → 3 pages-practice.css
     → 4 pages-identity.css → 5 pages-practice-fx.css → 6 pages-learn.css

   本段：练习页：选单元 / 设置 / 作答布局与手感
   ============================================================================ */

/* ============================================================================
   练习页（practice.js）
   ----------------------------------------------------------------------------
   配色与尺寸全部走 theme.css 的令牌，不新造颜色，保证和商店/库/成就一致。
   布局分三块：选单元、设置、答题（含结算）。

   答题区刻意做得比其它页「平」一些：
   商店页可以堆 banner 和卡片，答题时学生要盯着一个字一个字母，
   周围越安静越好。所以这里只有一条进度、一张卡、一副字母牌，
   没有装饰性元素 —— 这不是没做，是刻意不做。
   ============================================================================ */

/* ---------- 一、选单元 ---------- */

.pc-units {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
  gap: 10px;
  margin-top: 8px;
}

.pc-unit {
  display: flex;
  align-items: center;
  gap: 12px;
  width: 100%;
  min-height: 60px;
  padding: 10px 12px;
  text-align: left;
  background: var(--c-card);
  border: 1px solid transparent;
  border-radius: var(--r-md);
  color: var(--t-primary);
  cursor: pointer;
  transition: background 0.12s, border-color 0.12s;
}

.pc-unit:hover {
  background: var(--c-card-hi);
  border-color: var(--c-hover);
}

.pc-unit-no {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 38px;
  height: 38px;
  border-radius: var(--r-md);
  background: var(--c-input);
  color: var(--c-accent);
  font-size: var(--fs-lg);
  font-variant-numeric: tabular-nums;
}

.pc-unit-body {
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.pc-unit-title {
  color: var(--t-bright);
  font-size: var(--fs-lg);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.pc-unit-sub {
  color: var(--t-dim);
  font-size: var(--fs-xs);
}

/* （.pc-unit-go「✓ 已选 / 选择」已删除 —— 参看 .lib-unit 那处同样的说明。
   选中与否只由 .pc-unit.is-picked 的框体负责。） */

/* ---------- 二、练习设置 ---------- */

.pc-setup {
  margin-top: 12px;
  display: flex;
  flex-direction: column;
  gap: 4px;
}

/* ===========================================================================
   ★ 2026-10-12（S42）：共享设置面板的**标题 / 说明**两行。

   为什么要加这两个类：`ELP.practiceCore.drawPracticeSetupPanel()` 是把
   「挡位 / 本局题数 / 作答方式」这套设置**复用到任务（作业）那屏**用的 ——
   练习模式那两个设置屏自己有上层标题（`setContext` + `.detail-head`），
   而任务那屏把这块面板插在自己的一屏里，需要在面板内部能加一句标题。
   ★ 这两个类是**可选**的（不给 opt.title / opt.sub 就一个节点都不画），
     所以练习模式那两条路完全不受影响 —— 它们不传这两个字段。
   =========================================================================== */
.pc-set-title {
  padding-top: 4px;
  font-size: 17px;
  font-weight: 700;
  color: var(--t-bright);
}

.pc-set-sub {
  margin-bottom: 4px;
  font-size: 12.5px;
  line-height: 1.6;
  color: var(--t-dim);
}

.pc-set-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px;
  padding: 12px 0;
  border-bottom: 1px solid var(--c-line-soft);
}

.pc-set-row:last-child { border-bottom: 0; }

.pc-set-label {
  flex: 0 0 132px;
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.pc-set-label .t {
  color: var(--t-bright);
  font-size: var(--fs-lg);
}

.pc-set-label .h {
  color: var(--t-dim);
  font-size: var(--fs-xs);
}

.pc-set-opts {
  flex: 1 1 260px;
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

.pc-chip {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 1px;
  min-height: 46px;
  padding: 7px 13px;
  text-align: left;
  background: var(--c-input);
  border: 1px solid var(--c-line);
  border-radius: var(--r-md);
  color: var(--t-primary);
  cursor: pointer;
  transition: background 0.12s, border-color 0.12s, color 0.12s;
}

.pc-chip:hover {
  background: var(--c-hover);
  border-color: var(--c-accent-dim);
  color: var(--t-bright);
}

.pc-chip.is-on {
  background: var(--c-accent-deep);
  border-color: var(--c-accent);
  color: var(--t-bright);
}

.pc-chip .t { font-size: var(--fs-md); }
.pc-chip .h { color: var(--t-dim); font-size: var(--fs-xs); }
.pc-chip.is-on .h { color: #a9d8f5; }

/* 凑不齐的题量档（挑战固定 30/60/90，池子不够时最高档选不了）。
   ★ 不隐藏 —— 藏起来学生会以为「90 这道档根本不存在」；
     画出来、压暗、hover 不亮，点了会说明「本批只有 N 个词」。
     （和词本页那把独占锁一个道理：不给选就必须说清为什么。） */
.pc-chip.is-off {
  opacity: 0.42;
  cursor: not-allowed;
}
.pc-chip.is-off:hover {
  background: var(--c-input);
  border-color: var(--c-line);
  color: var(--t-primary);
}

/* 「词不够 90」那一行：只在凑不满最高档时出现 */
/* ★ 2026-09-21：`.pc-fill-row` / `.pc-fill-btn`（「从其他单元补词」那一行）
   随着补词设计一起删掉了 —— 现在凑不满的题量档**直接不显示**，
   没有「词不够」这个状态要提示了。相关逻辑见 practice_setup.js 里的说明。 */

.form-note.is-warn { color: #e6c15a; }

.pc-start-bar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 14px;
  margin-top: 16px;
}

/* 「已经在独立窗口练习了」的留守面板（drawDetached）。
   视觉上要一眼和「没开始」区分开：左边一条绿带 + 亮一点的底。 */
.pc-detached {
  margin-top: 18px;
  padding: 16px 18px;
  border-left: 3px solid #a6d95c;
}

.pc-detached-title {
  font-size: var(--fs-lg);
  font-weight: 600;
  color: var(--t-bright);
}

.pc-detached .lib-actions { margin-top: 12px; }

/* ==========================================================================
   练习页 —— 布局与手感（老师 2026-09-18 第二版）

   这一版针对老师提的「PC 上要放大到 200% 才正常」重做尺寸与容器宽度。

   三条尺寸原则：
     1. 答题区不再卡在 720px 中间。改 max-width 1080px ——
        PC 上字母牌一行能排开，牌和槽都能做大。
     2. 槽/牌给到 64px 档（原来是 42/48），字 30px 档（原来 22/20）。
        触控目标 44px 是下限，学习场景该往上给到 56-64。
     3. 用 clamp() 让字号跟着视口走，不要写死一个只能在某个屏上看的数。
   ========================================================================== */

.pc-quiz {
  max-width: 1080px;
  margin: 0 auto;
}

.pc-quiz-top {
  display: flex;
  flex-direction: column;
  gap: 9px;
  margin: 14px 0 22px;
}

.pc-prog-track {
  height: 8px;
  background: var(--c-input);
  border-radius: 4px;
  overflow: hidden;
}

.pc-prog-fill {
  height: 100%;
  width: 0;
  background: linear-gradient(to right, var(--c-accent-dim), var(--c-accent));
  border-radius: 4px;
  transition: width 0.25s ease;
}

.pc-counters {
  display: flex;
  align-items: center;
  gap: 18px;
  font-size: var(--fs-md);
  color: var(--t-muted);
  font-variant-numeric: tabular-nums;
}

.pc-counters .pc-score { color: var(--t-bright); }

/* 进度/题号之类的小计数 */
.pc-count { white-space: nowrap; }

/* 答题舞台：只做容器，不给视觉 */
.pc-stage { min-height: 260px; }

.pc-combo {
  color: var(--c-gold);
  margin-left: auto;
}

/* ═══════════════════════════════════════════════════════════════════════
   挑战「卷面式」（老师 2026-09-19 第二次修订）
   题号条 + 上一题/下一题 + 底部交卷条 + 交卷二次确认
   ═══════════════════════════════════════════════════════════════════════ */

/* ---- 题号条：所有字母都填满的题号变蓝（就是「学习中」那个蓝，一套语言） ---- */
.pc-qmap-row {
  display: flex;
  align-items: flex-start;
  gap: 12px;
}

.pc-qmap {
  display: flex;
  flex: 1 1 auto;
  flex-wrap: wrap;
  gap: 5px;
  /* ★ 老师 2026-09-19：题号区**高度固定**，不随题量变 ——
     30 题和 90 题的主窗口必须一样高，学生的肌肉记忆才立得住；
     题目少的时候下面空着，空着正是它的本职。
     这个 140px 是算出来的，不是估的：
       窗口 1120 宽，掐掉两侧留白、右侧「已做 N / M」一列和 12px 间隙，
       题号区约 940px；题号框固定 32px + 5px 间隙 = 每行 25 个；
       最大 90 题 = 4 行；4 × 30(高) + 3 × 5(间隙) = 135，留 5px 余量 → 140。
     题量真超了 90（或窗口更窄）就自己纵向滚 —— 那是兜底，不是常态。 */
  height: 140px;
  overflow-y: auto;
}

.pc-qchip {
  /* 固定宽高：题量再变，这一排的排布也不动（30 题与 90 题的第一行一模一样）。
     padding 归零交给按钮自带的居中 —— 有 padding 就不是固定宽了。 */
  width: 32px;
  height: 30px;
  padding: 0;
  background: var(--c-input);
  border: 1px solid var(--c-line);
  border-radius: var(--r-sm);
  color: var(--t-muted);
  font-family: var(--font);
  font-size: var(--fs-sm);
  font-variant-numeric: tabular-nums;
  cursor: pointer;
}

.pc-qchip:hover { background: var(--c-hover); color: var(--t-bright); }

/* 做过了 = 这一题的字母都填满了。★ 只看「填没填」，不看对错 ——
   配色一旦带上对错，就等于逐题泄露答案。 */
.pc-qchip.is-done {
  background: linear-gradient(90deg, var(--c-accent), var(--c-accent-dim));
  border-color: var(--c-accent-dim);
  color: var(--t-ink);
  font-weight: 700;
}

/* 当前这一题：内描边（不动 border-width，免得一排题号跟着抖） */
.pc-qchip.is-here { box-shadow: inset 0 0 0 2px var(--c-accent); }
.pc-qchip.is-done.is-here { box-shadow: inset 0 0 0 2px var(--t-bright); }

.pc-qmap-note {
  flex: 0 0 auto;
  padding-top: 5px;
  color: var(--t-dim);
  font-size: var(--fs-sm);
  white-space: nowrap;
}

/* ---- 上一题 / 下一题：在**底部工具行**（老师 2026-09-19 第二次修订）----
   与「⌫ 退一格 / 全部清空」同高、同排，分列它们两边。
   绿色来自按钮上的 .btn-confirm；「下一题」用 margin-left:auto 顶到最右边，
   所以中间那几个按钮自然居中 —— 键盘模式下这一行只有这两颗，
   也一样是一左一右。 */
.pc-nav-btn { min-width: 104px; }
.pc-nav-prev { margin-left: 0; }
.pc-nav-next { margin-left: auto; }
.pc-nav-btn:disabled { opacity: 0.4; cursor: default; }

.pc-counters .pc-done { color: var(--t-bright); }

/* ★ 房间局自己的进度（2026-09-21 第四轮）：学生要看得见"我做了多少"。
   绿色是因为它是**服务端记着的那份**（和老师看的是同一份数字），
   与上面「已做 N/M」那种本地计数区分开。只有房间局才会建这个节点。 */
.pc-counters .pc-room { color: var(--c-green-a); }

/* ---- 底部交卷条 ---- */
.pc-paper-bar {
  display: flex;
  align-items: center;
  gap: 14px;
  flex-wrap: wrap;
  margin: 18px 0 0;
  padding: 12px 14px;
  background: var(--c-card);
  border: 1px solid var(--c-line-soft);
  border-radius: var(--r-md);
}

/* ★ 「每道题都被打开以后，才会出现提交答案的按钮」——
   是「出现/不出现」，不是灰掉，所以这里必须把 hidden 压死。 */
.pc-paper-bar [hidden] { display: none !important; }

.pc-submit-paper { min-width: 148px; font-size: var(--fs-lg); }
.pc-paper-note { color: var(--t-dim); font-size: var(--fs-sm); }
.pc-undo-jump:disabled { opacity: 0.4; cursor: default; }

/* ---- 交卷二次确认：整窗遮罩，挂在 body 上 ---- */
.pc-confirm {
  position: fixed;
  inset: 0;
  z-index: 60;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 20px;
  background: rgba(10, 16, 24, 0.72);
}

.pc-confirm-box {
  width: 100%;
  max-width: 520px;
  padding: 22px 22px 18px;
  background: var(--c-card);
  border: 1px solid var(--c-line);
  border-radius: var(--r-md);
  box-shadow: 0 18px 40px rgba(0, 0, 0, 0.5);
}

.pc-cf-title { margin: 0 0 12px; font-size: var(--fs-xl); }
.pc-cf-body p { margin: 0 0 9px; }
.pc-cf-warn { color: var(--c-gold); }
.pc-cf-note { color: var(--t-dim); font-size: var(--fs-sm); }

.pc-cf-btns {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 10px;
  margin-top: 16px;
}

.pc-cf-ok { min-width: 128px; }
.pc-cf-back { min-width: 104px; }

.pc-card {
  background: var(--c-card);
  border-radius: var(--r-md);
  padding: 30px 28px 34px;
}

.pc-lead {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-bottom: 18px;
}

.pc-tier-tag {
  display: inline-flex;
  align-items: center;
  height: 24px;
  padding: 0 10px;
  border-radius: var(--r-sm);
  background: var(--c-accent-deep);
  color: #bfe3fb;
  font-size: var(--fs-sm);
}

.pc-pos {
  color: var(--t-dim);
  font-size: var(--fs-sm);
  font-style: italic;
}

.pc-pts {
  margin-left: auto;
  color: var(--t-dim);
  font-size: var(--fs-sm);
  font-variant-numeric: tabular-nums;
}

/* 题面 —— 全页视觉重心，字号刻意放大
   ★ 2026-10-13：下内边距 30px → 12px。这不是"顺手调间距"，
     而是给下面那个固定高度的提示槽**腾地方**（见 `.pc-verify-slot`）：
     零位移要求提示槽永远占位，那就得从别处把这点高度还回来，
     否则整张卡会平白高出一截。 */
.pc-prompt {
  text-align: center;
  padding: 16px 0 12px;
}

.pc-prompt-text {
  color: var(--t-bright);
  /* ★ 固定字号，理由同 `.pc-slot`：`clamp(..., vw, ...)` 在安卓 Chrome 上跟
     字母框一起出过问题（同时变小）。题面是学生盯得最久的元素，不能赌。
     窄屏另给一档，见文件末尾的 @media 640px。 */
  font-size: 34px;
  line-height: 1.4;
  word-break: break-word;
}

.pc-prompt-hint {
  margin-top: 12px;
  color: var(--t-dim);
  font-size: var(--fs-sm);
}

.pc-prompt.is-audio { padding-top: 6px; }

.pc-speak {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  min-height: 56px;
  padding: 0 30px;
  background: var(--c-accent-deep);
  border: 1px solid var(--c-accent-dim);
  border-radius: var(--r-md);
  color: var(--t-bright);
  font-size: var(--fs-xl);
  cursor: pointer;
}

.pc-speak:hover { background: var(--c-hover); }

.pc-speak-ico { font-size: 1.15em; line-height: 1; }

.pc-audio-hint {
  margin-top: 14px;
  color: var(--t-dim);
  font-size: var(--fs-sm);
}

/* --------------------------------------------------------------------------
   作答区（.pc-pad）—— 槽位在上、牌堆在下，整体居中
   -------------------------------------------------------------------------- */

/* ============================================================================
   ★★★ 2026-10-13（老师报的 bug）—— 「答对提示不能挤动布局」

   老师原话（逐字）：
     「**练习模式**，如果单词**书写正确**，会弹出一个**正确的提示**，
       这个提示**会占单词卡的位置**，于是会把**单词方块和备选字母这些东西
       往下移动**，同时也会**拉大整个输入框的大小**。这个要改提示成功的显示，
       同时**不要乱移动单词和输入框的位置**。
       （有些单词比较长，**输入框或者备选字母框会变成两行**）。」

   ▍根因（真 Chrome 量出来的，见 `_work/_selftest_cards_layout.mjs`）
     提示那一格是 `.pc-fb`，位置在**题面与作答区之间**的文档流里，
     初始 `.pc-fb{max-height:0;opacity:0}`（等于不占地方）；
     答对那一刻 `settle()` 把它换成 `.pc-verify`（`margin-top:18px;
     padding:4px 2px`）并塞进两行内容 ⇒ 它当场长高 80~130px，
     **把下面的东西整体推下去**。同一个毛病还有两处：
       · 键盘模式提交时会**现造一行 `.pc-slots.is-static` 插到提示前面**；
       · `.pc-slots` / `.pc-kb-slots` / `.pc-tiles` 都是"内容多高就多高"，
         长单词从一行变两行时卡片跟着长高。

   ▍选哪个做法：**预留固定高度的提示槽**（老师给的两个选项之一）。
     为什么不选"绝对定位浮层"：
       ① 提示里有**可点的东西**（`.pc-hear` 的「听」按钮、右键加词的
          「正确拼写」）—— 浮层要么盖住底下的字母块（那正是老师说的
          "占了单词卡的位置"），要么得给它开 pointer-events 特例，
          等于在拖拽目标上面盖一层玻璃；
       ② 浮层盖住谁、盖多少，取决于内容长度和视口，**测不出确定性**；
          而固定槽的"零位移"是**结构上成立**的，不靠运气。
     代价说清楚：这个槽**空着也占这么高**（约 84px）—— 这正是
     "内容变化不影响几何"的前提，不可能既要零位移又要空着不占位。
     为了不让卡片白白变高，把 `.pc-prompt` 的下内边距从 30px 收到 12px
     （见下面 `.pc-prompt` 那条），净增约 +66px。
   ========================================================================== */

/* 提示槽：高度钉死，空着 / 填满 / 跳过 / 答错，几何完全一样。 */
.pc-fb.pc-verify-slot {
  /* 先把 `.pc-fb` 那套"空着就 0 高、出现靠 max-height 过渡"整个关掉 ——
     那正是"提示一出来就把下面顶下去"的机制。 */
  max-height: none;
  opacity: 1;
  margin-top: 18px;
  padding: 8px 16px;
  /* 两行的高度：`.pc-fb-main` 一行 + `.pc-fb-mean`（含 36px 高的「听」按钮）
     一行。折行 / 不折行都落在同一个盒子里，外面看不见差别。 */
  height: 84px;
  min-height: 84px;
  max-height: 84px;
  /* 真塞不下（极窄屏 + 跳过那种三行内容）就**在这个槽内部滚**，
     绝不把高度放出去挤别人。 */
  overflow: auto;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  align-content: center;
  justify-content: center;
  gap: 4px 16px;
  /* ★ 取消过渡：`.pc-fb` 上那条 `transition: max-height/opacity/padding`
     会让"填进去"这件事在 0.2s 里把高度慢慢顶开 —— 哪怕最终高度一样，
     中途也会动。零位移要求"过程也不动"。 */
  transition: none;
}

/* 槽里的三行都改成"并排的一行"，别再各自带着 margin-top 往下叠。 */
.pc-fb.pc-verify-slot > .pc-fb-main { margin: 0; }
.pc-fb.pc-verify-slot > .pc-fb-mean { margin-top: 0; }
.pc-fb.pc-verify-slot > .pc-fb-answer { margin-top: 0; }
/* 标签列不再固定 76px —— 槽里横向空间比原来紧，让标签自己占宽。 */
.pc-fb.pc-verify-slot .pc-fb-answer .k,
.pc-fb.pc-verify-slot .pc-fb-mean .k { flex: 0 0 auto; }

/* ---- ① 单词方块（字母槽）：**固定两行高** ----
   64×78 的格子 + 10px 间隙 ⇒ 一行 78、两行 166。
   长单词从一行变两行，这个盒子一动不动（`align-content: flex-start`
   让第一行永远停在同一个位置，学生的手不用重新找）。
   ★ 别改成 `min-height`：min-height 只保证下限，3 行时照样长高。 */
.pc-slots {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 10px;
  height: 166px;
  min-height: 166px;
  max-height: 166px;
  align-content: flex-start;
  overflow-y: auto;
}

/* ---- ①b 拼写分段（★★★ 2026-10-17 老师立的约定） ----

   老师原话：「有些单词中间有" "、有的又有 '、有的还有 - ，学生很难输入正确的
   符号。我们做一个约定：一律给字母进行分段，不要放任何需要输入字母以外的符号，
   只需要学生输入字母，而且做一个隔断，让学生知道每个部分的单词是几个字母。」

   画法：含符号的词，槽位按段分组；段与段之间留一道更宽的空隙 + 一条淡竖线。
   ⇒ 学生看到的是 `▢▢▢▢▢▢ │ ▢▢▢▢`（6 + 4），知道这是两个词、每段几个字母，
     而**不需要输入任何符号**。

   ★ 段是 `.pc-slots` 的一个 flex item，但**段内部照样换行**
     —— 否则单段很长的词（如 11 字母）没法折行，会被挤成一行溢出。
     所以段要 `flex: 0 1 auto` + `max-width: 100%`（允许收缩到容器宽）。
   ★ 段间那条线用 `::before` 画，**绝不插入任何文字字符** ——
     插一个「|」学生会以为那是要打的东西。 */
.pc-seg {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  align-content: flex-start;
  gap: 10px;
  flex: 0 1 auto;
  max-width: 100%;
  position: relative;
}
.pc-slots[data-segs] .pc-seg + .pc-seg { margin-left: 30px; }
.pc-slots[data-segs] .pc-seg + .pc-seg::before {
  content: '';
  position: absolute;
  left: -16px;
  top: 6px;
  bottom: 6px;
  width: 2px;
  border-radius: 1px;
  background: var(--c-line);
  opacity: 0.7;
}

/* ---- ② 输入区（键盘模式的字格 + 提交后的检验行）：**共用一个固定两行的盒子** ----
   打字时显示字格、提交后显示检验行 —— 两种状态同一个盒子同一个高度，
   所以"打字越打越多"和"提交那一刻"都不会改变卡片几何。
   （DOM 侧见 practice_quiz.js 的 `.pc-letter-area`。） */
.pc-letter-area {
  /* ★ `flex-basis: 0`（不是 auto）是必须的：basis:auto 会拿**内容宽度**当基准，
     字一多这个盒子就跟着变宽 —— 实测空着 224.5px、打满 11 个字 393px。
     盒子的**宽度**和高度一样，都属于"不能让内容说了算"的那部分。
     ★ 自测就是这么抓到的：`_work/_selftest_cards_layout.mjs` 报
       `letterArea(w 224.5→393)`。 */
  flex: 1 1 0;
  min-width: 0;
  /* 取两者里高的那个：检验行是 `.pc-slots` 的两行 166px。 */
  height: 166px;
  min-height: 166px;
  max-height: 166px;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
}
.pc-letter-area > .pc-slots.is-static { margin-top: 0; width: 100%; }
.pc-letter-area > .pc-kb-slots { width: 100%; height: 100%; align-content: flex-start; }
/* 换脸用：一次只露一个 */
.is-hidden { display: none !important; }

/* ---- ③ 备选字母框：同样**固定两行高** ----
   68×68 的牌 + 12px 间隙，一行 68、两行 148。 */
.pc-tiles {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 12px;
  max-width: 860px;
  height: 148px;
  min-height: 148px;
  max-height: 148px;
  align-content: flex-start;
  overflow-y: auto;
}

/* ---- ④ 键盘模式的字格：原来是 min-height:56px（= 一行）----
   字一多就折成两行、输入区当场长高。现在交给 `.pc-letter-area` 定高。 */
.pc-kb-slots {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 8px;
  min-height: 0;
}

.pc-pad {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 34px;
}

/* ★★ 2026-09-21 老师：字母框太小、点起来非常麻烦（练习 / 挑战都一样）→ 整体放大。   原来 48–64 × 58–76、字号 24–30；现在固定 64 × 78、字号 32，约 +25%。
   ★ 真正的痛点在**窄屏**：那里原来被压到 40×50、字号 21（见文件末尾的
     @media 640px 段）—— 手机上一个字母只有指甲盖大。那一段也一起抬了。
   ★ 长单词（environment 这种 11 个字母）会折行。`flex-wrap: wrap` 本来就开着，
     折行不影响点选；但别改成 nowrap —— 那会把格子挤回去变小，等于没改。

   ★★ 为什么**不用 `clamp(58px, 6.4vw, 78px)`**（第一版就是这么写的，栽了）：
      老师在**安卓平板 Chrome** 上看到「字母框和输入框缩在一起，比『全部清空』
      那个按钮还小很多」，而**三星自带浏览器正常**。
      同一份 CSS 在两个 Chromium 上表现不同 —— 差别只能出在 `vw` 的解析与 flex
      尺寸协商上（`vw` 参与 `clamp` 之后，中间值随视口走，一旦它被算小，
      元素就贴着下限甚至被 flex 压缩）。这种不确定性不值得赌：
      改成**固定尺寸**，再用 `flex: 0 0 auto` 明说「不许压缩」——
      任何浏览器、任何视口宽度，这套数值都一模一样。
   ★ 真要按屏幕变化，走下面的媒体查询（显式、可预测），别再回到 `vw`。 */
.pc-slot {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;              /* ★ 不许被 flex 压缩 —— 「缩在一起」就是这么来的 */
  width: 64px;
  height: 78px;
  background: var(--c-input);
  border: 2px solid var(--c-line);
  border-bottom-width: 4px;
  border-radius: var(--r-md);
  color: var(--t-bright);
  font-size: 32px;
  font-weight: 500;
  font-variant-numeric: tabular-nums;
  text-transform: lowercase;
  transition: border-color 0.12s, background 0.12s, transform 0.08s;
}

.pc-slot.is-filled {
  background: var(--c-card);
  border-bottom-color: var(--c-accent);
}

/* 键盘光标所在格 */
.pc-slot.is-cursor {
  border-color: var(--c-accent);
  box-shadow: 0 0 0 3px rgba(102, 192, 244, 0.18);
}

/* 拖拽悬停目标 */
.pc-slot.is-hover {
  border-color: var(--c-accent);
  background: var(--c-hover);
  transform: translateY(-2px);
}

/* 可点性提示：已填的槽能点掉 */
.pc-slot.is-filled { cursor: pointer; }
.pc-slot.is-filled:hover { border-color: var(--c-accent-dim); }

.pc-slot-ch { pointer-events: none; }

/* 判定后的着色 —— 挑战模式绿/红 */
.pc-slots.is-ok .pc-slot { border-bottom-color: var(--c-green-a); }
.pc-slots.is-bad .pc-slot { border-bottom-color: var(--c-red-a); }

/* 练习模式：不用红色。拼错的格子用琥珀色标出「这里不一样」，
   学生知道要看哪，但不觉得在挨批评。 */
.pc-slots.is-done .pc-slot { border-bottom-color: var(--c-accent); }
.pc-slot.is-diff {
  border-color: #c9a227;
  border-bottom-color: #c9a227;
  background: rgba(201, 162, 39, 0.12);
}

/* 字母牌：牌堆。同样加大。
   ★ 2026-10-13：高度写在上面那一处（固定两行 148px），这里不再重复 ——
     同一个文件里写两遍，后写的会把先写的覆盖掉，等于给下一个改的人埋坑。 */

/* ★ 备选字母牌同样放大（老师 2026-09-21）：52–66 → 固定 68，字号 24–30 → 32。
   它是**被点/被拖**的那一方，触摸目标比槽位更要紧。
   ★ 同样用固定尺寸 + `flex: 0 0 auto`，理由见 `.pc-slot` 上面那段。 */
.pc-tile {
  display: flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
  width: 68px;
  height: 68px;
  background: linear-gradient(to bottom, #2b3d52, #22303f);
  border: 1px solid var(--c-line);
  border-radius: var(--r-md);
  color: var(--t-bright);
  font-size: 32px;
  font-weight: 500;
  text-transform: lowercase;
  cursor: pointer;
  user-select: none;
  touch-action: none;      /* 让 pointer 拖拽在触屏上不被滚动抢走 */
  transition: background 0.1s, transform 0.08s, border-color 0.1s;
}

.pc-tile:hover:not(.is-used) {
  background: var(--c-hover);
  border-color: var(--c-accent-dim);
  transform: translateY(-2px);
}

.pc-tile:active:not(.is-used) { transform: translateY(1px); }

/* 已入槽的牌：留在牌堆里但压暗，表示"这块用掉了" */
.pc-tile.is-used {
  opacity: 0.22;
  cursor: default;
}

.pc-tile.is-dragging { opacity: 0.35; }

.pc-tiles.is-locked .pc-tile { pointer-events: none; }

/* 拖拽跟手浮层 —— 挂在 body 上，position: fixed */
.pc-ghost {
  position: fixed;
  z-index: 90;
  transform: translate(-50%, -50%) scale(1.12);
  pointer-events: none;
  box-shadow: 0 10px 26px rgba(0, 0, 0, 0.5);
  opacity: 0.95;
}

/* =====================================================================
   平板防误触（老师 2026-09-21）
   ---------------------------------------------------------------------
   问题：iPad 上连点两下字母牌，Safari 把它当成**双击缩放** —— 整个页面被
   放大，练习窗口跟着变形，学生得重新调整窗口才能继续。
   ★ `touch-action: manipulation` 的语义正是「允许滚动和点击、**禁止双击缩放**」。
     `touch-action` 不是继承属性，但浏览器会把**触摸点元素到可滚动祖先**这一串的
     取值求交集 —— 所以设在答题屏这层容器上，就能覆盖它里面的每一处（题面、
     槽位、空白），同时**不碰全站其它页面**：导航、商店那几页仍然可以双指缩放
     （无障碍上要留这条路，所以没动 viewport 的 user-scalable）。
   ★ `.pc-tile` 本来就写着 `touch-action: none`（拖拽要独占），比这条更严，不用改。
   ★ `-webkit-touch-callout: none` 是另一件事：长按字母牌时别弹「拷贝 / 查询」
     那个系统菜单 —— 学生只是想按住拖动，弹菜单会打断拖拽。 */
.pc-stage,
.pc-quiz {
  touch-action: manipulation;
  -webkit-touch-callout: none;
}

/* 字母区不参与文本选择（点选、拖拽都更稳），但**输入框要留** ——
   键盘模式下学生得能用光标选字、改错。 */
.pc-slots,
.pc-tiles,
.pc-tile,
.pc-slot,
.pc-setup {
  -webkit-user-select: none;
  user-select: none;
}

.pc-input {
  -webkit-user-select: text;
  user-select: text;
}

/* ★ 房间号：这一屏最大的字（老师 2026-09-21「房间号和实际号码应该最醒目」）。
   ★ 同一份规则在 pages-classroom.css 里也有一份 —— 房间页与练习设置屏是两个页面，
     各自的 CSS 不会互相串，所以得各写一遍（改动时**两处一起改**）。 */
.cls-code-num {
  font-size: 40px;
  font-weight: 700;
  letter-spacing: 4px;
  font-variant-numeric: tabular-nums;
}

/* ---------------- 房间局「已交卷 / 已完成」的等待屏（S15，2026-09-22） ----------------
   老师拍的「等待逻辑」= 统计 + 等老师 + 看全班。
   ★ 统计那一行要比周围正文醒目一档（它是这一屏唯一属于"我"的东西），
     所以单独给它一个类，而不是借用 text-dim。 */
.pc-wait-stat {
  margin: 4px 0 6px;
  font-size: var(--fs-lg);
  color: var(--t-bright);
  font-variant-numeric: tabular-nums;
}

/* ★ 开跑前的倒数（老师 2026-09-21）—— 一个大数字占满视线。
   它只有 5 秒的存在时间，所以必须一眼看得见：要够大、够居中，
   数字宽度固定（tabular-nums）免得 5→4 时左右跳一下。 */
.pc-count-num {
  font-size: 84px;
  font-weight: 700;
  line-height: 1.15;
  text-align: center;
  color: var(--t-bright);
  font-variant-numeric: tabular-nums;
  margin: 12px 0;
}

/* =====================================================================
   键盘输入：让输入法**不进候选态**（老师 2026-09-21 第二次要求）
   ---------------------------------------------------------------------
   上一轮只挡住了「候选词填进来」—— 学生还能**看着候选栏抄**：打几个字母，
   候选栏亮出 apple，照着一敲就完事了。
   这一轮把 input 设成 `type="password"`：几乎所有输入法都对密码框**关闭联想**
   （不猜词、不弹候选、不学习），这是网页能做到的、最接近「禁用输入法」的手段。
   ★ 输入法的候选栏是**操作系统的窗口**，网页没有能力关掉它，
     也没有 API 能问出「现在是什么输入法」—— 所以只能从字段类型上绕。
   代价与对策：
     · 密码框只画圆点、也不显示 placeholder → 显示交给 `.pc-kb-slots` 那排自绘字格，
       所以 input 本体在这里**透明且缩到 1px**（仍然可聚焦，软键盘照常弹）。
     · 密码框会冒出浏览器自带的辅助按钮（眼睛 / 钥匙串 / 强密码建议）→ 下面全藏掉。
   ===================================================================== */

.pc-input {
  width: 1px;
  min-width: 1px;
  height: 1px;
  padding: 0;
  border: 0;
  background: transparent;
  color: transparent;
  caret-color: transparent;
  opacity: 0;          /* ★ 只透明，不用 display:none —— 那样就聚焦不了、软键盘不弹了 */
}

.pc-input::-ms-reveal,
.pc-input::-ms-clear,
.pc-input::-webkit-credentials-auto-fill-button,
.pc-input::-webkit-strong-password-auto-fill-button {
  display: none !important;
  visibility: hidden;
  pointer-events: none;
}

/* 自绘字格：替密码框显示已输入的字母
   ★ 2026-10-13：原来这里写的是 `min-height: 56px`（刚好一行）——
     字一多就折成两行，**输入区当场长高**，老师说的「拉大整个输入框的大小」
     就是它。现在高度交给外层 `.pc-letter-area`（固定两行 166px），
     这个盒子自己**不再有高度主张**，一行两行都不影响外面。
     ★ 尺寸与布局一条没改，只把"高度"这个变量从这一层拿掉。 */
.pc-kb-slots {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 8px;
  min-height: 0;
}

/* 键盘模式的自绘字格：尺寸向 .pc-slot 看齐（它们是同一个东西的两种画法），
   同样 `flex: 0 0 auto` 防压缩 —— 这一处正是老师看到的「输入框变得很小」。
   ★ 第一版写的 `clamp(38px, 4vw, 48px)` 与字母框一起缩在一起了，理由见 .pc-slot 上面那段。 */
.pc-kb-slot {
  display: flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
  width: 56px;
  height: 70px;
  background: var(--c-input);
  border: 2px solid var(--c-line);
  border-bottom-width: 4px;
  border-radius: var(--r-md);
  color: var(--t-bright);
  font-size: 30px;
  font-weight: 500;
  text-transform: lowercase;
}

.pc-kb-slot.is-cursor {
  border-color: var(--c-accent-dim);
}

/* 底部操作行：退格 / 清空 / 提示 */
.pc-tile-tools {
  display: flex;
  justify-content: center;
  gap: 10px;
  margin-top: 4px;
}

.pc-tile-tools .btn {
  min-height: 42px;
  padding: 0 18px;
  font-size: var(--fs-md);
}

.pc-backspace { }

/* 键盘提示（卡片模式下也能打字） */
.pc-play-hint kbd {
  display: inline-block;
  min-width: 22px;
  padding: 1px 6px;
  margin: 0 2px;
  background: var(--c-input);
  border: 1px solid var(--c-line);
  border-bottom-width: 2px;
  border-radius: 4px;
  color: var(--t-primary);
  font-family: inherit;
  font-size: 0.92em;
}

/* 键位提示条——只在卡片模式出现，讲清「也能用键盘」 */
.pc-play-hint {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 6px 14px;
  margin-top: 16px;
  color: var(--t-dim);
  font-size: var(--fs-sm);
}

/* --------------------------------------------------------------------------
   键盘输入模式
   -------------------------------------------------------------------------- */

.pc-input-wrap {
  display: flex;
  /* ★ 2026-10-13：字母区现在是**固定两行高**（`.pc-letter-area` 166px），
     不写这一条的话默认 `stretch` 会把「确认提交」按钮一起拉到 166px 高。
     居中对齐后按钮仍是它自己的 60px。 */
  align-items: center;
  gap: 12px;
  max-width: 560px;
  margin: 0 auto;
}

/* 键盘输入模式：这一行**占满整张卡**。
   ★ 2026-10-13（老师报的 bug 的收尾）：560px 里再挤掉按钮和输入框，
   字母区只剩 393px —— 一行放 5 个字母格，`environment`（11 个字母）
   要折三行，超过"预留两行"的高度就被裁掉。占满卡片之后一行放得下 15 个，
   两行够到 30 个字母；而且和字母卡片模式的 `.pc-slots`（同样占满、居中）
   是同一条版式。 */
.pc-input-wrap.pc-input-wrap-wide { max-width: none; }

.pc-input {
  /* ★★★ 2026-10-13：`flex: 1 1 auto` → `flex: 0 0 1px`。
     这个 input 是**隐形**的（上面那段：宽 1px、透明，只负责聚焦和收键盘），
     显示由 `.pc-kb-slots` 那排字格负责。可它原来带着 `flex-grow: 1` ——
     于是它和一个**同样 grow** 的兄弟平分整行：实测字母区被挤到 196px，
     11 个字母要折成 **4 行**，超出字母区固定高度后被裁掉。
     隐形的东西不该参与分配宽度，改成不伸不缩的 1px 之后，
     字母区拿到 415px，11 个字母正好两行（= 字母区预留的高度）。
     ★ 位置：必须在上面那条 `width: 1px` **之后**（文件靠后生效）。 */
  flex: 0 0 1px;
  height: 60px;
  font-size: 28px;
  letter-spacing: 2px;
  text-align: center;
  text-transform: lowercase;
}

.pc-submit { flex: 0 0 auto; min-height: 60px; padding: 0 30px; font-size: var(--fs-xl); }

/* --------------------------------------------------------------------------
   反馈条

   练习模式（.is-learn）：中性的强调色，没有红底、没有 ✕。
   挑战模式：保留 is-ok / is-bad 的绿红两态。
   -------------------------------------------------------------------------- */

.pc-fb {
  margin-top: 26px;
  padding: 0 16px;
  max-height: 0;
  overflow: hidden;
  border-radius: var(--r-md);
  opacity: 0;
  transition: max-height 0.2s ease, opacity 0.2s ease, padding 0.2s ease;
}

.pc-fb.is-show {
  max-height: 420px;
  padding: 16px 18px;
  opacity: 1;
}

.pc-fb.is-ok {
  background: rgba(117, 176, 34, 0.14);
  border-left: 3px solid var(--c-green-a);
}

.pc-fb.is-bad {
  background: rgba(192, 57, 43, 0.15);
  border-left: 3px solid var(--c-red-a);
}

/* 练习模式：中性色，不评判 */
.pc-fb.is-learn {
  background: var(--c-input);
  border-left: 3px solid var(--c-accent);
}

.pc-fb-main {
  display: flex;
  align-items: center;
  gap: 10px;
  color: var(--t-bright);
  font-size: var(--fs-xl);
}

.pc-fb.is-ok .pc-fb-icon { color: #a6d95c; }
.pc-fb.is-bad .pc-fb-icon { color: #ef8b8b; }

/* 反馈条里那句话 */
.pc-fb-text { line-height: 1.45; }

.pc-fb-answer,
.pc-fb-mean {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-top: 10px;
  font-size: var(--fs-md);
}

.pc-fb-answer .k,
.pc-fb-mean .k {
  flex: 0 0 76px;
  color: var(--t-dim);
}

.pc-fb-answer .w {
  color: var(--t-bright);
  /* ★ 固定字号（同上：不跟 `vw` 走，安卓 Chrome 上吃过亏）。
     这里是答对后亮出的正确拼写，学生要照着念、照着记，得看得清。 */
  font-size: 30px;
  font-weight: 500;
  letter-spacing: 1.5px;
  text-transform: lowercase;
}

.pc-fb-mean .v { color: var(--t-primary); }

/* 反馈里的「听」按钮 */
.pc-hear {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  min-height: 36px;
  padding: 0 14px;
  background: var(--c-accent-deep);
  border: 1px solid var(--c-accent-dim);
  border-radius: var(--r-sm);
  color: var(--t-bright);
  font-size: var(--fs-sm);
  cursor: pointer;
}

.pc-hear:hover { background: var(--c-hover); }

.pc-fb-gain {
  margin-top: 8px;
  color: #a6d95c;
  font-size: var(--fs-md);
  font-variant-numeric: tabular-nums;
}

.pc-quit {
  display: flex;
  justify-content: center;
  margin-top: 22px;
}

.pc-quit .btn { font-size: var(--fs-md); min-height: 40px; }

/* --------------------------------------------------------------------------
   四、结算
   -------------------------------------------------------------------------- */

.pc-result {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 28px;
  padding: 26px;
  margin-top: 14px;
  background: var(--c-card);
  border-radius: var(--r-md);
  border-left: 4px solid var(--c-accent);
}

.pc-result.is-best { border-left-color: var(--c-gold); }
.pc-result.is-good { border-left-color: var(--c-green-a); }
.pc-result.is-mid { border-left-color: var(--c-accent); }
.pc-result.is-low { border-left-color: var(--c-red-a); }

.pc-ring {
  flex: 0 0 auto;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  width: 140px;
  height: 140px;
  border-radius: 50%;
  background: var(--c-input);
  border: 3px solid var(--c-accent-dim);
}

.pc-result.is-best .pc-ring { border-color: var(--c-gold); }
.pc-result.is-good .pc-ring { border-color: var(--c-green-a); }
.pc-result.is-low .pc-ring { border-color: var(--c-red-a); }

.pc-ring .n {
  color: var(--t-bright);
  font-size: 38px;
  line-height: 1.1;
  font-variant-numeric: tabular-nums;
}

.pc-ring .l {
  color: var(--t-dim);
  font-size: var(--fs-sm);
}

.pc-result-right {
  flex: 1 1 300px;
  min-width: 0;
}

.pc-result-right .g {
  color: var(--t-bright);
  font-size: var(--fs-2xl);
  margin-bottom: 16px;
}

.pc-result-cells {
  display: flex;
  flex-wrap: wrap;
  gap: 30px;
}

.pc-cell .n {
  color: var(--t-bright);
  font-size: var(--fs-2xl);
  font-variant-numeric: tabular-nums;
}

.pc-cell .l {
  color: var(--t-dim);
  font-size: var(--fs-sm);
}

.pc-mastery,
.pc-wrong,
.pc-allright {
  margin-top: 16px;
}

.pc-mbars {
  display: flex;
  flex-direction: column;
  gap: 10px;
  margin-top: 12px;
}

.pc-mbar {
  display: flex;
  align-items: center;
  gap: 12px;
}

.pc-mbar .l {
  flex: 0 0 76px;
  color: var(--t-muted);
  font-size: var(--fs-md);
}

.pc-mtrack {
  flex: 1 1 auto;
  height: 10px;
  background: var(--c-input);
  border-radius: 5px;
  overflow: hidden;
}

.pc-mfill {
  height: 100%;
  width: 0;
  border-radius: 5px;
  transition: width 0.4s ease;
}

.pc-mbar.is-mastered .pc-mfill { background: var(--c-green-a); }
.pc-mbar.is-fuzzy .pc-mfill { background: var(--c-gold); }
.pc-mbar.is-weak .pc-mfill { background: var(--c-red-a); }

.pc-mbar .n {
  flex: 0 0 56px;
  text-align: right;
  color: var(--t-muted);
  font-size: var(--fs-md);
  font-variant-numeric: tabular-nums;
}

.pc-wrong-list {
  display: flex;
  flex-wrap: wrap;
  gap: 9px;
  margin: 12px 0 16px;
}

.pc-wrong-word {
  display: inline-flex;
  align-items: center;
  height: 36px;
  padding: 0 14px;
  background: rgba(192, 57, 43, 0.14);
  border: 1px solid rgba(192, 57, 43, 0.4);
  border-radius: var(--r-sm);
  color: #f0b3ac;
  font-size: var(--fs-md);
  letter-spacing: 0.5px;
}

/* 练习模式的错词标签：中性色，不是"错误提示" */
.pc-wrong-word.is-learn {
  background: var(--c-input);
  border-color: var(--c-line);
  color: var(--t-primary);
}

.pc-wrong-more { color: var(--t-dim); font-size: var(--fs-sm); align-self: center; }

.pc-allright {
  color: #a6d95c;
  border-left: 3px solid var(--c-green-a);
}

.pc-result-acts { margin-top: 18px; flex-wrap: wrap; }

#pc-save-tip.is-ok { color: #9dc95c; }
#pc-save-tip.is-bad { color: #e08a80; }

/* --------------------------------------------------------------------------
   窄屏 / 平板
   -------------------------------------------------------------------------- */

@media (max-width: 899px) {
  .pc-card { padding: 24px 18px 26px; }
  .pc-pad { gap: 26px; }
  /* ★ 2026-10-13：备选字母框在这里换成 gap 10 —— 两行高度得跟着换，
     否则"预留两行"这句话在 641–899 这一段就是假的。 */
  .pc-tiles { gap: 10px; max-width: 100%; height: 146px; min-height: 146px; max-height: 146px; }
}

@media (max-width: 640px) {
  .pc-set-label { flex: 0 0 100%; }
  .pc-set-opts { flex: 1 1 100%; }
  .pc-prompt-text { font-size: 24px; }
  .pc-prompt { padding: 12px 0 12px; }
  /* ★★ 窄屏原来是 40×50 / 字号 21、字母牌 44 —— 手机上根本点不准，
     这正是老师说的「字母太小了点起来非常麻烦」的主因。
     现在抬到 54×66 / 字号 27、字母牌 60。★ 别再往小压：
     48px 是触摸目标的下限，低于它就又会变成「点三次错两次」。 */
  .pc-slot { width: 54px; height: 66px; font-size: 27px; border-bottom-width: 3px; }
  .pc-tile { width: 60px; height: 60px; font-size: 27px; }
  /* ★ 2026-10-13：槽 / 牌在窄屏各小一档，那"预留两行"的高度也要跟着换算 ——
     写死 166/148 的话窄屏就会多出一截空白（两行其实只占 142/128）。
       字母槽 2×66 + 10 = 142 ／ 字母牌 2×60 + 8 = 128 ／ 字格 2×60 + 8 = 128
       ⇒ 字母区取高的那个 = 142。 */
  .pc-slots { height: 142px; min-height: 142px; max-height: 142px; }
  .pc-tiles { height: 128px; min-height: 128px; max-height: 128px; }
  .pc-letter-area { height: 142px; min-height: 142px; max-height: 142px; }
  /* 键盘模式的字格与题面在窄屏也各让一档 —— 34px 的题面在手机上会占掉半屏 */
  .pc-kb-slot { width: 48px; height: 60px; font-size: 26px; }
  .pc-prompt-text { font-size: 28px; }
  .pc-fb-answer .w { font-size: 26px; }
  .pc-pad { gap: 20px; }
  .pc-tiles { gap: 8px; }
  /* 提示槽窄屏两行放不下（内容会自己折三行）⇒ 内部滚，几何照旧不动。 */
  .pc-fb.pc-verify-slot { height: 76px; min-height: 76px; max-height: 76px; padding: 6px 10px; }
  .pc-result { gap: 18px; padding: 18px; }
  .pc-ring { width: 96px; height: 96px; }
  .pc-ring .n { font-size: 26px; }
  .pc-result-cells { gap: 20px; }
  .pc-input { height: 52px; font-size: 22px; }
  .pc-submit { min-height: 52px; padding: 0 20px; }
  .pc-units { grid-template-columns: 1fr; }
}

/* 触屏设备：不显示 hover 位移，避免"点一下还留着浮起来"的怪状态 */
@media (hover: none) {
  .pc-tile:hover:not(.is-used) { transform: none; }
  .pc-slot.is-hover { transform: none; }
}


