:root {
  --bg: #f4f5f7;
  --surface: #ffffff;
  --text: #1f2329;
  --muted: #8b929c;
  --border: #e6e8eb;
  --primary: #2f6fed;
  --primary-soft: #eaf1ff;
  --again: #e5484d;
  --hard: #f5a524;
  --good: #22b573;
  --radius: 12px;
}

* { box-sizing: border-box; }

html, body {
  margin: 0;
  padding: 0;
  background: var(--bg);
  color: var(--text);
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Microsoft YaHei", "PingFang SC", sans-serif;
  font-size: 15px;
  line-height: 1.6;
  -webkit-tap-highlight-color: transparent;
}

button { font-family: inherit; font-size: inherit; cursor: pointer; }
input, textarea, select { font-family: inherit; font-size: inherit; }

#app { max-width: 720px; margin: 0 auto; padding: 16px 16px 88px; }
/* 没有 tabbar 的页面（门禁 / 登录 / 断网兜底）把那 88px 的导航让位收掉。
   不留这一截，门禁页总高会超出一屏，备案号被挤到屏幕外。
   类的开关在 app.js 的 watchTabbar()，不是靠 :has()（老 WebView 不认）。 */
body:not(.has-tabbar) #app { padding-bottom: 16px; }

/* ---------- 顶栏 ---------- */
.topbar {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 16px;
  /* 窄屏（手机 390px）时按钮整块换到下一行，
     否则 flex 会把标题和按钮都压扁 → 「背书助手」和「统计」被折成竖排 */
  flex-wrap: wrap;
}
.topbar h1 { font-size: 20px; font-weight: 600; margin: 0; white-space: nowrap; }
.topbar .btn { white-space: nowrap; }
.topbar .sub { color: var(--muted); font-size: 13px; }

/* ---------- 卡片容器 ---------- */
.panel {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 14px 16px;
  margin-bottom: 12px;
}

/* ---------- 卡组列表 ---------- */
.deck-item {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 14px 16px;
  margin-bottom: 10px;
  cursor: pointer;
}
.deck-item:active { background: #fafbfc; }
.deck-item .name { font-weight: 500; }
.deck-item .meta { color: var(--muted); font-size: 13px; margin-top: 2px; }
.deck-item .a-acts { display: flex; align-items: center; gap: 2px; flex: none; }
.deck-item .a-acts button {
  border: 0; background: transparent; padding: 2px 6px; font-size: 13px; color: var(--muted);
}
.deck-item .a-acts button.mini-btn { color: var(--primary); }
.badge {
  background: var(--primary-soft);
  color: var(--primary);
  border-radius: 999px;
  padding: 2px 10px;
  font-size: 13px;
  white-space: nowrap;
}
.badge.zero { background: #f0f1f3; color: var(--muted); }

/* ---------- 按钮 ---------- */
.btn {
  border: 1px solid var(--border);
  background: var(--surface);
  color: var(--text);
  border-radius: 10px;
  padding: 9px 16px;
}
.btn.primary { background: var(--primary); border-color: var(--primary); color: #fff; }
.btn.ghost { background: transparent; }
.btn.danger { color: var(--again); border-color: #f5c2c4; background: #fff; }
.btn.block { display: block; width: 100%; text-align: center; }
.btn:disabled { opacity: .5; cursor: not-allowed; }
.btn-row { display: flex; gap: 10px; flex-wrap: wrap; }

/* ---------- ICP 备案号（2026-11-03 备案通过） ----------
   管局要求首页底部悬挂并链接工信部。样式故意**极小极淡**：它不是内容，
   但也不能看不见 —— 11px 灰字是常见口径（再小手机上就糊成一条灰线）。
   ★ 底部留 60px + 安全区：`.tabbar` 是 fixed 的（z-index 60），不留这一截
     备案号正好被它盖住 —— 人眼看不见，检查时算"未悬挂"。 */
.icp-bar {
  max-width: 720px; margin: 0 auto;
  padding: 2px 16px calc(60px + env(safe-area-inset-bottom));
  text-align: center; font-size: 11px; line-height: 1.6; color: var(--muted);
}
/* 没有 tabbar 的页面不用让这 60px。门禁页是最常被"外人/核验"看到的那一屏，
   它一旦因为这一截超出一屏，备案号就掉到屏幕外（2026-11-03 实测 390×844：
   带 60px 时底边 876，去掉后 826，回到首屏内）。 */
body:not(.has-tabbar) .icp-bar {
  padding-bottom: calc(10px + env(safe-area-inset-bottom));
}
.icp-bar a { color: var(--muted); text-decoration: none; }
.icp-bar a:hover { text-decoration: underline; }
.icp-bar .icp-sep { margin: 0 6px; }

/* ---------- 底部导航 ---------- */
.tabbar {
  position: fixed;
  left: 0; right: 0; bottom: 0;
  z-index: 60;                 /* 要压住扒在它上沿的伙伴（见 .edge-pets） */
  display: flex;
  background: var(--surface);
  border-top: 1px solid var(--border);
  padding-bottom: env(safe-area-inset-bottom);
}
.tabbar button {
  flex: 1;
  border: 0;
  background: transparent;
  padding: 12px 0 14px;
  color: var(--muted);
  font-size: 14px;
}
.tabbar button.active { color: var(--primary); font-weight: 500; }

/* ---------- 复习 ---------- */
.review-card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 22px 18px;
  min-height: 180px;
  display: flex;
  flex-direction: column;
  justify-content: center;
}
.q-text { font-size: 17px; line-height: 1.75; white-space: pre-wrap; word-break: break-word; }
.a-text {
  font-size: 15px;
  line-height: 1.75;
  white-space: pre-wrap;
  word-break: break-word;
  margin-top: 16px;
  padding-top: 16px;
  border-top: 1px dashed var(--border);
  color: #3d4450;
}
.rating-row { display: flex; gap: 10px; margin-top: 14px; }
.rating-row button {
  flex: 1;
  border: 0;
  border-radius: 10px;
  padding: 14px 0;
  color: #fff;
  font-size: 15px;
}
.r-again { background: var(--again); }
.r-hard { background: var(--hard); }
.r-good { background: var(--good); }
.progress { color: var(--muted); font-size: 13px; margin-bottom: 10px; }

/* ---------- 选项 ---------- */
.option {
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 10px 12px;
  margin-top: 8px;
}
.option.correct { border-color: var(--good); background: #f0fbf5; }
.option .key { font-weight: 500; margin-right: 6px; }

/* ---------- 表单 ---------- */
.field { margin-bottom: 12px; }
.field label { display: block; font-size: 13px; color: var(--muted); margin-bottom: 6px; }
.field input[type="text"], .field textarea, .field select {
  width: 100%;
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 10px 12px;
  background: #fff;
  color: var(--text);
}
.field textarea { min-height: 160px; resize: vertical; }

/* ---------- 弹层 ---------- */
.mask {
  position: fixed;
  inset: 0;
  background: rgba(20, 22, 26, .45);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 20px;
  z-index: 50;
}
.dialog {
  background: var(--surface);
  border-radius: 14px;
  padding: 18px;
  width: 100%;
  max-width: 460px;
  max-height: 86vh;
  overflow-y: auto;
}
.dialog h2 { font-size: 16px; font-weight: 600; margin: 0 0 14px; }

/* ---------- 杂项 ---------- */
.hint { color: var(--muted); font-size: 13px; }
.empty { text-align: center; color: var(--muted); padding: 40px 0; }
.center { text-align: center; }
.toast {
  position: fixed;
  left: 50%;
  bottom: 84px;
  transform: translateX(-50%);
  background: rgba(31, 35, 41, .92);
  color: #fff;
  border-radius: 8px;
  padding: 9px 16px;
  font-size: 14px;
  z-index: 80;
}
.list-gap { margin-top: 10px; }
.card-row {
  border-bottom: 1px solid var(--border);
  padding: 10px 0;
  display: flex;
  justify-content: space-between;
  gap: 12px;
  align-items: flex-start;
}
.card-row:last-child { border-bottom: 0; }
.card-row .t { flex: 1; min-width: 0; word-break: break-word; }
.card-row .del { color: var(--muted); border: 0; background: transparent; padding: 2px 6px; }

/* 单词卡：正面居中放大 */
.q-text.word {
  text-align: center;
  font-size: 26px;
  font-weight: 500;
  letter-spacing: .5px;
  padding: 18px 0;
  word-break: break-word;
}

/* 背面按词性分行 */
.a-text .sense { padding: 3px 0; line-height: 1.6; }
.pos {
  display: inline-block;
  min-width: 52px;
  color: var(--primary);
  font-size: 13px;
  font-weight: 500;
  vertical-align: top;
}

/* ---------- 首页：打卡面板 ---------- */
.checkin .ck-row { display: flex; align-items: flex-end; }
.ck-cell { flex: 1; text-align: center; }
.ck-cell b { display: block; font-size: 26px; font-weight: 600; line-height: 1.2; }
.ck-cell span { color: var(--muted); font-size: 12px; }
.goal { margin: 16px 0 12px; }
.goal-top { display: flex; justify-content: space-between; font-size: 13px; color: var(--muted); margin-bottom: 6px; }
.bar { height: 8px; background: #eceef1; border-radius: 999px; overflow: hidden; }
.bar i { display: block; height: 100%; background: var(--primary); border-radius: 999px; }
/* 目标面板（§2.9，2026-10-26）：首页「离背完高中词汇」与统计页「背完进度」共用。
   首页那张卡是给孩子看的，所以要"有进度"的观感 —— 条子比默认 .bar 粗一圈。 */
.goal-big { margin-bottom: 12px; }
.gb-hd { display: flex; align-items: baseline; justify-content: space-between; gap: 8px;
         font-size: 13px; color: var(--muted); }
.gb-hd b { font-size: 20px; font-weight: 600; color: var(--text); line-height: 1.1; }
.gb-hd b i { font-size: 12px; font-style: normal; font-weight: 400; color: var(--muted); }
.gb-hd .gb-pct { font-size: 20px; color: var(--primary); }
.gb-bar { height: 10px; margin: 10px 0 7px; }
.gb-ft { display: flex; justify-content: space-between; gap: 8px;
         font-size: 11.5px; color: var(--muted); }
.gb-ft b { color: var(--text); font-weight: 600; }
/* .ck-row 的 flex 只写在 .checkin 里，这里必须自己声明，否则两格会上下堆叠 */
.gb-row { display: flex; align-items: flex-end; margin: 12px 0 0; }
/* 统计页「今日通过率」也是 .ck-row，同样要自己声明 flex（原来两格是上下堆叠的） */
.tr-row { display: flex; align-items: flex-end; }
.ck-row.gb-row .ck-cell b { font-size: 22px; }
.gb-mini { display: flex; justify-content: space-between; gap: 4px; margin-top: 10px; text-align: center; }
.gb-mini span { flex: 1; font-size: 11.5px; color: var(--muted); }
.gb-mini b { display: block; font-size: 17px; color: var(--text); font-weight: 600; line-height: 1.3; }
.gb-tip { margin-top: 10px; padding: 8px 10px; border-radius: 8px;
          background: #fff8e8; color: #8a6100; font-size: 12px; line-height: 1.45; }
/* PWA 装到桌面引导条（2026-10-26）：30 天只出现一次，故意做得轻，
   不能跟「今日任务」抢注意力 */
.pwa-hint { background: var(--primary-soft); border: 1px solid #cfdffb; }
.pw-hd { display: flex; align-items: center; justify-content: space-between; margin-bottom: 4px; }
.pw-hd b { font-size: 14px; color: var(--text); }
.pw-x { border: 0; background: transparent; color: var(--muted); font-size: 15px;
        padding: 2px 4px; cursor: pointer; line-height: 1; }
.pw-tx { font-size: 12.5px; color: #4a5568; line-height: 1.5; margin-bottom: 8px; }
.btn.done { background: #e9f8f1; border-color: #bfe9d5; color: #178a56; font-weight: 500; }
.quota-hint { margin: -4px 0 12px; font-size: 12px; color: var(--muted); text-align: center; }
.quota-hint b { color: var(--text); font-weight: 600; }
/* 今日复习任务单卡（首页 / 复习页共用）：份数 + 通过率 + "还有 N 张到期" */
.task-card .task-top { display: flex; align-items: baseline; justify-content: space-between; margin-bottom: 8px; }
.task-card .task-top b { font-size: 15px; font-weight: 600; }
.task-card .task-rate { font-size: 13px; color: var(--muted); }
.task-card .task-rate b { color: var(--text); font-weight: 600; }
.task-card .bar { margin-bottom: 8px; }
.task-card .task-sub { font-size: 12px; color: var(--muted); margin-bottom: 12px; }
.task-card .task-sub b { color: var(--text); font-weight: 600; }
.sec-title {
  display: flex; align-items: center; justify-content: space-between;
  margin: 20px 0 8px; font-size: 14px; color: var(--muted);
}

/* ---------- 文章：分组头（可折叠 + 组操作） ---------- */
.g-head {
  display: flex; align-items: center; gap: 8px;
  background: var(--primary-soft);
  border: 1px solid #d8e3fb;
  border-radius: var(--radius);
  padding: 9px 12px;
  margin: 18px 0 -4px;
  cursor: pointer;
  -webkit-user-select: none; user-select: none;
}
.g-head:active { filter: brightness(0.97); }
.g-head .g-caret { color: var(--primary); font-size: 12px; width: 11px; flex: none; }
.g-head .g-name { font-weight: 600; font-size: 14px; flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.g-head .g-num { color: var(--muted); font-size: 12px; flex: none; }
.g-head .g-acts { display: flex; align-items: center; gap: 2px; flex: none; }
.g-head .g-acts button { border: 0; background: transparent; padding: 2px 6px; font-size: 13px; color: var(--muted); }
.g-head .g-acts button.mini-btn { color: var(--primary); }

/* ---------- 小按钮 ---------- */
.btn.sm { padding: 6px 11px; font-size: 13px; border-radius: 8px; }

/* ---------- 词表 ---------- */
.search { display: flex; gap: 8px; margin-bottom: 10px; }
.search input {
  flex: 1; min-width: 0;
  border: 1px solid var(--border); border-radius: 10px;
  padding: 9px 12px; background: #fff; color: var(--text);
}
.chips { display: flex; gap: 8px; flex-wrap: wrap; margin-bottom: 10px; }
.chip {
  border: 1px solid var(--border); background: #fff; color: var(--muted);
  border-radius: 999px; padding: 6px 12px; font-size: 13px;
}
.chip.on { border-color: var(--primary); color: var(--primary); background: var(--primary-soft); }
.chip i { font-style: normal; color: var(--muted); margin-left: 4px; font-size: 12px; }
.chip.on i { color: var(--primary); }

/* 「刷多少」的自定义数量输入（跟随 chip 外观） */
.chip-num {
  width: 88px; border: 1px solid var(--border); background: #fff;
  border-radius: 999px; padding: 6px 12px; font-size: 13px;
  color: var(--text); text-align: center; -moz-appearance: textfield;
}
.chip-num::placeholder { color: var(--muted); }
.chip-num:focus { outline: 0; border-color: var(--primary); color: var(--primary); }
.chip-num::-webkit-outer-spin-button,
.chip-num::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }

.word-row {
  display: flex; justify-content: space-between; align-items: flex-start;
  gap: 12px; padding: 12px 0; border-bottom: 1px solid var(--border);
}
.word-row:last-child { border-bottom: 0; }
.word-row .wb { flex: 1; min-width: 0; }
.word-row .wt { font-weight: 600; font-size: 16px; margin-bottom: 2px; }
.word-row.left { border-left: 0; }
.mark-row { display: flex; gap: 6px; flex-shrink: 0; }
.mark-row button {
  border: 1px solid var(--border); background: #fff; color: var(--muted);
  border-radius: 8px; padding: 5px 10px; font-size: 13px;
}
.mark-row.big { margin-top: 14px; }
.mark-row.big button { flex: 1; padding: 12px 0; font-size: 14px; }
.m-black.on { background: #fdeaea; border-color: #e5484d; color: #c62a2f; font-weight: 600; }
.m-gray.on  { background: #eef0f3; border-color: #9aa3af; color: #5b6472; font-weight: 600; }
.m-white.on { background: #e9f8f1; border-color: #22b573; color: #178a56; font-weight: 600; }

/* ---------- 文章阅读 ---------- */
.read-tools { display: flex; gap: 8px; flex-wrap: wrap; margin-bottom: 10px; }
.legend { color: var(--muted); font-size: 13px; margin-bottom: 8px; }
.legend .dot {
  display: inline-block; width: 10px; height: 10px; border-radius: 50%;
  margin: 0 5px 0 14px; vertical-align: middle;
}
.legend .dot:first-child { margin-left: 0; }
.legend .dot.black { background: #e5484d; }
.legend .dot.gray  { background: #9aa3af; }
.legend .dot.white { background: #22b573; }
.article-body { font-size: 17px; line-height: 2; }
.topbar h1.ellipsis { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* 文章里的词：黑白灰三色标记 */
.w { border-radius: 3px; padding: 0 1px; cursor: pointer; }
.w.black { background: #fdeaea; box-shadow: inset 0 -2px 0 #e5484d; }
.w.gray  { background: #eef0f3; box-shadow: inset 0 -2px 0 #9aa3af; }
.w.white { background: transparent; }
.w:active { filter: brightness(.94); }
.w.blank {
  display: inline-block; min-width: 46px; height: 1.05em;
  background: #eef1f5; box-shadow: inset 0 -2px 0 #c3cad3;
  border-radius: 3px; vertical-align: baseline;
}
.w.blank.on { background: #fff7e6; box-shadow: inset 0 -2px 0 var(--hard); }

/* 朗读按钮 */
.speak { margin-top: 10px; align-self: center; }
.mini-btn {
  border: 0; background: transparent; color: var(--primary);
  padding: 0 0 0 10px; font-size: 13px;
}

/* 弹层里的释义不要那条上分隔线 */
.dialog .a-text { margin-top: 8px; padding-top: 0; border-top: 0; }

/* ---------- 复习：出题模式（认词 / 拼写 / 选择） ---------- */
.chips.modes { margin-bottom: 12px; }
.review-card .a-text.prompt { margin-top: 6px; padding-top: 0; border-top: 0; font-size: 16px; }
.spell-box { margin-top: 18px; }
.spell-box input {
  width: 100%; border: 1px solid var(--border); border-radius: 10px;
  padding: 14px 16px; font-size: 20px; text-align: center; letter-spacing: 1px;
  background: #fff; color: var(--text);
}
.choices { margin-top: 18px; }
.choices button {
  display: block; width: 100%; text-align: left; margin-bottom: 8px;
  border: 1px solid var(--border); background: #fff; color: var(--text);
  border-radius: 10px; padding: 13px 14px; font-size: 16px;
}
.choices button:last-child { margin-bottom: 0; }
.choices button.right { border-color: var(--good); background: #f0fbf5; color: #178a56; font-weight: 600; }
.choices button.wrong { border-color: var(--again); background: #fdeaea; color: #c62a2f; }
.result {
  margin-top: 14px; padding: 12px 14px; border-radius: 10px;
  border: 1px solid var(--border); background: #fafbfc; font-size: 15px;
}
.result.ok   { border-color: #bfe9d5; background: #f0fbf5; color: #178a56; }
.result.near { border-color: #f7dcae; background: #fff8ec; color: #a9741a; }
.result.bad  { border-color: #f5c2c4; background: #fdeaea; color: #c62a2f; }
.result .right-ans { color: var(--text); margin-top: 6px; font-size: 18px; font-weight: 600; }
/* 化学选择题：选项前挂 A/B/C/D，答完给出整段解析 */
.choices.exam button { display: flex; align-items: flex-start; gap: 8px; }
.choices.exam .op-key {
  flex: 0 0 auto; font-style: normal; font-weight: 700; font-size: 13px;
  width: 20px; height: 20px; line-height: 20px; text-align: center;
  border-radius: 6px; background: #eef1f5; color: var(--muted); margin-top: 1px;
}
.choices.exam button.right { background: #f0fbf5; }
.choices.exam button.right .op-key { background: var(--good); color: #fff; }
.choices.exam button.wrong .op-key { background: var(--again); color: #fff; }
.result .qr-back {
  color: var(--text); margin-top: 6px; font-size: 14px;
  line-height: 1.6; white-space: pre-wrap;
}

/* 弹层里的长文本框 */
.dialog textarea.tall { min-height: 220px; }
.field input[type="file"] { font-size: 13px; width: 100%; }
.field code { background: #f0f1f3; border-radius: 4px; padding: 1px 5px; font-size: 13px; }

/* ---------- 文章：三步面板 / 选项框 ---------- */
.step-panel .step-top {
  display: flex; align-items: baseline; justify-content: space-between; gap: 10px;
}
.bank-row { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; margin-bottom: 10px; }
.bank-row .bl { color: var(--muted); font-size: 13px; }
.bank-row .bk {
  background: var(--primary-soft); color: var(--primary);
  border-radius: 6px; padding: 2px 8px; font-size: 13px;
}

/* ---------- 第一步：初筛（文中挑词） ---------- */
.screen-bar {
  display: flex; align-items: center; gap: 6px; margin-bottom: 10px;
  font-size: 13px; flex-wrap: wrap;
}
.screen-bar > span { flex: 1 1 auto; min-width: 118px; color: var(--muted); }
.screen-grid {
  display: grid; grid-template-columns: repeat(4, 1fr); gap: 8px;
}
.sw {
  border: 1px solid var(--border); background: #fff; color: var(--text);
  border-radius: 10px; padding: 13px 6px; font-size: 15px; text-align: center;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.sw.bank { border-color: #cbddfb; }
.sw.on   { border-color: var(--primary); background: var(--primary-soft); color: var(--primary); font-weight: 600; }
.sw.pass { border-color: #22b573; background: #e9f8f1; color: #178a56; font-weight: 600; }
.sw.fail { border-color: #e5484d; background: #fdeaea; color: #c62a2f; font-weight: 600; }

/* 初筛倒计时（点一下可关掉限时） */
.cd {
  border: 0; background: transparent; color: var(--muted);
  font-size: 15px; font-weight: 600; padding: 4px 6px;
  font-variant-numeric: tabular-nums;
}
.cd.off { font-weight: 400; font-size: 13px; }

/* 分组翻页 */
.pager {
  display: flex; align-items: center; justify-content: center; gap: 14px;
  margin: 14px 0 2px; font-size: 13px; color: var(--muted);
}
.pager .btn[disabled] { opacity: .38; }

/* 底部操作条：「跳过挑词」独占左端（不可逆操作远离手指落区），翻页组靠右 */
.screen-foot {
  display: flex; align-items: center; gap: 10px; margin-top: 10px;
}
.screen-foot .foot-sep { width: 1px; height: 18px; background: var(--border); }
.screen-foot .pager { margin: 0 0 0 auto; gap: 10px; }

/* 后果提示条（放在操作条上方，先看到后果再动手） */
.foot-note {
  margin-top: 12px; padding: 7px 10px; border-radius: 8px;
  background: #fdf4e3; border: 1px solid #f0dcb2; color: #8a6320;
  font-size: 13px;
}

/* ---------- 中英消消乐 ---------- */
.match-bar {
  display: flex; align-items: center; justify-content: space-between;
  margin: 12px 0 10px; font-size: 14px; color: var(--muted);
}
.match-bar b { color: var(--primary); }
.match-grid {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
  gap: 8px;
}
.tile {
  min-height: 56px; padding: 8px 10px;
  border: 1px solid var(--border); border-radius: 10px; background: #fff;
  color: var(--text); font-size: 15px; line-height: 1.4;
  word-break: break-word;
  transition: transform .12s, opacity .25s, background .15s;
}
.tile.en { font-weight: 600; }
.tile.zh { color: #4a5260; font-size: 14px; }
.tile.sel { border-color: var(--primary); background: var(--primary-soft); color: var(--primary); }
.tile.bad { border-color: #e5484d; background: #fdeaea; color: #c62a2f; }
.tile.gone {
  opacity: .32; border-style: dashed; background: #f4f6f8;
  color: var(--muted); pointer-events: none;
}

/* ---------- 第二步：验证（看英文选中文） ---------- */
.ctx {
  margin-top: 12px; padding: 10px 12px; background: #f6f7f9;
  border-radius: 8px; color: #4a5260; font-size: 14px; line-height: 1.7;
}
.ctx .hl { color: var(--primary); }
.choices.mean button { line-height: 1.5; }
.op-mean { display: block; margin-top: 5px; color: var(--muted); font-size: 13px; font-weight: 400; }
.choices button.right .op-mean { color: #2f8b62; }
.choices button.wrong .op-mean { color: #b0454a; }

/* ---------- 伙伴（激励层） ---------- */

/* 折叠区（道馆 / 传说之路 / 幻兽台 / 箱子）。
   道馆打完就没用了，传说之路 28 关一屏放不下 —— 收起来，摘要行留在外面。
   用原生 <details>，箭头用 ::after 自己画（各浏览器的默认三角样式不统一）。 */
details.fold { margin: 0 0 14px; }
details.fold > summary {
  display: flex;
  align-items: baseline;
  gap: 8px;
  padding: 10px 30px 10px 14px;   /* 右边留出箭头的位置 */
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface);
  cursor: pointer;
  list-style: none;
  user-select: none;
  position: relative;
}
details.fold > summary::-webkit-details-marker { display: none; }
details.fold > summary::after {
  content: "▾";
  position: absolute;
  right: 12px;
  top: 11px;                      /* 摘要行折行时箭头也留在右上角，不跟着掉下去 */
  color: var(--muted);
  font-size: 12px;
}
details.fold[open] > summary::after { content: "▴"; }
details.fold[open] > summary { margin-bottom: 10px; }
/* 摘要行可能很长，允许折行；箭头用 margin-left:auto 留在行尾。 */
details.fold > summary > b { flex: 0 0 auto; white-space: nowrap; }
details.fold .fold-sub {
  color: var(--muted); font-size: 13px;
  flex: 1 1 0; min-width: 0; line-height: 1.45;
}
/* 传说之路折叠摘要：进度 / 已打完哪关 / 下一关 / 差多少，四块分开摆。
   以前是一整串同字号的字（「8/28 · 打过：时空之塔 · 下一关：破格的世界（要 900 白词，
   还差 12）」），手机上折两行还分不清哪个是打过的、哪个是要打的（2026-10-26 孩子反馈）。 */
details.fold .rsub { display: flex; flex-wrap: wrap; align-items: center; gap: 4px 6px; }
.rsub-prog { font-weight: 600; color: var(--text); }
.rsub-done, .rsub-next {
  font-style: normal; font-size: 12px; line-height: 18px;
  padding: 1px 7px; border-radius: 9px; white-space: nowrap;
}
.rsub-done { background: rgba(34, 181, 115, .13); color: #178a58; }
.rsub-next { background: var(--primary-soft); color: var(--primary); }
.rsub-why {
  font-style: normal; font-size: 11px; opacity: .78; margin-left: 5px;
}
details.fold .fold-body > .hint:last-child { margin-bottom: 0; }

/* ---------- 传说之路专用折叠区（手工折叠，不是 <details>） ----------
   需求原话（2026-10-26）：「收起来的状态上面有提示 2 关，下面也保留提示这两关显示出来，
   其余关隐藏。点击打开再全部显示。」
   ⇒ 收起时正文里还要露面，<details> 做不到（浏览器把正文整个藏掉；覆写 UA 样式
     Chrome 能行、Safari 不保证）⇒ 自己做 .fold-h 标题 + .all 状态。
   视觉和 <details> 那套保持一致，箭头同样用 ::after 画。 */
.fold.openable { margin: 0 0 14px; }
.fold.openable > .fold-h {
  display: flex; align-items: baseline; gap: 8px;
  padding: 10px 30px 10px 14px;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface);
  cursor: pointer; user-select: none; position: relative;
}
.fold.openable > .fold-h > b { flex: 0 0 auto; white-space: nowrap; }
.fold.openable > .fold-h::after {
  content: "▾";
  position: absolute; right: 12px; top: 11px;
  color: var(--muted); font-size: 12px;
}
.fold.openable.all > .fold-h::after { content: "▴"; }
.fold.openable > .fold-h + .fold-body { margin-top: 10px; }
.fold.openable .fold-sub {
  color: var(--muted); font-size: 13px;
  flex: 1 1 0; min-width: 0; line-height: 1.45;
}
.fold.openable .rsub { display: flex; flex-wrap: wrap; align-items: center; gap: 4px 6px; }
/* 收起时只留两格（打完的最后一关 + 下一关），其余关和下面的大段说明一律藏掉；
   展开（.all）时全部回来，提示行消失。 */
.fold.openable:not(.all) .rt-extra,
.fold.openable:not(.all) .rt-tips { display: none; }
/* 收起时第一行的顶线去掉：它前面那关被藏了，但 `.pt-route + .pt-route` 照样命中，
   不处理的话面板顶上会多一条莫名其妙的横线。 */
.fold.openable:not(.all) .rt-first { border-top: 0; }
.fold.openable .rt-more-hint { display: none; }
.fold.openable:not(.all) .rt-more-hint { display: block; margin: 8px 2px 0; }

/* 加油团：队伍里没上场的伙伴，在赢下这一场时从血条下面探头欢呼。
   纯 CSS 动画（不用 JS 定时器），img 标签上的 animation-delay 让它们依次起来。 */
.bt-rally {
  display: flex; align-items: flex-end; justify-content: center;
  gap: 3px; margin: 0 0 12px;
}
.bt-rally img {
  width: 46px; height: 46px; object-fit: contain;
  animation: rallyJump .62s ease-in-out infinite alternate;
}
.bt-rally i {
  font-style: normal; font-size: 13px; font-weight: 600;
  color: var(--primary); margin-right: 5px; align-self: center;
}
@keyframes rallyJump {
  from { transform: translateY(3px); }
  to { transform: translateY(-7px); }
}

/* 二级页的返回键：跟着屏幕走（图鉴很长，滚到哪儿都能回，不用一路滑回顶上）。
   做法不是 position:fixed 浮一个圆钮 —— 那样会压在档案条（曈曈）上面。
   改成**顶栏 sticky + 按钮绝对定位在顶栏里**：滚动时整条顶栏贴住屏幕顶部，
   按钮自然跟着走，桌面端也不用 max() 对齐 720px 容器。 */
.topbar.has-back {
  position: sticky;
  top: 0;
  z-index: 65;
  background: var(--bg);            /* 不透明，否则内容会从底下透出来 */
  padding: 6px 0 8px 52px;
  margin-top: -6px;
}
.sub-back {
  position: absolute;
  left: 0;
  top: 50%;
  transform: translateY(-50%);
  width: 40px;
  height: 40px;
  padding: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  border: 1px solid var(--border);
  border-radius: 50%;
  background: var(--surface);
  color: var(--text);
  font-size: 18px;
  line-height: 1;
  box-shadow: 0 1px 4px rgba(31, 35, 41, .10);
}
.sub-back:active { transform: translateY(-50%) scale(.94); }

.pt-points { display: flex; text-align: center; }
.pt-points .pt-cell { flex: 1; }
.pt-points .pt-cell b { display: block; font-size: 22px; color: var(--primary); }
.pt-points .pt-cell span { font-size: 12px; color: var(--muted); }

.pt-party {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 10px;
  margin-bottom: 12px;
}
.pt-slot {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 10px 8px;
  text-align: center;
  cursor: pointer;
}
.pt-slot img { width: 56px; height: 56px; image-rendering: pixelated; }
.pt-slot.empty {
  border-style: dashed;
  color: var(--muted);
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 112px;
  font-size: 13px;
}
.pt-nm {
  font-size: 13px; font-weight: 500; margin-top: 4px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.pt-lv { font-size: 12px; color: var(--muted); }
.pt-bar { height: 5px; background: #eef0f3; border-radius: 999px; overflow: hidden; margin-top: 5px; }
.pt-bar i { display: block; height: 100%; background: var(--primary); border-radius: 999px; }
.pt-ev { font-size: 11px; color: var(--good); margin-top: 3px; }

/* ---------- 调出场顺序（点一只 → 再点一只，两只换位置） ----------
   为什么不用拖拽：孩子主要在**平板上**用，HTML5 拖拽在触摸屏上时灵时不灵；
   「点两下换位」在鼠标和手指上是同一套动作，也不会误触发。 */
.ro-btn { flex: none; font-size: 12px; padding: 4px 10px; }
.ro-bar {
  display: flex; align-items: center; gap: 8px;
  background: var(--primary-soft); border: 1px solid #d8e3fb;
  border-radius: 10px; padding: 8px 12px; margin-bottom: 10px;
  font-size: 13px; color: var(--primary);
}
.ro-bar b { font-weight: 600; }
.pt-slot.pick { position: relative; cursor: pointer; }
.pt-slot.pick::after {
  content: '⇄'; position: absolute; top: 4px; right: 6px;
  font-size: 12px; color: var(--primary); opacity: .75;
}
.pt-slot.pick:active { filter: brightness(.97); }
.pt-slot.sel {
  border-color: var(--primary);
  box-shadow: 0 0 0 2px var(--primary-soft);
}
.pt-slot.sel::after { content: '①'; }
.pt-slot.empty.pick { cursor: default; }
.pt-slot.empty.pick::after { content: ''; }
.hp-slot.pick { cursor: pointer; outline: 2px dashed #c8d6f5; outline-offset: -2px; }
.hp-slot.sel { outline: 2px solid var(--primary); outline-offset: -2px; }

.pt-eggrow { display: flex; align-items: center; gap: 10px; padding: 8px 0; }
.egg-ico { font-size: 26px; }
.egg-meta { flex: 1; font-size: 13px; color: var(--muted); }
.btn.sm { padding: 6px 12px; font-size: 13px; }

.pt-legend { display: flex; align-items: center; gap: 12px; }
.pt-legend .pt-lg { width: 64px; height: 64px; image-rendering: pixelated; }
.pt-lg-txt { flex: 1; }
.pt-lg-nm { font-weight: 500; }

/* ---------- 传说之路（打完八道馆开启） ---------- */
.pt-route { display: flex; align-items: center; gap: 10px; padding: 9px 0; }
.pt-route + .pt-route { border-top: 1px solid var(--border); }
.pt-route img { width: 46px; height: 46px; image-rendering: pixelated; }
.pt-route-txt { flex: 1; min-width: 0; }
.pt-route-txt b { font-size: 14px; font-weight: 600; }
.pt-route.cleared .pt-route-txt b { color: var(--good); }
.pt-route.locked img { filter: grayscale(1); opacity: .5; }
.pt-route.locked .pt-route-txt b { color: var(--muted); }
.pt-route.locked .btn { opacity: .5; }

/* ---------- 幻兽兑换台（学习徽章换） ---------- */
.bs-grid {
  display: grid; gap: 8px;
  grid-template-columns: repeat(auto-fill, minmax(70px, 1fr));
}
.bs-cell {
  border: 1px dashed var(--border); border-radius: 10px;
  padding: 7px 2px 5px; text-align: center;
}
.bs-cell img {
  width: 44px; height: 44px; image-rendering: pixelated;
  display: block; margin: 0 auto 2px;
}
.bs-nm { font-size: 11px; line-height: 1.2; margin-bottom: 4px; }
.bs-cell.got { border-style: solid; border-color: #f0d78c; background: #fffbef; }
.bs-cell.ready { border-color: var(--good); }
.bs-tag { font-size: 11px; color: var(--good); }
.bs-cell .btn.sm { font-size: 11px; padding: 2px 10px; }

.pt-badges { display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px; }
.pt-badge {
  border: 1px dashed var(--border); border-radius: 10px;
  padding: 8px 6px; text-align: center;
}
.pt-badge.got { border-style: solid; border-color: #f0d78c; background: #fffbef; }
.bg-nm { font-size: 13px; font-weight: 500; }

/* 箱子：外壳是普通容器，网格在内层（外层还要放搜索条和「展开全部」） */
.pt-box { display: block; }
.bx-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 10px; }
.bx-foot { display: flex; align-items: center; justify-content: space-between;
  gap: 8px; flex-wrap: wrap; margin-top: 10px; }
.bx-foot .hint { margin: 0; }
/* 排序下拉：跟 .search 里的输入框同一套皮肤，宽度收窄，别把搜索框挤没 */
.bx-sort { flex: 0 0 auto; max-width: 42%; padding: 9px 8px;
  border: 1px solid var(--border); border-radius: 10px;
  background: #fff; color: var(--text); }
.pt-mini { text-align: center; cursor: pointer; }
.pt-mini img { width: 46px; height: 46px; image-rendering: pixelated; }

.pt-sheet { display: flex; gap: 12px; align-items: center; margin-bottom: 14px; }
.pt-sheet img { width: 72px; height: 72px; image-rendering: pixelated; }
/* 伙伴弹窗里的立绘 = 图鉴介绍的入口。必须给视觉暗示（光标 + 文案），
   否则用户根本不知道这里能点 —— 语文遮罩那轮踩过同样的坑。 */
.pt-pic-wrap { display: flex; flex-direction: column; align-items: center; gap: 4px; }
.pt-pic-wrap span { font-size: 11px; color: var(--muted); white-space: nowrap; }
.pt-pic { cursor: pointer; }
.pt-pic:active { transform: scale(.94); }

/* ---------- 进化方向选择（分叉形态，如伊布 / 喵喵）---------- */
.ev-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px; }
.ev-cell {
  display: flex; flex-direction: column; align-items: center; gap: 2px;
  padding: 8px 4px; border: 1px solid var(--border); border-radius: var(--radius);
  background: var(--surface); color: var(--text);
}
.ev-cell img { width: 52px; height: 52px; image-rendering: pixelated; }
.ev-cell b { font-size: 12px; font-weight: 500; text-align: center; line-height: 1.3; }
.ev-cell:active { border-color: var(--primary); background: var(--primary-soft); color: var(--primary); }

/* ---------- 冒险入口 ---------- */
.pt-adv-row { display: flex; align-items: center; gap: 10px; padding: 10px 0; }
.pt-adv-row + .pt-adv-row { border-top: 1px solid var(--border); }
.pt-adv-ico { font-size: 22px; width: 30px; text-align: center; }
.pt-adv-txt { flex: 1; min-width: 0; }
.pt-adv-txt b { font-size: 15px; font-weight: 600; }
/* 异空间决斗开门时给一点颜色，不然和普通入口混在一起看不出「今天还能打」 */
.pt-adv-row.on .pt-adv-ico { filter: drop-shadow(0 0 5px rgba(120, 86, 214, .55)); }

/* ---------- 打怪 ---------- */
/* 多阶段战斗：对面整支队伍。打倒的划掉，当前那只高亮 —— 需求是
   「道馆里每个怪兽至少吃一次攻击」，得让他看得见这件事真发生了。 */
.bt-foes {
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface);
  padding: 8px 10px;
  margin-bottom: 10px;
}
.bt-foes-head { font-size: 12px; color: var(--muted); margin-bottom: 6px; }
.bt-foes-head b { color: var(--text); font-size: 13px; }
.bt-foes-row { display: flex; gap: 8px; overflow-x: auto; padding-bottom: 2px; }
.bt-foe { position: relative; flex: 0 0 auto; width: 52px; text-align: center; }
.bt-foe img {
  width: 44px; height: 44px; image-rendering: pixelated;
  display: block; margin: 0 auto; opacity: .45; transition: opacity .2s;
}
.bt-foe.cur img { opacity: 1; filter: drop-shadow(0 2px 5px rgba(31, 35, 41, .28)); }
.bt-foe.down img { opacity: .18; filter: grayscale(1); }
.bt-foe-nm {
  font-size: 10px; color: var(--muted); line-height: 1.2;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.bt-foe.cur .bt-foe-nm { color: var(--text); font-weight: 600; }
.bt-foe.down .bt-foe-nm { text-decoration: line-through; }
.bt-foe-x {
  position: absolute; top: 8px; left: 50%; transform: translateX(-50%);
  font-size: 18px; color: #e5484d; font-style: normal; font-weight: 700;
}
/* 精灵球点阵（2026-10-30）：**只用在剧情舞台**（见 .ss-mon-wrap）。
   需求原话：「敌人的宝可梦数量可以在敌人宝可梦右上方一点用精灵球显示，
   还有的用亮的精灵球，出战的和死亡的用暗的精灵球。玩家这侧在宝可梦左上一点。」
   ★ 亮 = 还没上过场；暗 = 已经出过场（含场上这只）和已经倒下的。
     场上那只已经看得见，再给个亮球是重复信息 —— 这样「亮球数」= 「还得打几只」。
   ★ 普通战斗（打野/道馆/异空间）不用球：那边保留整队卡片，名字和等级都在上面。 */
.bt-balls {
  --s: 11px;
  position: absolute; top: -7px; z-index: 4;
  display: flex; gap: 3px; line-height: 0;
}
.bt-balls i {
  width: var(--s); height: var(--s); border-radius: 50%; font-style: normal;
  background:
    radial-gradient(circle at 50% 50%,
      #fbfdff 0 12%, #2c333b 12% 26%, rgba(0, 0, 0, 0) 26%),
    linear-gradient(180deg, #ef5350 0 44%, #2c333b 44% 57%, #f7fafc 57% 100%);
  box-shadow: 0 1px 2px rgba(31, 35, 41, .3);
}
.bt-balls i.off { filter: grayscale(1) brightness(.78); opacity: .5; box-shadow: none; }
/* 出战伙伴后面的暴击率：等级的用处，得摆在战斗里才看得见 */
.bt-crit {
  font-style: normal; font-size: 10px; font-weight: 500;
  color: #b26b00; background: #fff4d6; border-radius: 8px;
  padding: 0 5px; margin-left: 3px;
}
.bt-down { color: var(--muted); font-size: 11px; }
/* 我方出战队列（2026-10-26：最多 2 只依次上场）。绿色边框和「对面」区分开 */
.bt-foes.bt-ours { border-color: rgba(34, 181, 115, .45); background: rgba(34, 181, 115, .06); }
.bt-foes.bt-ours .bt-foes-head b { color: #178a58; }
.bt-foe-lv { font-size: 9px; color: var(--muted); line-height: 1.2; white-space: nowrap; }
.bt-foe.cur .bt-foe-lv { color: #178a58; }

.bt-arena {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 8px;
  padding: 18px 14px 14px;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: linear-gradient(180deg, #eef4ff, #fbfdff);
  margin-bottom: 14px;
}
.bt-side { flex: 1; text-align: center; position: relative; min-width: 0; }
.bt-side img { width: 84px; height: 84px; image-rendering: pixelated; display: block; margin: 0 auto; }
.bt-side .bt-nm {
  font-size: 13px; font-weight: 500; margin-top: 4px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.bt-side .bt-nm span { color: var(--muted); font-weight: 400; }
.bt-vs { flex: 0 0 auto; font-weight: 700; color: #aeb8c4; padding-bottom: 30px; }

.bt-hp { height: 8px; border-radius: 999px; background: #e4e9f0; overflow: hidden; margin: 7px 6px 0; }
.bt-hp i { display: block; height: 100%; border-radius: 999px; transition: width .35s ease; }
.bt-hp.enemy i { background: linear-gradient(90deg, #ff9d94, #e5484d); }
.bt-hp.own i { background: linear-gradient(90deg, #8fe0a8, #22b573); }

.bt-dmg {
  position: absolute; top: -4px; left: 50%;
  font-size: 20px; font-weight: 800; color: #e5484d;
  text-shadow: 0 1px 0 #fff, 0 0 8px #fff;
  animation: btFloat .95s ease-out forwards;
  pointer-events: none;
}
@keyframes btFloat {
  0%   { opacity: 0; transform: translate(-50%, 8px) scale(.6); }
  30%  { opacity: 1; transform: translate(-50%, -10px) scale(1.2); }
  100% { opacity: 0; transform: translate(-50%, -36px) scale(1); }
}
@keyframes btShake {
  0%, 100% { transform: translateX(0); }
  15% { transform: translateX(-6px); } 30% { transform: translateX(6px); }
  45% { transform: translateX(-5px); } 60% { transform: translateX(4px); }
  75% { transform: translateX(-2px); }
}
@keyframes btLungeL {
  0% { transform: translateX(0) scale(1); }
  40% { transform: translateX(-16px) scale(1.08); }
  100% { transform: translateX(0) scale(1); }
}
@keyframes btLungeR {
  0% { transform: translateX(0) scale(1); }
  40% { transform: translateX(16px) scale(1.08); }
  100% { transform: translateX(0) scale(1); }
}
.bt-side.hurt img { animation: btShake .45s ease; filter: drop-shadow(0 0 6px #e5484d) brightness(1.35); }
.bt-side.hero.atk img { animation: btLungeL .5s ease; }
.bt-side.wild.atk img { animation: btLungeR .5s ease; }
.bt-side.hurt.crit img { animation: btShake .55s ease; filter: drop-shadow(0 0 10px #e5484d) brightness(1.6) saturate(1.6); }
.bt-side.hurt.crit .bt-dmg { font-size: 26px; }
.bt-side.hurt.crit .bt-dmg::before { content: "暴击 "; font-size: 14px; }

.bt-round { text-align: center; font-size: 13px; color: var(--muted); margin-bottom: 10px; }
.bt-q { text-align: center; padding: 22px 14px; }
.bt-word {
  font-size: 30px; font-weight: 700; color: var(--text);
  letter-spacing: .4px; margin-bottom: 18px; word-break: break-word;
}
.bt-opts { display: grid; gap: 9px; }
.bt-opt {
  padding: 12px 14px; border: 1.5px solid var(--border); border-radius: 10px;
  background: var(--surface); color: var(--text); font-size: 15px;
  text-align: left; transition: .15s;
}
.bt-opt:active { transform: scale(.985); }
.bt-opt.right { border-color: var(--good); background: #eefaf3; color: #1d8a56; }
.bt-opt.wrong { border-color: var(--again); background: #fdeeee; color: #c1383d; }
.bt-opt:disabled { cursor: default; }

.bt-result { text-align: center; padding: 24px 16px; }
.bt-result.win { background: linear-gradient(180deg, #f2fbf6, var(--surface)); }
.bt-result.lose { background: linear-gradient(180deg, #f4f5f7, var(--surface)); }
.bt-big { font-size: 22px; font-weight: 800; margin-bottom: 6px; }
.bt-rw { margin: 12px 0; font-size: 15px; font-weight: 600; color: var(--good); line-height: 1.8; }
.bt-up { margin-top: 4px; font-size: 14px; font-weight: 700; color: #e8590c; }

/* ---------- 野餐动画 ---------- */
.picnic {
  position: fixed; inset: 0; z-index: 80;
  background: rgba(255, 255, 255, .95);
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 12px;
}
.pc-food { font-size: 30px; letter-spacing: 10px; animation: pcFood 1.2s ease-in-out infinite; }
.pc-party { display: flex; gap: 6px; flex-wrap: wrap; justify-content: center; max-width: 320px; }
.pc-party img { width: 56px; height: 56px; image-rendering: pixelated; animation: pcBounce .9s ease-in-out infinite; }
.pc-party img:nth-child(2n) { animation-delay: .15s; }
.pc-party img:nth-child(3n) { animation-delay: .3s; }
.pc-txt { font-size: 16px; font-weight: 700; color: var(--good); }
.pc-up { font-size: 14px; font-weight: 700; color: #e8590c; }
@keyframes pcBounce { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-10px); } }
@keyframes pcFood { 0%, 100% { transform: translateY(0) rotate(-3deg); } 50% { transform: translateY(-8px) rotate(3deg); } }

/* ---------- 道馆 ---------- */
.pt-gym { display: flex; align-items: center; gap: 10px; padding: 9px 0; }
.pt-gym + .pt-gym { border-top: 1px solid var(--border); }
.pt-gym img { width: 46px; height: 46px; image-rendering: pixelated; }
.pt-gym-txt { flex: 1; min-width: 0; }
.pt-gym-txt b { font-size: 14px; font-weight: 600; }
.pt-gym.cleared .pt-gym-txt b { color: var(--good); }
.gym-type {
  display: inline-block; font-style: normal; font-size: 10px; font-weight: 600;
  padding: 1px 6px; border-radius: 999px; margin-left: 5px; vertical-align: 1px;
}
.t-rock { background: #e9ecef; color: #495057; }
.t-water { background: #e7f5ff; color: #1971c2; }
.t-electric { background: #fff9db; color: #e67700; }
.t-grass { background: #ebfbee; color: #2b8a3e; }
.t-poison { background: #f3e8ff; color: #7048e8; }
.t-psychic { background: #fff0f6; color: #c2255c; }
.t-fire { background: #fff4e6; color: #e8590c; }
.t-ground { background: #f8f0e3; color: #a06820; }
.bt-badge { margin-top: 8px; font-size: 15px; font-weight: 700; color: #e8590c; }

/* ---------- 图鉴 ---------- */
.dex-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 8px; }
.dex-cell {
  position: relative;                /* 编号角标要定位 */
  background: var(--surface); border: 1px solid var(--border);
  border-radius: 10px; padding: 8px 4px; text-align: center;
}
.dex-no {
  position: absolute; top: 3px; left: 4px;
  font-size: 9px; color: var(--muted); opacity: .75; letter-spacing: 0;
}
.dex-cell img { width: 44px; height: 44px; image-rendering: pixelated; display: block; margin: 0 auto; }
.dex-cell.off { opacity: .4; }
.dex-cell.off img { filter: grayscale(1); }
.dex-cell.hide { display: none; }   /* 图鉴搜索：不匹配的格子藏起来（用 DOM 过滤，不重绘） */
.dex-nm { font-size: 12px; margin-top: 2px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.dex-rar { display: inline-block; font-size: 10px; padding: 1px 6px; border-radius: 999px; margin-top: 3px; }
.r-c { background: #eef2f7; color: #5b6b7c; }
.r-uc { background: #e6fcf5; color: #0ca678; }
.r-u { background: #e7f5ff; color: #1971c2; }
.r-r { background: #f3e8ff; color: #7048e8; }
.r-sr { background: #fff4e6; color: #e8590c; }
.r-lg { background: #fff0f6; color: #c2255c; }
.dex-lv { font-size: 10px; color: var(--muted); }
.dex-lv.miss { color: #adb5bd; }
/* 已收集的格子可点开详情（未收集的不可点 —— 图鉴介绍只给已收集的看） */
.dex-cell.tap { cursor: pointer; }
.dex-cell.tap:active { transform: scale(.97); }

/* ---- 图鉴详情弹窗（点开一只：高清立绘 + 中英介绍 + 进化链） ---- */
.ds-wrap { display: flex; flex-direction: column; gap: 12px; }
.ds-top { display: flex; gap: 12px; align-items: center; }
.ds-pic {
  width: 96px; height: 96px; flex: none; object-fit: contain;
  background: var(--bg); border-radius: 12px;
}
.ds-info { min-width: 0; }
.ds-no { font-size: 12px; color: var(--muted); letter-spacing: 1px; }
.ds-nm { font-size: 17px; font-weight: 600; }
.ds-nm .ds-en-nm { font-size: 13px; color: var(--muted); font-weight: 400; margin-left: 6px; }
.ds-meta { font-size: 12px; color: var(--muted); margin-top: 2px; }
.ds-sec { border-top: 1px solid var(--border); padding-top: 10px; }
.ds-cap {
  font-size: 12px; color: var(--muted); margin-bottom: 5px;
  display: flex; justify-content: space-between; align-items: baseline;
}
.ds-cap .ds-tip { font-size: 11px; color: var(--primary); }
.ds-cn { font-size: 14px; line-height: 1.75; }
.ds-cn.dim { color: var(--muted); font-size: 13px; }
.ds-en { font-size: 14px; line-height: 1.9; }
/* 英文描述里可点的生词：点一下加进生词本 */
.lore-w {
  border-bottom: 1px dashed var(--border); cursor: pointer;
  padding: 0 1px; border-radius: 3px;
}
.lore-w.on {
  background: var(--primary-soft); color: var(--primary);
  border-bottom-color: var(--primary);
}
.ds-evo { font-size: 13px; color: var(--muted); }
.ds-evo b { color: var(--text); }
/* 时空入口：还没见过的伙伴画成问号（有几只看得见，是谁看不见） */
.dex-cell.q { border-style: dashed; background: transparent; }
.dex-qm {
  width: 44px; height: 44px; margin: 0 auto; border-radius: 10px;
  display: flex; align-items: center; justify-content: center;
  font-size: 26px; font-weight: 700; color: var(--muted);
  background: var(--bg); border: 1px dashed var(--border);
}
.dex-cell.q .dex-nm { color: var(--muted); letter-spacing: 2px; }
.dex-tabs { display: flex; gap: 6px; overflow-x: auto; padding-bottom: 2px; margin-bottom: 10px; }
.dex-tabs button {
  flex: 0 0 auto; border: 1px solid var(--border); background: var(--surface);
  color: var(--text); font-size: 12px; padding: 5px 10px; border-radius: 999px;
  cursor: pointer; white-space: nowrap;
}
.dex-tabs button i { font-style: normal; color: var(--muted); margin-left: 3px; }
.dex-tabs button.active { background: var(--primary); border-color: var(--primary); color: #fff; }
.dex-tabs button.active i { color: rgba(255,255,255,.75); }
.dex-tabs button:disabled { opacity: .45; cursor: default; }

/* ---------- 道馆锁定 ---------- */
.pt-gym.locked img { filter: grayscale(1); opacity: .5; }
.pt-gym.locked .pt-gym-txt b { color: var(--muted); }
.pt-gym.locked .btn { opacity: .5; }

/* 朱紫剧情模式：冠军之路卡片（复用 .pt-gym 布局，intro 显示剧情文案） */
.story-intro {
  margin-top: 5px;
  padding-left: 8px;
  border-left: 3px solid var(--primary);
  color: var(--text);
  font-size: 12px;
  line-height: 1.55;
  opacity: .92;
}
.pt-story img { border-radius: 8px; }

/* 朱紫剧情模式：冠军之路地图
   ★ 2026-10-30 换成**竖版 4:5**（1024×1280）。原来是 16:10 横图，容器宽 358px 时
     高度被锁死在 224px，屏幕下面还空着 200 多像素 —— 用户原话「地图是不是有点小」。
     竖版后同样宽度下高 448px，正好吃掉那块空白，节点也终于分得开。
   ★ 换比例**必须同时重标 9 个节点坐标**（pet.py 里的 x/y 是百分比）。旧坐标是按
     16:10 的横椭圆标的，直接套到竖版上会有一半点落进海里。 */
.story-map {
  position: relative;
  width: 100%;
  aspect-ratio: 4 / 5;
  border-radius: 12px;
  background-color: #2a3b52;
  overflow: hidden;
  border: 1px solid var(--border);
}
/* 地图画布（2026-10-31 从 `.story-map` 拆出来，为了「横版放大档」）：
   `.story-map` 只当**可视窗**（overflow:hidden），真正的底图 + 节点 + 小人都在这一层，
   它按 `--mz` 加宽、左右居中 ⇒ 放大时只裁左右，纵向永远铺满。
   ★ `background-size:100% 100%` 必须留在画布上（不能再放回窗口）：
     cover 在亚像素取整时会以侧边为准裁掉 0.3px，把左右海岸各切一条。
   ★ 画布宽高比恒等于底图比例（窗口高 = 画布宽 / 图比例），所以底图不会被压扁；
     mz=1 时画布正好等于窗口，和旧结构完全等价。 */
.map-canvas {
  position: absolute;
  top: 0;
  left: 50%;
  transform: translateX(-50%);
  width: 100%;
  height: 100%;
  background-size: 100% 100%;
  background-position: center;
  background-repeat: no-repeat;
}

/* 剧情地图「一屏就是地图」（2026-10-31 用户定；当晚按手机截图回调一次）：
   第一版把地图垂直居中、把上下说明挤到屏幕外，追求「首屏除了标题条就只有地图」。
   用户实测反馈：「上下还有很多空位，上面的描述也加回来，下面的能显示多少显示多少」
   —— 横版 1.30 的图只有 300px 高，居中之后上下各留 100~200px 纯空白，比文字还空。
   ⇒ 现在只保留「左右出血」这一条：地图顶到屏幕两边、整图可见，
     高度交回自然流（不再 min-height / 不再垂直居中），上下留给介绍与说明。
   ⚠️ #app 有 16px 内边距，地图要顶到屏幕边就得用负边距补回来。
   ⚠️ 这里**不能再加 overflow-x:hidden**：地图自己要出血，剪掉就成了 390px 内的窄条。 */
.map-screen {
  position: relative;
  overflow: hidden;
  margin: 0 -16px;
}
/* ⚠️ 试过用「同一张底图的模糊放大版」垫满上下留白，**看起来像三块拼在一起**的
   地图（模糊 16px 还不够糊，接缝是硬边）。已删除，不要再来一次：留白就用页面
   自己的渐变底，干净；首屏下方露出的那半行说明文字正好是"还能往下滚"的提示。 */
.map-screen > .story-map {
  position: relative;     /* 压到模糊层上面 */
  z-index: 1;
  width: 100%;
  /* 出血到屏幕边就不该再有圆角和左右描边（会露出两条竖线） */
  border-radius: 0;
  border-left: 0;
  border-right: 0;
}
/* 「下一站」卡片（2026-10-31 晚）：横版地图放大 1.2 之后，阿罗拉下面还空 170px。
   再放大就到顶了（1.4 起站点锚点出界），这 170px 用来回答「下一步打哪、对面是谁」。
   ★ 放在说明段（tail）**之后**，不挤走说明文字；首屏从 ~673 填到 ~795。
   ★ 立绘 `object-fit:contain`，不要 cover —— 立绘左右是透明区，cover 会切手臂；
     也不要圆形裁切，会把帽檐和发型切掉（图鉴那边同一条教训）。 */
.map-next {
  margin: 14px 0 6px;
  padding: 11px 12px 10px;
  border: 1px solid var(--border);
  border-radius: 12px;
  background: var(--surface);
}
.map-next .mn-head {
  display: flex; justify-content: space-between; align-items: baseline;
  font-size: 12px; color: var(--muted); margin-bottom: 8px;
}
.map-next .mn-head b { color: var(--text); font-size: 13px; font-weight: 700; letter-spacing: .5px; }
.map-next .mn-main { display: flex; align-items: center; gap: 10px; }
.map-next .mn-pic {
  flex: 0 0 48px; width: 48px; height: 48px;
  object-fit: contain; object-position: bottom center;
  border-radius: 8px; background: var(--bg);
}
.map-next .mn-txt { flex: 1 1 auto; min-width: 0; }
.map-next .mn-txt b { display: block; font-size: 15px; line-height: 1.25; }
.map-next .mn-txt span {
  display: block; font-size: 11.5px; color: var(--muted);
  line-height: 1.35; margin-top: 2px;
}
.map-next .mn-go {
  flex: 0 0 auto; border: 0; cursor: pointer; font-family: inherit;
  background: var(--primary); color: #fff;
  font-size: 13px; font-weight: 600;
  padding: 9px 14px; border-radius: 999px;
  box-shadow: 0 2px 8px rgba(0, 0, 0, .18);
}
.map-next .mn-go:active { transform: scale(.97); }
.map-next .mn-go[disabled] { background: var(--border); color: var(--muted); cursor: default; box-shadow: none; }
.map-next .mn-bar {
  margin-top: 9px; height: 5px; border-radius: 3px;
  background: var(--border); overflow: hidden;
}
.map-next .mn-bar i {
  display: block; height: 100%; border-radius: 3px;
  background: var(--good, #39c06a);
  transition: width .35s ease;
}
/* 剧情模式 · 世代画廊（2026-10-30）：9 个地区，3×3。
   ★ 封面用 4:5，和新地图同比例 —— 缩略图和点进去看到的是同一张脸。
   ★ 空壳世代**不灰到看不见**：虚线框 + 半透明 + 「敬请期待」，
     孩子得能数出"还有 8 个地区没开"，这比只显示 1 个地区有盼头。 */
.story-gen-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 8px;
}
.story-cell {
  padding: 0 0 8px;
  border: 1px solid var(--border);
  border-radius: 10px;
  background: var(--surface);
  text-align: center;
  overflow: hidden;
  cursor: pointer;
}
.story-cell .sg-cover {
  display: block;
  width: 100%;
  aspect-ratio: 4 / 5;
  background-size: cover;
  background-position: center;
  background-color: #2a3b52;
}
.story-cell .sg-empty {
  position: relative;
  display: block;
  background: repeating-linear-gradient(135deg, #eef1f4 0 6px, #e4e8ec 6px 12px);
}
/* 空壳封面里的「?」用绝对定位而不是 flex 居中：
   flex 容器会把 aspect-ratio 算出来的高度吃掉（第一版实测格子矮成一横条）。
   字符用 ASCII 问号，不依赖 emoji 字体 —— headless 和部分安卓 WebView 里
   🗺 会被裁成半个方块。 */
.story-cell .sg-empty i {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-style: normal;
  font-size: 26px;
  font-weight: 700;
  color: #c2ccd6;
}
.story-cell b { display: block; font-size: 12px; margin-top: 6px; }
.story-cell .sg-sub { display: block; font-size: 10.5px; color: var(--muted); margin-top: 1px; }
.story-cell .sg-done { color: var(--good); font-weight: 600; }
.story-cell .sg-soon { color: var(--warn, #b4780f); }
.story-cell.done { border-color: var(--good); background: #f2fbf7; }
.story-cell.soon { border-style: dashed; opacity: .62; }
.story-lines {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
}
.route-seg {
  fill: none;
  stroke: rgba(255, 255, 255, .35);
  stroke-width: .5;
  stroke-dasharray: 1.4 1.4;
  stroke-linecap: round;
}
.route-seg.lit {
  stroke: var(--good, #39c06a);
  stroke-dasharray: none;
  stroke-width: .7;
}
.map-node {
  position: absolute;
  transform: translate(-50%, -50%);
  display: flex;
  flex-direction: row;
  align-items: center;
  gap: 3px;
  background: rgba(255, 255, 255, .92);
  border: 2px solid var(--primary);
  border-radius: 10px;
  padding: 2px 6px;
  min-width: 40px;
  cursor: pointer;
  box-shadow: 0 2px 6px rgba(0, 0, 0, .25);
  font-size: 11px;
  line-height: 1.2;
  color: var(--text);
}
.map-node .mn-dot { display: none; }
.map-node .mn-name { font-weight: 600; white-space: nowrap; }
.map-node .mn-flag { font-size: 11px; line-height: 1; }
.map-node.cleared { border-color: var(--good, #39c06a); }
.map-node.cleared .mn-flag { color: var(--good, #39c06a); }
.map-node.locked {
  background: rgba(180, 180, 180, .85);
  border-color: #999;
  cursor: not-allowed;
}
.map-node:not(.locked):hover { transform: translate(-50%, -50%) scale(1.06); }
.map-node[disabled] { opacity: .85; }
/* 贴边站（2026-10-31）. 横版地图放大 1.2 倍后画布比可视窗宽，最外侧两站居中放会
   被屏幕边缘切掉半个标签（城都「白银山」丢了个「白」）。改成锚点对齐：
   `.la` = 锚点是标签**左缘**，往右展开；`.ra` = 锚点是**右缘**，往左展开。
   ★ 三个 transform 都要写全（含 hover），少写一个 hover 会把对齐弹回居中。 */
.map-node.la { transform: translate(0, -50%); }
.map-node.ra { transform: translate(-100%, -50%); }
.map-node.la:not(.locked):hover { transform: translate(0, -50%) scale(1.06); }
.map-node.ra:not(.locked):hover { transform: translate(-100%, -50%) scale(1.06); }

/* 三条主线 tab（2026-10-30）：冠军之路 / 星尘之路 / 传说之路。
   原作是三条线并行，全通才开第零区，所以放在同一页顶部当分段控件。 */
.track-tabs {
  display: flex; gap: 6px;
  margin: 0 0 10px;
  background: var(--surface, #fff);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 3px;
}
.track-tab {
  flex: 1;
  display: flex; flex-direction: column; align-items: center; gap: 1px;
  padding: 6px 2px;
  border: 0; border-radius: 8px;
  background: transparent;
  font-size: 12.5px; font-weight: 600; color: var(--muted);
  cursor: pointer;
  line-height: 1.15;
}
.track-tab i {
  font-style: normal; font-size: 10px; font-weight: 400; opacity: .8;
}
.track-tab.on {
  background: var(--primary);
  color: #fff;
}
.track-tab.on i { opacity: .9; }

/* 地图上的小人（2026-10-30）：点哪站走到哪站。
   ★ 走路靠 left/top 的 transition，**不能**用 transform 做位移 —— 节点按钮的
     translate(-50%,-50%) 和它是两套坐标系，混用会让小人偏出半格。
   ★ 走路时只叠一个上下颠的 animation，transform 那层保持在 keyframes 里写全。 */
.map-me {
  position: absolute;
  height: 26px; width: auto;
  transform: translate(-50%, -88%);
  transition: left .78s ease-in-out, top .78s ease-in-out;
  pointer-events: none;
  z-index: 5;
  filter: drop-shadow(0 2px 3px rgba(0, 0, 0, .45));
}
.map-me.walking { animation: meBob .3s linear infinite alternate; }
@keyframes meBob {
  from { transform: translate(-50%, -88%) translateY(0); }
  to   { transform: translate(-50%, -88%) translateY(-4px); }
}
/* 打到一半的站：名字后面一个小圆点（断点存档的可见标记） */
.map-node .mn-half { font-size: 8px; line-height: 1; color: var(--warn, #b4780f); }


/* 剧情对话气泡（每波开打前展示） */
.story-dialog {
  margin: 0 0 12px;
  background: linear-gradient(135deg, #fdf6e3, #f3ead0);
  border: 1px solid #e3d4a8;
  border-radius: 12px;
  padding: 12px 14px;
}
.story-dialog .sd-en { font-size: 15px; font-weight: 600; color: #5a4a1f; font-style: italic; }
.story-dialog .sd-cn { font-size: 13px; color: #6b5a2a; margin-top: 3px; }
.story-dialog .sd-intro { font-size: 12.5px; color: #7a6a3a; margin-top: 6px; line-height: 1.5; }

/* ---------------- 剧情场景层（P2 两层 + 推轨） ----------------
   ★★ 舞台比例 5:8 必须等于地面素材（1280×2048）。改了比例，horizon 与
      project() 的每一个数都会歪 —— 这不是"美化参数"，是坐标系。
   宽度取 min(容器宽, 60vh×0.625)：390×844 上舞台 316×506 居中，两侧留暗边；
   窄屏（360×640）自动缩到 240×384，保证整套（舞台+题目）不用滚动。
   ★ 地面用 100% 100% 不用 cover：同比例下等价，但 cover 会因亚像素取整
     各切掉一条边（地基/台阶被削），而这里地平线位置是硬指标。 */
.story-stage {
  position: relative;
  width: 100%;
  max-width: 100%;
  /* ★ 2026-10-30「压低角度」：可见窗口改成方形，世界层（5:8）底对齐、只露下半截。
     以前整块 5:8 竖着摆，光天空和远景就吃掉屏幕三分之一，人和宝可梦被挤在下面一小条。 */
  aspect-ratio: 1 / 1;
  margin: 0 auto 8px;
  border-radius: 14px;
  overflow: hidden;
  background: #141d28;
  isolation: isolate;
  box-shadow: 0 4px 16px rgba(0, 0, 0, .28);
}
/* 世界层 = 真正的那张 5:8 坐标系（等于地面素材 1280×2048 的比例）。
   ★ 所有 `project()` / `horizon` 的百分比都相对这一层 —— 窗口再变，坐标系不动。
   ★ 底对齐：被裁掉的是上面那片天空，不是脚下这块地。 */
.ss-world {
  position: absolute; left: 0; bottom: 0;
  width: 100%;
  aspect-ratio: 5 / 8;
}

/* ---------- 剧情战斗「一屏装下」（2026-10-30） ----------
   用户原话：「打仗的时候至少要能保证战斗的 2 个宝可梦和宝可梦的血，
   加完整的题和选项能在一屏装下」。
   ★ 舞台高度不再写死 60vh：`#app.bt-fit` 把整页做成 flex 列，舞台 flex:1
     吃掉剩下的高度，题目和 4 个选项按内容高度排在下面。这样不管手机多高，
     题目永远不会被挤到屏幕外；舞台是有多大用多大。
   ★ 这个类只在**剧情战斗有场景层**的时候加（见 render()），别的视图一律不加。 */
#app.bt-fit {
  display: flex;
  flex-direction: column;
  height: 100vh;
  height: 100dvh;
  padding: 10px 14px 56px;      /* 底部只给 tabbar 留位，不再留通用的 88 */
  /* 正常情况下内容正好等于视口、不滚动；极端矮屏（横屏）时允许滚一点点，
     绝不裁掉选项 —— 裁掉比滚一下更糟。 */
  overflow-x: hidden;
  overflow-y: auto;
}
#app.bt-fit > .topbar { flex: 0 0 auto; margin-bottom: 6px; }
#app.bt-fit > .bt-stage-hold {
  flex: 1 1 auto;
  min-height: 0;
  display: flex;
  justify-content: center;
  align-items: center;
}
/* 舞台：1:1 时高度就该≈宽度。`min(100%, 100vw-28px)` 保证它不会在
   高屏 / 桌面浏览器里被拉成竖长条（那时 100% 会远大于宽度，world 露得太多、构图就散了）。 */
#app.bt-fit .story-stage {
  height: min(100%, calc(100vw - 28px));
  width: auto;
  max-width: 100%;
  max-height: 100%;
  margin: 0;
  flex: 0 0 auto;
}
#app.bt-fit > .bt-round { flex: 0 0 auto; margin: 4px 0 6px; }
#app.bt-fit > .panel.bt-q { flex: 0 0 auto; padding: 14px 12px; }
#app.bt-fit .bt-word { font-size: 26px; margin-bottom: 12px; }
#app.bt-fit .bt-opts { gap: 7px; }
#app.bt-fit .bt-opt { padding: 10px 12px; }
#app.bt-fit > .hint { display: none; }
/* 旁白（sd-intro）在战斗舞台里最占地方，而且答错时会冒出「全部意思」面板把舞台压小，
   气泡就盖住宝可梦了 —— 战斗时只留台词，旁白让位给「两只宝可梦必须看得见」。 */
#app.bt-fit .story-dialog.ss-dlg .sd-intro { display: none; }
.ss-sky,
.ss-ground {
  position: absolute; left: 0; width: 100%;
  background-size: 100% 100%; background-repeat: no-repeat;
}
/* 天空层 = 地面图顶部 34% 那块，永远不动。推轨时只有地面在动，才有"走过去"感；
   天空要是跟着放大，就会变成"道馆在长大"。 */
.ss-sky { top: 0; height: 34%; z-index: 1; }
/* 地面层：原点在地平线（不是地基线）——地平线是不动点，地基下沉并变大。 */
.ss-ground {
  top: 0; height: 100%; z-index: 2;
  transform-origin: 50% calc(var(--hz, 0.3) * 100%);
  transform: scale(var(--k, 1));
  will-change: transform;
}
/* 人物：锚点是**脚底中心**（立绘 512×512 方画布、脚底零留白） */
.ss-act {
  position: absolute; z-index: 3;
  transform: translate(-50%, -100%);
  pointer-events: none;
}
.ss-player { z-index: 4; }          /* 玩家在前景，挡住一点馆主是正常的 */
/* 终章五人同框：当前对手满亮、其余压暗。五个 Q 版人并排，不点亮根本分不清在跟谁打 */
.ss-lineup { opacity: .68; filter: saturate(.82) brightness(.95); transition: opacity .18s; }
.ss-lineup.active { opacity: 1; filter: none; }
/* 脚下的椭圆影子：没有它，人看着像浮在地面上 —— "脚踩地"的观感一半来自它 */
.ss-shadow {
  position: absolute; z-index: 2;
  transform: translate(-50%, -50%);
  border-radius: 50%;
  background: radial-gradient(ellipse at center, rgba(0, 0, 0, .34), rgba(0, 0, 0, 0) 72%);
  pointer-events: none;
}
/* 血条本体（名字和血条现在挂在各自的宝可梦下方，见 .ss-mon-info；
   2026-10-30 之前那套「舞台顶沿两条 HUD」已经取消，别再加回来） */
.ss-hp {
  height: 7px; border-radius: 4px;
  background: rgba(0, 0, 0, .42); overflow: hidden;
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, .3);
}
.ss-hp i { display: block; height: 100%; transition: width .3s ease; }
.ss-hp.foe i { background: linear-gradient(90deg, #ff9a6c, #e8503a); }
.ss-hp.own i { background: linear-gradient(90deg, #6ee27a, #35b34a); }

/* 前排两只宝可梦（2026-10-30）。锚点同样是**脚底中心**，和立绘一套规矩。
   ★ 它们不参与推轨（proj 时 k=1），所以这里可以放心用固定 transform。
   ★ 2026-10-30 晚：外面多包一层 `.ss-mon-wrap` —— 精灵球（队伍还剩几只）要贴在
     宝可梦的角上，img 自己没法挂子元素。定位与动画都搬到 wrap 上，
     img 只管「撑满 wrap、保持方形」。 */
.ss-mon-wrap {
  position: absolute; z-index: 5;
  transform: translate(-50%, -100%);
  pointer-events: none;
}
.ss-mon-wrap .ss-mon {
  display: block; height: 100%; width: auto;
  filter: drop-shadow(0 3px 5px rgba(0, 0, 0, .35));
}
/* 受击/出招的 keyframes 里写的就是 translate(-50%,-100%) —— 那正是 wrap 自己的锚点，
   所以动画必须挂在 wrap 上；挂到 img 上会和 wrap 的定位叠加，一抖就飞出去。 */
.ss-mon-wrap.hurt { animation: ssShake .45s ease; }
.ss-mon-wrap.hurt .ss-mon { filter: drop-shadow(0 0 7px #e5484d) brightness(1.4); }
.ss-mon-wrap.atk { animation: ssLunge .42s ease; }
/* 舞台里的球要小一号：宝可梦本体才 100px 高，11px 的球会显得比脑袋还大。
   ★ 位置用百分比往里收，不能用 -4px 硬顶在 wrap 角上 —— 精灵图是方形画布、
     图形只占中间六七成，贴角会让球飘在本体外面一大截，看着跟它没关系。
   ★ 2026-10-30 需求第 3 条：敌方球「再往右一点」（右上角顶到图形外沿）；
     我方球从左上改到**左下**（脚下方居中已经给名字血条，球让到左下角）。 */
.ss-mon-wrap .bt-balls { --s: 9px; }
/* 球往外飘：wrap 是正方形画布（透明区域很大），`-16%` 才等于"离本体一小段距离"，
   写 `1%` 会贴在透明边上、看着像长在身上。用户两次要求"各自再往外"，一直推到 **-28%**。 */
/* 球往里到外：**第 1 只贴着身体，后面的往外排**。
   敌方球挂在右上方外侧 ⇒ 第 1 只应该在左端（靠内），顺排即可；
   我方球挂在左下方外侧 ⇒ 第 1 只应该在右端（靠内），要 row-reverse。
   （之前反过来写了，导致两侧都是「第 1 只离本体最远」，打死一只时暗的是最远端那颗。） */
.ss-mon-wrap.foe .bt-balls { top: -1%; right: -28%; }
.ss-mon-wrap.own .bt-balls { top: auto; bottom: 3%; left: -28%; flex-direction: row-reverse; }

/* ---------- 极巨化（伽勒尔，2026-11-01） ----------
   ★ 三件套：地面红光（.ss-gmax-haze）+ 立绘放大与呼吸（.ss-mon-wrap.gmax）+ 右上角标。
     全部是**循环动画**，不是一次性入场：这一页每答一题就整块重建 DOM，
     一次性动画（震屏那种）会每题重播一次，晃得人没法看题。
   ★ 红光只铺下半部、z-index 4：低于宝可梦（5）、高于人物（3）——
     「光从地面升起来把人脚染红，但宝可梦本体还是清楚的」。
   ★ 立绘放大本身不在 CSS 里做，是 JS 换了槽位（STAGE_MON_FOE_GMAX，h 0.15→0.36）；
     CSS 只负责光晕和呼吸。两边都放大就会叠加成 4 倍，直接顶出画面。 */
.ss-gmax-haze {
  position: absolute; left: -8%; right: -8%; bottom: -4%; height: 66%;
  z-index: 4; pointer-events: none;
  background:
    radial-gradient(58% 52% at 66% 84%, rgba(255, 92, 34, .42), rgba(255, 92, 34, 0) 68%),
    radial-gradient(90% 60% at 50% 100%, rgba(126, 8, 26, .34), rgba(126, 8, 26, 0) 72%);
  animation: ssGmaxBreath 3.4s ease-in-out infinite;
}
@keyframes ssGmaxBreath {
  0%, 100% { opacity: .72; }
  50% { opacity: 1; }
}
/* 变形原点钉在脚底，否则 scale 会以图片中心为圆心，脚一涨就离地飘起来 */
.ss-mon-wrap.gmax .ss-mon {
  transform-origin: 50% 100%;
  filter: drop-shadow(0 0 16px rgba(255, 96, 32, .9))
          drop-shadow(0 6px 12px rgba(0, 0, 0, .45));
  animation: ssGmaxIdle 2.8s ease-in-out infinite;
}
@keyframes ssGmaxIdle {
  0%, 100% { transform: scale(1); }
  50% { transform: scale(1.035); }
}
.ss-gmax-tag {
  position: absolute; right: 10px; top: 10px; z-index: 9;
  pointer-events: none;
  font-size: 11px; letter-spacing: .08em;
  padding: 2px 9px; border-radius: 999px;
  color: #ffd9c9; background: rgba(140, 20, 20, .72);
  border: .5px solid rgba(255, 120, 80, .55);
}

/* ---------- 太晶化（帕底亚，2026-11-01） ----------
   ★ 和极巨化**故意的区别**：不换槽位、不放大。极巨化卖「大」，太晶化卖「亮」——
     两代都放大就变成「同一个特效换了个颜色」，孩子也分不出两代机制。
   ★ 三件套全挂在 `.ss-mon-wrap` 里（不是挂在舞台上）：这样受击抖、出招冲这两下
     会和立绘一起动；挂舞台上的话人一抖、水晶留在原地，像贴纸。
   ★ 颜色只走**一个变量** `--tc`（太晶属性色，由 app.js 按 `B.wild.tera` 注入，
     写在 wrap 上让三个子元素一起继承）。改配色只改那一张表。
   ★ 全是循环动画：这一页每答一题就整块重建 DOM，一次性闪光会每题重播一次。
   ★ 棱光 / 晶环用负 z-index 沉到立绘**后面**：wrap 自己 `z-index:5` 建了层叠上下文，
     负值只会退到本层里，不会掉到地面下面去（这一点和极巨化红光不同，那是铺舞台的）。 */

/* ① 棱光：身后一圈放射状光，慢转 + 呼吸
   ★ 盒子必须**比立绘大一大圈**（左右各出去 60%）。第一版只出 22%，结果整团光被
     立绘本体盖住 —— 它挂在 z-index:-2（立绘后面），露在外面的只有边缘那一圈，
     盒子不够大就等于什么都没画。实测放到 ±60% 才有「光从身上透出来」的样子。 */
.ss-tera-burst {
  position: absolute; left: -60%; right: -60%; top: -42%; bottom: -22%;
  z-index: -2; pointer-events: none;
  opacity: .5;
  background: repeating-conic-gradient(from 0deg,
    var(--tc) 0deg 6deg, rgba(0, 0, 0, 0) 6deg 26deg);
  -webkit-mask: radial-gradient(closest-side, rgba(0, 0, 0, .95) 0 26%,
    rgba(0, 0, 0, .55) 52%, rgba(0, 0, 0, 0) 82%);
  mask: radial-gradient(closest-side, rgba(0, 0, 0, .95) 0 26%,
    rgba(0, 0, 0, .55) 52%, rgba(0, 0, 0, 0) 82%);
  filter: blur(1.4px);
  animation: ssTeraSpin 16s linear infinite, ssTeraBreath 3.6s ease-in-out infinite;
}
/* 护罩打碎之后棱光只剩一层残影 —— 壳没了，光不该还是满格 */
.ss-tera-burst.broken { opacity: .22; }

/* ② 晶环：脚下一圈发光的椭圆
   ★ 两个坑：
     ① 别用 `border + scaleY(.36)` 做椭圆 —— 竖向一压，2px 的边只剩 0.7px，直接消失。
        正解是给一个**横向拉长、竖向压扁的盒子**，再用 `radial-gradient(closest-side)`
        画环：渐变自己跟着盒子变椭圆，不需要 transform。
     ② 要**比立绘还宽**（150%）：大部分精灵图是撑满画布的，写 100% 的环整个藏在脚底下，
        只露出正前方一小段，看着像踩了块石头。 */
.ss-tera-ring {
  position: absolute; left: 50%; bottom: -6%;
  width: 150%; height: 26%;
  transform: translateX(-50%);
  z-index: -1; pointer-events: none;
  opacity: .72;
  /* ★ 三层：亮环（最上）、**暗垫**（垫在亮环外面一圈）、外圈柔光。
     暗垫这一层是 2026-11-01 实测补上的：一般的属性色是米灰（#c9c6b0），
     落在锦汇那种浅色石板广场上，整个环和地面一个色，等于没画。
     加一圈 30% 的墨色垫底之后，浅背景上它是一条有边的环，深背景上仍然是一圈光。 */
  background:
    radial-gradient(closest-side, rgba(0, 0, 0, 0) 56%, var(--tc) 61%,
      var(--tc) 66%, rgba(0, 0, 0, 0) 71%),
    radial-gradient(closest-side, rgba(0, 0, 0, 0) 52%, rgba(8, 16, 26, .34) 62%,
      rgba(8, 16, 26, .34) 70%, rgba(0, 0, 0, 0) 80%),
    radial-gradient(closest-side, rgba(0, 0, 0, 0) 50%, var(--tc) 78%,
      rgba(0, 0, 0, 0) 98%);
}
/* 环上再叠一圈会转的短划，光才是"活的" */
.ss-tera-ring::before {
  content: ''; position: absolute; inset: 0; border-radius: 50%;
  background: repeating-conic-gradient(from 0deg,
    var(--tc) 0deg 9deg, rgba(0, 0, 0, 0) 9deg 34deg);
  -webkit-mask: radial-gradient(closest-side, rgba(0, 0, 0, 0) 58%, #000 70%,
    #000 84%, rgba(0, 0, 0, 0) 92%);
  mask: radial-gradient(closest-side, rgba(0, 0, 0, 0) 58%, #000 70%,
    #000 84%, rgba(0, 0, 0, 0) 92%);
  animation: ssTeraSpin 9s linear infinite;
}
@keyframes ssTeraSpin { from { transform: rotate(0deg); } to { transform: rotate(360deg); } }
@keyframes ssTeraBreath {
  0%, 100% { opacity: .42; }
  50% { opacity: .62; }
}

/* ③ 太晶冠：头顶五枚晶柱，中间最高、两侧依次倾斜。
   ★ 落点 `top` 由 app.js 写成**这只图里图形顶端**的比例（后端按 species 量的）——
     卡比兽 0.299、电肚蛙 0.000，差了三成，写死一个数字必然一半埋脸一半悬空。
   ★ `translate(-50%,-100%)`：冠的**底边**贴那条线，往上传，所以不会挡住头顶。 */
.ss-tera-crown {
  /* ★ 尺寸全用**百分比**，不用 aspect-ratio：wrap 是正方形（宽=高），
     所以 `height:34%` 和 `width:62% + 11:6` 完全等价，但少一个浏览器特性依赖
     （这顶冠是整条线的门面，不想赌老 WebView 支不支持 aspect-ratio）。 */
  position: absolute; left: 50%; width: 62%; height: 34%;
  transform: translate(-50%, -100%);
  z-index: 6; pointer-events: none;
  animation: ssTeraFloat 3.4s ease-in-out infinite;
}
.ss-tera-crown i {
  position: absolute; bottom: 0; width: 22%; height: 76%;
  transform-origin: 50% 100%;
  /* ★ 两层：属性色本体 + 一层很淡的**棱光彩虹**。
     只给纯色的话，米灰/银白这类属性色出来的是一枚"纸冠"（卡比兽那张）；
     叠 8%~18% 的彩虹之后，不管什么属性都像水晶折射。 */
  background:
    linear-gradient(24deg, rgba(126, 226, 255, .30) 0%, rgba(255, 138, 220, .24) 52%,
      rgba(255, 240, 168, .30) 100%),
    linear-gradient(158deg, #ffffff 0%, var(--tc) 46%, rgba(255, 255, 255, .92) 100%);
  clip-path: polygon(50% 0%, 100% 36%, 78% 100%, 22% 100%, 0% 36%);
  box-shadow: 0 0 10px var(--tc);
  /* ★ 两层：先属性色的光，再一层**墨色投影**。只给彩光的话，米灰/银白这类
     属性色在浅色石板背景上会和地面糊成一片（卡比兽那张实测像纸片），
     加一道 1px 的下投影，任何背景上都有轮廓。 */
  filter: drop-shadow(0 0 5px var(--tc)) drop-shadow(0 1px 2px rgba(10, 20, 30, .5));
}
.ss-tera-crown i:nth-child(1) { left: 6%; transform: rotate(-28deg) scale(.62); }
.ss-tera-crown i:nth-child(2) { left: 24%; transform: rotate(-14deg) scale(.82); }
.ss-tera-crown i:nth-child(3) { left: 39%; }
.ss-tera-crown i:nth-child(4) { left: 54%; transform: rotate(14deg) scale(.82); }
.ss-tera-crown i:nth-child(5) { left: 72%; transform: rotate(28deg) scale(.62); }
@keyframes ssTeraFloat {
  0%, 100% { transform: translate(-50%, -100%); }
  50% { transform: translate(-50%, -100%) translateY(-9%); }
}

/* 立绘本体：只加一点点饱和度 + 属性色描边光，**不动尺寸** */
.ss-mon-wrap.tera .ss-mon {
  filter: saturate(1.18) brightness(1.05) drop-shadow(0 0 9px var(--tc));
}

/* 右上角标（和极巨化同角，见 app.js 的注释） */
.ss-tera-tag {
  position: absolute; right: 10px; top: 10px; z-index: 9;
  pointer-events: none;
  font-size: 11px; letter-spacing: .06em;
  padding: 2px 9px; border-radius: 999px;
  color: #08161d;
  background: linear-gradient(100deg, #ffffff 0%, var(--tc) 78%);
  box-shadow: 0 0 12px var(--tc);
}

/* 血条上的水晶壳分界：最后那 1 点血就是壳，虚线标出来。打碎后这条线自然消失
   （app.js 只在 `teraShield` 为真时才给 `--shield`，没给就整个类都不加）。 */
.ss-hp.tera { position: relative; }
.ss-hp.tera::after {
  content: ''; position: absolute; top: -1px; bottom: -1px;
  left: var(--shield); width: 0;
  border-left: 1px dashed rgba(255, 255, 255, .9);
  box-shadow: 0 0 4px rgba(255, 255, 255, .8);
}

/* 名字 + 血条贴在宝可梦**正下方**（2026-10-30 需求第 5 条）。
   wrap 的锚点是脚底中心、高度就是宝可梦高度 ⇒ `top:100%` 正好落在脚下面。 */
.ss-mon-info {
  position: absolute; top: 100%; left: 50%;
  transform: translateX(-50%);
  width: 96px; margin-top: 3px;
  pointer-events: none;
}
.ss-mi-row {
  display: flex; align-items: baseline; justify-content: center; gap: 3px;
  font-size: 10px; line-height: 1.2; color: #fff;
  text-shadow: 0 1px 3px rgba(0, 0, 0, .9);
  white-space: nowrap;
}
.ss-mi-row b { font-weight: 700; }
.ss-mi-row span { font-size: 9px; opacity: .8; }
.ss-mon-info .ss-hp { height: 6px; }

/* 敌方训练家的名字：贴在他本人**头顶正上方一点**（2026-10-30 需求第 4 条） */
.ss-foe-tag {
  position: absolute; z-index: 6;
  transform: translate(-50%, -100%);
  padding: 1px 8px 2px;
  border-radius: 999px;
  background: rgba(10, 16, 24, .66);
  box-shadow: 0 1px 4px rgba(0, 0, 0, .35);
  color: #fff; font-size: 11px; font-weight: 700; letter-spacing: .3px;
  white-space: nowrap; pointer-events: none;
}

/* 换波横幅（2026-10-31）：小弟打完换馆主上场时，舞台正中压一条大字提示。
   之前只有一个小 toast，孩子盯着题目根本没注意到台上换了人。
   动画：砸下来 → 停住 → 淡出（总 2.4s，由 JS 的到期时间戳对齐）。 */
.ss-wave-banner {
  position: absolute; z-index: 9;
  left: 50%; top: 34%;
  transform: translate(-50%, -50%);
  padding: 10px 22px;
  border-radius: 14px;
  background: rgba(10, 16, 24, .78);
  box-shadow: 0 4px 18px rgba(0, 0, 0, .45);
  color: #fff; font-size: 19px; font-weight: 800; letter-spacing: 1px;
  white-space: nowrap; pointer-events: none;
  animation: ssWaveBanner 2.4s ease forwards;
}
@keyframes ssWaveBanner {
  0%   { opacity: 0; transform: translate(-50%, -120%) scale(1.25); }
  12%  { opacity: 1; transform: translate(-50%, -50%) scale(1); }
  78%  { opacity: 1; transform: translate(-50%, -50%) scale(1); }
  100% { opacity: 0; transform: translate(-50%, -56%) scale(.96); }
}

/* 我方训练家：**半身背影、最下偏右**，朝敌方宝可梦那边（2026-10-30 需求第 6 条）。
   ★ 素材是另出的背面图（`actor_player_back.webp`）：头肩特写、512 方画布、底边贴底。
     正面立绘镜像后仍是"正脸大头"，做不出背影 —— 别退回去用 `scaleX(-1)` 糊。
   ★ `top:101%` 把底边压到舞台外一点点，底部的 mask 渐隐才不会留一条直线。 */
.ss-me {
  position: absolute; z-index: 4;
  /* ★ 位置是被两条血条"夹"出来的，不是随便定的：
       伊布的 info 占 46%~142、百合根娃娃的 info 占 205%~301（舞台百分比）。
       人只要露半身，横向就只有 52% 这一个缝能站 ——
       往右一点就压住敌方血条，往左一点就压住我方血条。
     left 52% 仍在中线右侧；头朝右 ⇒ 视线越过画面对上 0.70 那只怪。
     height 20% + top 100%：素材是"头+肩+胸"，20% 正好露到肩膀，
     再小就只剩一顶帽子（用户要的是"半身背影"，不是"一个后脑勺"）。 */
  left: 52%; top: 100%; height: 20%;
  /* 顺时针 3 度（以脚底为轴）：整个人往右前方倾一点，才像"在看右边那只怪"。
     素材本身头是平的，正着放会显得在发呆。 */
  transform: translate(-50%, -100%) rotate(3deg);
  transform-origin: 50% 100%;
  pointer-events: none;
  filter: brightness(.94) saturate(.98) drop-shadow(-5px 4px 9px rgba(0, 0, 0, .3));
  -webkit-mask-image: linear-gradient(to top, rgba(0, 0, 0, 0) 0, #000 16%);
  mask-image: linear-gradient(to top, rgba(0, 0, 0, 0) 0, #000 16%);
}
/* 同伴（派帕）：站主角右侧稍后，只露到胸口 —— "跟着来看"，不抢主角。
   位置让开敌方宝可梦脚下的名字血条（那条横向占 62%~78%），所以从 84% 起。 */
.ss-pal {
  position: absolute; z-index: 3;
  left: 84%; top: 100%; height: 17%;
  transform: translate(-50%, -100%) rotate(-2deg);
  transform-origin: 50% 100%;
  pointer-events: none;
  filter: brightness(.96) saturate(.98) drop-shadow(-5px 4px 9px rgba(0, 0, 0, .3));
  -webkit-mask-image: linear-gradient(to top, rgba(0, 0, 0, 0) 0, #000 14%);
  mask-image: linear-gradient(to top, rgba(0, 0, 0, 0) 0, #000 14%);
}
@keyframes ssShake {
  0%, 100% { transform: translate(-50%, -100%); }
  15% { transform: translate(calc(-50% - 6px), -100%); }
  35% { transform: translate(calc(-50% + 6px), -100%); }
  55% { transform: translate(calc(-50% - 4px), -100%); }
  75% { transform: translate(calc(-50% + 3px), -100%); }
}
@keyframes ssLunge {
  0%   { transform: translate(-50%, -100%) scale(1); }
  40%  { transform: translate(-50%, -108%) scale(1.07); }
  100% { transform: translate(-50%, -100%) scale(1); }
}
/* 伤害飘字：打掉一只必须看得见数字，否则 11 只的队伍完全没有节奏感 */
.ss-dmg {
  position: absolute; z-index: 7;
  font-weight: 800; font-size: 22px; color: #ff5a4d;
  text-shadow: 0 2px 4px rgba(0, 0, 0, .6);
  pointer-events: none;
  animation: btFloat .95s ease-out forwards;
}
.ss-dmg.on-foe { left: 71%; top: 60%; }
.ss-dmg.on-own { left: 24%; top: 70%; }

/* 台词气泡改成**叠在舞台里**（原先是页面上方的米色卡片）：
   省掉 60~90px 的纵向空间，舞台才能有 60vh。 */
.story-dialog.ss-dlg {
  position: absolute; left: 8px; right: 8px; bottom: 8px; z-index: 6;
  margin: 0; padding: 7px 10px;
  background: rgba(10, 16, 24, .76);
  border: 0; border-radius: 10px;
}
.story-dialog.ss-dlg .sd-en { color: #ffe9a8; font-size: 13px; }
.story-dialog.ss-dlg .sd-cn { color: #e8eef6; font-size: 12px; margin-top: 2px; }
.story-dialog.ss-dlg .sd-intro { color: #b8c4d2; font-size: 11.5px; margin-top: 4px; line-height: 1.4; }
/* 台词气泡长大会盖住宝可梦 —— 而「两只宝可梦必须看得见」是硬要求，
   所以中英文各限两行、旁白在矮屏直接不要（2026-10-30 小屏 667 实测被盖满）。 */
.story-dialog.ss-dlg .sd-en,
.story-dialog.ss-dlg .sd-cn {
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  overflow: hidden;
}
@media (max-height: 760px) {
  .story-dialog.ss-dlg { padding: 5px 8px; border-radius: 8px; }
  .story-dialog.ss-dlg .sd-intro { display: none; }
  .story-dialog.ss-dlg .sd-en { font-size: 12px; }
  .story-dialog.ss-dlg .sd-cn { font-size: 11.5px; }
}

/* 馆内界面弹层 */
.modal-head {
  display: flex; align-items: center; gap: 8px;
  margin: -4px 0 12px;
}
.modal-head b { font-size: 16px; }
.modal-head .sub { color: var(--muted); font-size: 13px; }
.modal-head .x {
  margin-left: auto; border: 0; background: transparent;
  font-size: 18px; color: var(--muted); cursor: pointer; line-height: 1;
}
.sp-leader {
  width: 96px; height: 96px; object-fit: contain;
  image-rendering: pixelated;
  display: block; margin: 0 auto 10px;
  background: #f0f0f3; border-radius: 12px; padding: 6px;
}
.sp-badge { text-align: center; font-weight: 600; color: var(--good, #39c06a); margin-bottom: 10px; }
.sp-badge.dim { color: var(--muted); font-weight: 500; }
.sp-seq-title { font-size: 12px; color: var(--muted); margin: 4px 0 6px; }
.sp-seq { display: flex; flex-direction: column; gap: 6px; margin-bottom: 14px; }
.seq-row {
  display: flex; align-items: center; gap: 8px;
  padding: 7px 10px; border-radius: 9px;
  background: var(--surface-2, #f3f4f6); font-size: 13px;
}
.seq-row.leader { background: #fff4e0; border: 1px solid #f0d9a8; font-weight: 600; }
.seq-idx {
  width: 20px; height: 20px; flex: none;
  display: flex; align-items: center; justify-content: center;
  background: var(--primary); color: #fff; border-radius: 50%;
  font-size: 11px;
}
.seq-name { flex: 1; }
.seq-tag { color: var(--muted); font-size: 11px; }
.seq-row.leader .seq-tag { color: #c8861a; }

/* ---------- 词表分级（主表 / 子表） ---------- */
.sp-entry { padding: 14px; }
.sp-head { display: flex; justify-content: space-between; align-items: baseline; margin-bottom: 8px; }
.sp-head b { font-size: 15px; }
.sp-head span { font-size: 12px; color: var(--muted); }
.sp-bar { display: flex; height: 8px; border-radius: 999px; overflow: hidden; background: var(--border); }
.sp-bar i { display: block; height: 100%; }
.sp-bar i.b { background: #3b3f46; }
.sp-bar i.g { background: #9aa1ab; }
.sp-bar i.w { background: var(--good); }
.sp-legend { display: flex; gap: 14px; font-size: 12px; color: var(--muted); margin-top: 6px; }

/* ---------- 单词速刷 ---------- */
.sp-tip {
  background: var(--primary-soft); color: var(--primary); border-radius: var(--radius);
  padding: 10px 12px; font-size: 13px; margin-bottom: 10px;
}
.sp-timer { text-align: center; font-size: 20px; font-weight: 700; color: var(--primary); margin-bottom: 8px; }
.sp-timer.warn { color: var(--again); }

/* 每行一个词，不做多列，方便一眼扫过 */
.sp-grid { display: grid; grid-template-columns: 1fr; gap: 8px; }
.sp-cell {
  position: relative; background: var(--surface); border: 1px solid var(--border);
  border-radius: 10px; padding: 11px 14px; font-size: 16px;
  cursor: pointer; user-select: none; word-break: break-word;
}
.sp-cell.on { background: #fdecec; border-color: var(--again); color: var(--again); }
.sp-cell i { position: absolute; top: 50%; right: 12px; transform: translateY(-50%);
  font-style: normal; font-size: 13px; }
.sp-foot { display: flex; align-items: center; gap: 10px; margin-top: 14px; }
.sp-foot .sp-page { flex: 1; text-align: center; font-size: 13px; color: var(--muted); }

.sp-match { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; }
.sp-col { display: flex; flex-direction: column; gap: 8px; }
.sp-tile {
  border: 1px solid var(--border); background: var(--surface); border-radius: 10px;
  padding: 10px 8px; font-size: 14px; text-align: center; cursor: pointer;
  word-break: break-word; min-height: 44px; display: flex; align-items: center; justify-content: center;
}
.sp-tile.on { border-color: var(--primary); background: var(--primary-soft); color: var(--primary); }
.sp-tile.used { opacity: .35; pointer-events: none; }
.sp-tile.g { font-size: 13px; }

.sp-rrow { display: flex; align-items: center; gap: 10px; padding: 9px 0; border-bottom: 1px solid var(--border); }
.sp-rrow:last-child { border-bottom: 0; }
.sp-rrow b { min-width: 92px; }
.sp-rrow span { flex: 1; color: var(--muted); font-size: 13px; }
.sp-rrow i { font-style: normal; font-size: 12px; padding: 2px 10px; border-radius: 999px; }
.sp-rrow.ok i { background: #e7f7ef; color: var(--good); }
.sp-rrow.no i { background: #fdecec; color: var(--again); }
.sp-done { text-align: center; padding: 20px; }
.sp-big { font-size: 20px; font-weight: 700; margin-bottom: 8px; }
.sp-resume { border-left: 3px solid var(--hard); }

/* 答错时补看该词的其余义项 */
.sp-rwhy { padding-bottom: 10px; }
.sp-rwhy .sense { color: var(--muted); font-size: 13px; }
.bt-all { margin-top: 12px; }
.bt-all .sense { color: var(--muted); font-size: 14px; }

/* ---------- 首页：出战伙伴横条 ---------- */
.hp-top { display: flex; justify-content: space-between; align-items: baseline; margin-bottom: 10px; }
.hp-top b { font-size: 14px; }
.hp-row { display: flex; gap: 8px; }
.hp-slot {
  position: relative; flex: 1; aspect-ratio: 1 / 1; border-radius: 10px;
  background: var(--bg); border: 1px solid var(--border); overflow: hidden;
  display: flex; align-items: center; justify-content: center;
}
.hp-slot img { width: 84%; height: 84%; object-fit: contain; }
.hp-slot i {
  position: absolute; left: 0; right: 0; bottom: 0; font-style: normal; text-align: center;
  font-size: 10px; color: var(--muted); background: rgba(255, 255, 255, .86);
}
.hp-slot.empty { color: var(--muted); font-size: 18px; }

/* ---------- 本篇结算 ---------- */
.sm-hero { text-align: center; }
.sm-big { font-size: 22px; font-weight: 700; margin-bottom: 4px; }
.sm-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 8px; margin-bottom: 12px; }
.sm-cell {
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius);
  padding: 12px 4px; text-align: center;
}
.sm-cell b { display: block; font-size: 24px; font-weight: 600; line-height: 1.2; }
.sm-cell span { font-size: 12px; color: var(--muted); }
.sm-cell.ok b { color: var(--good); }
.sm-cell.bad b { color: var(--again); }
.sm-cell.pick b { color: var(--primary); }
.sm-cell.wh b { color: var(--muted); }
.sm-pts { text-align: center; font-size: 14px; }
.sm-pts b { color: var(--hard); font-size: 18px; }
.sm-dist-t { font-size: 13px; color: var(--muted); margin-bottom: 8px; }

/* ---- 读后练习（阅读理解单选） ---- */
.quiz-panel { border-left: 3px solid var(--primary); }
.qz-item { padding: 12px 0; border-bottom: 1px solid var(--line); }
.qz-item:last-child { border-bottom: 0; }
.qz-q { font-size: 15px; line-height: 1.55; margin-bottom: 8px; }
.qz-q b { color: var(--primary); }
.qz-opt {
  display: flex; align-items: flex-start; gap: 8px; padding: 8px 10px;
  border: 1px solid var(--line); border-radius: 10px; margin-bottom: 6px;
  cursor: pointer; background: #fff;
}
.qz-opt i {
  font-style: normal; flex: none; width: 20px; height: 20px; line-height: 20px;
  text-align: center; border-radius: 50%; background: #eef2f7;
  font-size: 12px; font-weight: 600; color: var(--muted);
}
.qz-opt span { flex: 1; font-size: 14px; line-height: 1.5; }
.qz-opt.on { border-color: var(--primary); background: #eef4ff; }
.qz-opt.on i { background: var(--primary); color: #fff; }
.qz-opt.right { border-color: #22a06b; background: #eafaf1; }
.qz-opt.right i { background: #22a06b; color: #fff; }
.qz-opt.wrong { border-color: #e05252; background: #fdeeee; }
.qz-opt.wrong i { background: #e05252; color: #fff; }
.qz-why {
  margin-top: 6px; font-size: 13px; line-height: 1.6; color: var(--muted);
  background: #f7f9fb; border-radius: 8px; padding: 8px 10px;
}

/* ---------- 多档案顶栏 ---------- */
.pf-bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  margin: 0 0 10px;
}
.pf-chip {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  max-width: 55%;
  padding: 5px 12px;
  border: 1px solid var(--border);
  border-radius: 999px;
  background: var(--surface);
  color: var(--text);
  font-weight: 600;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.pf-chip i { font-style: normal; color: var(--muted); font-size: 11px; }
/* 胶囊里的档案头像：登录页那套是 34px，缩小才塞得进这么窄的按钮 */
.pf-chip .login-face-img { width: 20px; height: 20px; }
.pf-unit {
  color: var(--muted);
  font-size: 12px;
  text-align: right;
  line-height: 1.35;
}
.pf-unit b { color: var(--primary); font-size: 14px; }
.pf-unit em { font-style: normal; opacity: .8; }
.pf-row {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 4px 0;
  border-bottom: 1px solid var(--border);
}
.pf-row:last-of-type { border-bottom: 0; }
.pf-row.on .pf-pick { color: var(--primary); font-weight: 600; }
.pf-pick {
  flex: 1;
  text-align: left;
  padding: 9px 4px;
  border: 0;
  background: transparent;
  color: var(--text);
  border-radius: 8px;
}
.pf-mini {
  padding: 5px 10px;
  font-size: 12px;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--surface);
  color: var(--muted);
}
.pf-mini.danger { color: var(--again); border-color: #f5c2c4; }

/* ---------- 登录页 ---------- */
.login-wrap {
  /* 32 = #app 上下 padding；后面那 120 = 底部 ICP 备案号那一行（`.icp-bar`）+ 余量。
     不减这一截，门禁页正好占满一屏，备案号被挤到屏外 —— 管局查首页时
     "要滚一下才看得到"很容易被判未悬挂。减完登录卡片仍然居中，只是整体上移一点。
     ★ 实测（390×844）：减 112 时备案号底边 854 还是差 10px 出屏，所以再让出 40。 */
  min-height: calc(100vh - 152px);
  display: flex;
  align-items: center;
  justify-content: center;
}
.login-panel {
  width: 100%;
  max-width: 340px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 16px;
  padding: 28px 22px 22px;
  text-align: center;
  box-shadow: 0 8px 30px rgba(31, 35, 41, .06);
}
.login-logo { font-size: 40px; line-height: 1; }
.login-title { font-size: 20px; margin: 10px 0 2px; }
/* 备案里的「网站名称」（2026-11-03）。管局核验会比对这一行，所以它必须**看得见**，
   但又不能抢「背书助手」的视觉位置 —— 11.5px 灰字 + 拉开字距，读起来像登记名。 */
.login-site {
  margin: 0 0 8px; text-align: center;
  font-size: 11.5px; letter-spacing: .18em; color: var(--muted);
}
.login-sub { color: var(--muted); font-size: 13px; margin: 0 0 18px; }
.login-list { display: flex; flex-direction: column; gap: 10px; }
.login-card {
  display: flex;
  align-items: center;
  gap: 12px;
  width: 100%;
  padding: 12px 14px;
  border: 1px solid var(--border);
  border-radius: 12px;
  background: #fafbfc;
  color: var(--text);
  text-align: left;
}
.login-card:active { background: var(--primary-soft); }
.login-face { font-size: 26px; line-height: 1; }
.login-face-img {
  width: 34px; height: 34px; border-radius: 50%; object-fit: cover;
  display: inline-block; vertical-align: middle;
}
.av-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 10px; margin: 14px 0; }
.av-opt {
  border: 1px solid var(--border); border-radius: 12px; padding: 6px;
  background: #fff; cursor: pointer;
}
.av-opt:active { background: var(--primary-soft); }
.av-opt img { width: 100%; height: 44px; object-fit: contain; display: block; }
.av-emo-row { display: flex; flex-wrap: wrap; gap: 8px; }
.av-emo { font-size: 24px; padding: 6px 12px; border-radius: 10px; }
.av-tabs { display: flex; gap: 8px; margin: 12px 0 8px; }
.av-tab { flex: 1; padding: 8px 0; border: 1px solid var(--border); border-radius: 10px; background: #fff; color: var(--text); font-size: 14px; cursor: pointer; }
.av-tab.on { background: var(--primary); color: #fff; border-color: var(--primary); }
.av-poke-grid { display: grid; grid-template-columns: repeat(6, 1fr); gap: 6px; margin: 10px 0; }
.av-poke { padding: 4px; }
.av-poke img { width: 100%; height: 36px; object-fit: contain; display: block; }
.av-page-row { display: flex; flex-wrap: wrap; gap: 4px; justify-content: center; margin: 8px 0; }
.av-page { min-width: 28px; padding: 4px 6px; border: 1px solid var(--border); border-radius: 6px; background: #fff; font-size: 12px; cursor: pointer; }
.av-page.on { background: var(--primary); color: #fff; border-color: var(--primary); }
.login-name { flex: 1; font-weight: 600; }
.login-name i { font-style: normal; font-size: 13px; margin-left: 2px; }
.login-last {
  font-style: normal;
  font-size: 10px;
  color: var(--muted);
  border: 1px solid var(--border);
  border-radius: 999px;
  padding: 1px 6px;
  margin-left: 6px;
  font-weight: 400;
  vertical-align: 1px;
}
.login-go { color: var(--primary); font-size: 13px; }
.login-pinbox { margin-top: 4px; }
.login-pin-title { font-weight: 600; margin-bottom: 10px; }
.login-pin-row { display: flex; gap: 8px; }
/* 窄屏上「进入」会被挤成竖排 → 按钮不许被压缩 */
.login-pin-row .btn { flex: 0 0 auto; white-space: nowrap; }
.login-pin-row input {
  flex: 1;
  padding: 10px 12px;
  border: 1px solid var(--border);
  border-radius: 10px;
  font-size: 18px;
  letter-spacing: 4px;
  text-align: center;
}
.login-err { color: var(--again); font-size: 13px; margin-top: 8px; }

/* 站点门禁页（公网模式）：和密码框分开写 —— 口令是长串字符，
   不要 login-pinbox 那个 letter-spacing:4px + 居中对齐（看着像在读密码本）。 */
.gate-box { display: flex; gap: 8px; margin-top: 4px; }
.gate-box .btn { flex: 0 0 auto; white-space: nowrap; }
.gate-box input {
  flex: 1;
  min-width: 0;
  padding: 10px 12px;
  border: 1px solid var(--border);
  border-radius: 10px;
  font-size: 16px;
}
.login-hint { font-size: 13px; color: var(--muted, #888); margin-top: 8px; }
.login-note { font-size: 12px; color: var(--muted, #888); margin-top: 14px; line-height: 1.6; }
.login-back {
  margin-top: 12px;
  border: 0;
  background: transparent;
  color: var(--muted);
  font-size: 13px;
}
/* 「记住我」：勾了 cookie 存 30 天，不勾关掉浏览器就要重输 */
.login-remember {
  display: flex;
  align-items: center;
  gap: 6px;
  margin-top: 10px;
  font-size: 13px;
  color: var(--muted);
  cursor: pointer;
}
.login-remember input { width: 16px; height: 16px; margin: 0; }

/* ---------- 老师布置（临时词表） ---------- */
.tch-item {
  padding: 12px 0;
  border-bottom: 1px solid var(--border);
}
.tch-item:first-child { padding-top: 0; }
.tch-item:last-child { padding-bottom: 0; border-bottom: 0; }
.tch-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 10px;
  margin-bottom: 6px;
}
.tch-head b { font-size: 15px; font-weight: 600; word-break: break-all; }
.tch-head span { color: var(--muted); font-size: 12px; white-space: nowrap; }
.tch-item .btn-row { margin-top: 8px; }

/* ---------- 首页伙伴挂件（存在感） ---------- */
.hp-card {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 10px;
  border-radius: 10px;
  background: var(--primary-soft);
}
.hp-card .hp-av {
  flex: 0 0 auto;
  width: 62px;
  height: 62px;
  border-radius: 50%;
  background: #fff;
  display: flex;
  align-items: center;
  justify-content: center;
}
.hp-card .hp-av img { width: 88%; height: 88%; object-fit: contain; }
.hp-card.bounce .hp-av img { animation: hp-bounce .5s ease; }
@keyframes hp-bounce {
  0%, 100% { transform: translateY(0); }
  30% { transform: translateY(-9px) scale(1.08); }
  60% { transform: translateY(0) scale(.96); }
}
.hp-main { flex: 1; min-width: 0; }
.hp-name { font-weight: 600; font-size: 15px; }
.hp-name i {
  font-style: normal;
  color: var(--muted);
  font-weight: 400;
  font-size: 12px;
  margin-left: 4px;
}
.hp-exp {
  height: 6px;
  border-radius: 3px;
  background: #fff;
  overflow: hidden;
  margin: 5px 0 4px;
}
.hp-exp > i { display: block; height: 100%; background: var(--primary); }
.hp-say {
  font-size: 12.5px;
  color: var(--muted);
  min-height: 20px;
  transition: color .2s;
}
.hp-say.hot { color: var(--primary); font-weight: 600; }
.hp-cheer {
  flex: 0 0 auto;
  padding: 7px 12px;
  border: 0;
  border-radius: 999px;
  background: var(--primary);
  color: #fff;
  font-size: 13px;
}

/* ---------- 答题时伙伴冒头 ---------- */
.peek {
  position: fixed;
  right: 14px;
  bottom: 96px;
  z-index: 90;
  display: flex;
  align-items: flex-end;
  gap: 6px;
  pointer-events: none;
  animation: peek-in .28s ease both;
}
.peek.out { animation: peek-out .35s ease both; }
@keyframes peek-in {
  from { opacity: 0; transform: translateY(24px) scale(.8); }
  to { opacity: 1; transform: none; }
}
@keyframes peek-out {
  to { opacity: 0; transform: translateY(18px) scale(.9); }
}
.peek .pk-bub {
  max-width: 168px;
  padding: 7px 11px;
  border-radius: 12px 12px 2px 12px;
  background: var(--surface);
  border: 1px solid var(--border);
  box-shadow: 0 4px 14px rgba(0, 0, 0, .1);
  font-size: 13px;
  line-height: 1.45;
}
.peek.bad .pk-bub { border-color: #f5c2c4; }
.peek .pk-pic { width: 54px; height: 54px; object-fit: contain; }

/* ---------- 伙伴扒着屏幕边往里看（贴边站岗） ----------
   整层 pointer-events:none —— 这是氛围层，绝不能抢按钮的点击。
   只把身子挪出去大半、留小半个露在屏幕里，就是"扒着边往里看"的意思。 */
.edge-pets { position: fixed; inset: 0; pointer-events: none; z-index: 50; }
.edge-pet {
  position: absolute;
  width: 74px;
  height: 74px;
  opacity: .55;
  animation: edge-bob 5s ease-in-out infinite;
  -webkit-touch-callout: none;
  user-select: none;
}
.edge-pet img {
  width: 100%;
  height: 100%;
  object-fit: contain;
  image-rendering: pixelated;
}
/* 精灵图四周本来就有透明边距，所以"露出来"的部分要比裁掉的更宽一点，
   否则只剩一条看不清的色带，看不出是只宝可梦 */
.edge-pet.l { left: -28px; top: var(--a); }
.edge-pet.r { right: -28px; top: var(--a); }
.edge-pet.t { top: -28px; left: var(--a); }
/* 下边那只扒在标签栏的上沿：只把脑袋露出来（下半身被标签栏挡住），
   而且淡一档 —— 底部本来就压着图例和提示文字，露太多会碍眼 */
.edge-pet.b { bottom: 4px; left: var(--a); opacity: .45; }
@keyframes edge-bob {
  0%, 100% { transform: translateY(0); }
  50% { transform: translateY(-6px); }
}
/* 有事发生：随机一只探头动一下（答对跳一下，答错摇头） */
.edge-pet.hi { opacity: .95; }
.edge-pet.hi img { animation: edge-hi 1.15s ease both; }
.edge-pet.bad img { animation: edge-bad 1.15s ease both; }
@keyframes edge-hi {
  0% { transform: none; }
  25% { transform: translateY(-13px) scale(1.18); }
  60% { transform: translateY(-4px) scale(1.06); }
  100% { transform: none; }
}
@keyframes edge-bad {
  0%, 100% { transform: none; }
  20% { transform: translateX(7px) rotate(-7deg); }
  45% { transform: translateX(-7px) rotate(7deg); }
  70% { transform: translateX(4px) rotate(-4deg); }
}

/* ---------- 轻按留脚印 / 长按宝可梦走过来 ---------- */
.paw-trail { position: fixed; z-index: 80; pointer-events: none; }
.paw-trail span {
  position: absolute;
  font-size: 18px;
  line-height: 1;
  animation: paw-in 1.15s ease-out both;
}
@keyframes paw-in {
  0% { opacity: 0; transform: scale(.55); }
  25% { opacity: .8; transform: scale(1); }
  100% { opacity: 0; transform: scale(1) translateY(-9px); }
}
.walk-pet {
  position: fixed;
  z-index: 95;
  width: 62px;
  height: 62px;
  margin: -31px 0 0 -31px;      /* 让"脚底下"正好落在按点上 */
  pointer-events: none;
}
.walk-pet img {
  width: 100%;
  height: 100%;
  object-fit: contain;
  image-rendering: pixelated;
}
.walk-pet.hop img { animation: walk-hop .6s ease both; }
@keyframes walk-hop {
  0%, 100% { transform: translateY(0) scale(1); }
  40% { transform: translateY(-12px) scale(1.12); }
}

/* ---------- 进化仪式感 ---------- */
.evo {
  position: fixed;
  inset: 0;
  z-index: 200;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 14px;
  background: rgba(20, 24, 33, .82);
  color: #fff;
  animation: evo-bg .4s ease both;
}
@keyframes evo-bg { from { opacity: 0; } to { opacity: 1; } }
.evo h2 { margin: 0; font-size: 22px; letter-spacing: 1px; }
.evo .evo-sub { color: #c9cfda; font-size: 13px; margin-top: -8px; }
.evo-pair { display: flex; align-items: center; gap: 18px; }
.evo-pair img { width: 92px; height: 92px; object-fit: contain; }
.evo-pair img.from { animation: evo-fade 1.6s ease forwards; }
.evo-pair img.to {
  animation: evo-pop 1.1s cubic-bezier(.2, 1.5, .4, 1) .9s both;
  filter: drop-shadow(0 0 16px rgba(255, 235, 130, .9));
}
@keyframes evo-fade {
  0% { opacity: 1; }
  55% { opacity: 1; filter: brightness(3) blur(2px); }
  100% { opacity: .25; filter: brightness(1); }
}
@keyframes evo-pop {
  0% { opacity: 0; transform: scale(.3); }
  70% { opacity: 1; transform: scale(1.15); }
  100% { opacity: 1; transform: scale(1); }
}
.evo-arrow { font-size: 26px; opacity: .8; }
.evo .btn { background: rgba(255, 255, 255, .16); border: 0; color: #fff; }

/* ---------- 盖章：今天复习做完了，把当天的印章「盖」下来 ----------
   形象跟日历上那一枚完全一致（同一天同一只宝可梦，由服务端给 sp）。
   动作只有「从大到小 + 转正」一步 —— 像真的把章按下去，不是弹出来。
   渐变底和日历的 .cal-stamp 用同一组色，视觉上是同一枚章。
   约 1.7 秒自动退场，点一下也能立刻收起（小朋友会忍不住点）。 */
.stamp-pop {
  position: fixed;
  inset: 0;
  z-index: 200;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 6px;
  background: rgba(20, 24, 33, .78);
  color: #fff;
  cursor: pointer;
  animation: stamp-bg .22s ease both;
}
.stamp-pop.out { animation: stamp-fade .26s ease both; }
@keyframes stamp-bg { from { opacity: 0; } to { opacity: 1; } }
@keyframes stamp-fade { to { opacity: 0; } }
.sp-seal {
  width: 132px;
  height: 132px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  background: radial-gradient(circle at 50% 40%,
              rgba(255, 228, 156, .92), rgba(226, 160, 40, .55));
  box-shadow: inset 0 0 0 4px rgba(196, 136, 20, .6),
              0 10px 30px rgba(0, 0, 0, .35);
  /* 收尾停在 rotate(-8deg) —— 和日历印章同一个倾角，看着就是同一枚章 */
  animation: stamp-drop .62s cubic-bezier(.2, .9, .3, 1.25) both;
}
.sp-seal img {
  width: 96px;
  height: 96px;
  image-rendering: pixelated;
  filter: drop-shadow(0 2px 0 rgba(255, 255, 255, .45));
}
@keyframes stamp-drop {
  0%   { opacity: 0; transform: scale(2.4) rotate(-24deg); }
  60%  { opacity: 1; }
  100% { opacity: 1; transform: scale(1) rotate(-8deg); }
}
.sp-txt {
  font-size: 20px;
  font-weight: 600;
  letter-spacing: 1px;
  animation: stamp-txt .4s ease .45s both;
}
.sp-sub { color: #c9cfda; font-size: 13px; animation: stamp-txt .4s ease .55s both; }
@keyframes stamp-txt {
  from { opacity: 0; transform: translateY(8px); }
  to { opacity: 1; transform: none; }
}
/* 系统里开了「减少动态效果」（晕动症）就别转别缩，直接静态显示 */
@media (prefers-reduced-motion: reduce) {
  .sp-seal { animation: none; transform: rotate(-8deg); }
  .sp-txt, .sp-sub { animation: none; }
}

/* ---------- 复习收尾页：一批做完，盖在首页上 ----------
   跟盖章共用同一套暗底，区别在"停留时间"：盖章是演一下就退场，
   这个是让孩子自己点掉的。内容只有数量和一句睡前提示，别往里堆东西。 */
.closing-pop {
  position: fixed;
  inset: 0;
  z-index: 190;                 /* 比盖章（200）低，万一同时出现让章盖在上面 */
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 20px;
  background: rgba(20, 24, 33, .78);
  animation: stamp-bg .22s ease both;
}
.closing-pop.out { animation: stamp-fade .2s ease both; }
.cl-card {
  width: 100%;
  max-width: 330px;
  background: var(--surface);
  border-radius: 16px;
  padding: 22px 18px 16px;
  text-align: center;
  animation: stamp-txt .3s ease .08s both;
}
.cl-title { color: var(--muted); font-size: 14px; }
.cl-num { font-size: 38px; font-weight: 600; line-height: 1.2; margin: 2px 0 0; }
.cl-num i { font-style: normal; font-size: 15px; font-weight: 400; color: var(--muted); margin-left: 3px; }
.cl-sub { color: var(--muted); font-size: 13px; margin-top: 2px; }
.cl-tip {
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 12px 13px;
  text-align: left;
  margin: 16px 0;
}
.cl-tip-h { font-size: 14px; font-weight: 600; margin-bottom: 4px; }
.cl-tip-b { color: var(--muted); font-size: 13px; line-height: 1.65; }
@media (prefers-reduced-motion: reduce) {
  .cl-card { animation: none; }
}

/* ---------- 默写填空 ---------- */
.dic-q { font-size: 17px; line-height: 2; word-break: break-word; }
.dic-blank {
  display: inline-block;
  min-width: 92px;
  padding: 0 6px;
  border: 0;
  border-bottom: 2px solid var(--primary);
  background: var(--primary-soft);
  font: inherit;
  font-size: 16px;
  text-align: center;
  border-radius: 4px 4px 0 0;
}
.dic-blank:focus { outline: 0; background: #fff; }
.dic-blank.right { border-color: var(--good); background: #e8f8f0; color: #146c47; }
.dic-blank.wrong { border-color: var(--again); background: #fdecec; color: var(--again); }
.dic-zh { color: var(--muted); font-size: 14px; margin: 4px 0 12px; }
.dic-tip { font-size: 12.5px; color: var(--muted); margin-bottom: 10px; }
.dic-tip b { color: var(--text); }
/* 题面上一行：左边来源信息，右边「遮住中文」开关 */
.dic-bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 6px;
  margin-bottom: 10px;
}
.dic-bar .dic-tip { margin-bottom: 0; }
.dic-bar .btn { flex: 0 0 auto; }
.dic-zh-mid { margin: 8px 0 2px; font-size: 15px; }
.dic-score { font-size: 34px; font-weight: 600; }
.dic-wrong { display: flex; flex-wrap: wrap; gap: 6px; margin: 8px 0 4px; }
.dic-wtag {
  padding: 3px 10px;
  border-radius: 999px;
  background: #fdecec;
  color: #a8282c;
  font-size: 13.5px;
  font-weight: 600;
}
.dic-res {
  margin-top: 12px;
  padding: 10px 12px;
  border-radius: 10px;
  font-size: 14px;
  background: #e8f8f0;
  color: #146c47;
}
.dic-res.bad { background: #fdecec; color: #a8282c; }
.dic-res .ans { font-weight: 700; }

/* ---------- 科目切换（有语文内容才显示） ---------- */
.subj-tabs { display: flex; gap: 8px; margin-top: 12px; flex-wrap: wrap; }
.subj-tab {
  padding: 5px 12px;
  border: 1px solid var(--border);
  border-radius: 999px;
  background: var(--surface);
  color: var(--muted);
  font-size: 13px;
}
.subj-tab.on {
  border-color: var(--primary);
  background: var(--primary-soft);
  color: var(--primary);
  font-weight: 600;
}
.subj-tab i { font-style: normal; opacity: .6; font-size: 12px; }

/* ---------- 周末区域挑战赛 ---------- */
.pt-cup-note {
  margin-bottom: 10px;
  padding: 8px 10px;
  border-radius: 8px;
  background: var(--primary-soft);
  color: var(--primary);
  font-size: 13px;
}
.pt-cup-note.shut { background: #f1f2f4; color: var(--muted); }
.cup-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px; }
.cup-cell {
  padding: 8px 4px;
  border: 1px solid var(--border);
  border-radius: 10px;
  background: var(--surface);
  text-align: center;
}
.cup-cell.won { border-color: var(--good); background: #f2fbf7; }
.cup-cell img { width: 52px; height: 52px; object-fit: contain; display: block; margin: 0 auto; }
.cup-cell b { display: block; font-size: 13px; margin-top: 2px; }
.cup-cell span { font-size: 11px; color: var(--muted); }
.cup-cell .won-tag { color: var(--good); font-size: 11px; font-weight: 600; }
/* 剧情副本：卡片上直接列对手名，否则「关都」看着和别处没区别，孩子不会点 */
.cup-cell .cup-cast { display: block; font-size: 10px; line-height: 1.35;
                      margin-top: 2px; color: var(--muted); word-break: break-all; }
.cup-cell:disabled { opacity: .5; }
/* 没解锁的地区：比「周末没开」更弱一点，并把「还差几只」写成醒目的小字 */
.cup-cell.locked { opacity: .38; border-style: dashed; }
.cup-cell .cup-lock { display: block; font-size: 10px; line-height: 1.3;
                      margin-top: 2px; color: var(--warn, #b4780f); }

/* ---------- 默写 / 听写：提示与放音 ---------- */
.dic-hints { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 8px; }
.dic-hint {
  padding: 3px 10px;
  border-radius: 999px;
  font-size: 13px;
  background: #FAEEDA;
  color: #633806;
  border: 1px solid #EF9F27;
}
.dic-hint b { color: #412402; }
.dic-listen { text-align: center; margin: 6px 0 2px; }
.dic-play {
  width: 76px;
  height: 76px;
  border: 0;
  border-radius: 50%;
  background: var(--primary-soft);
  font-size: 30px;
  line-height: 1;
}
.dic-play:active { background: #d8e6ff; }
.ans-ipa { color: var(--muted); font-weight: 400; margin-left: 6px; }

/* ---------- 语文隐藏背诵 ---------- */
.zh-tag {
  font-style: normal;
  font-size: 11px;
  font-weight: 400;
  color: var(--primary);
  background: var(--primary-soft);
  border-radius: 4px;
  padding: 1px 5px;
  margin-left: 4px;
}
.zh-chips { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 12px; }
.zh-chip {
  padding: 5px 12px;
  border: 1px solid var(--border);
  border-radius: 999px;
  background: var(--surface);
  color: var(--muted);
  font-size: 13px;
}
.zh-chip.on {
  border-color: var(--primary);
  background: var(--primary-soft);
  color: var(--primary);
  font-weight: 600;
}
.zh-chip:disabled { opacity: .4; }
.zh-chip i { font-style: normal; opacity: .6; font-size: 12px; }
.zh-body { font-size: 17px; line-height: 2.2; letter-spacing: .3px; }
.zh-tipbar {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 10px;
  margin: 6px 0 10px;
}
.zh-tipbar span:first-child { flex: 1; }
.zh-count { color: var(--primary); font-weight: 600; font-size: 12.5px; white-space: nowrap; }
.zh-t { cursor: pointer; border-radius: 4px; padding: 0 1px; }
/* 悬停就亮一下 —— 不点出来，用户根本不知道词是可以点的（自选隐藏全靠这个） */
.zh-t:hover { background: #eef2f8; box-shadow: 0 0 0 2px #eef2f8; }
.zh-t.zh-b:hover { background: #dbe4f4; box-shadow: 0 0 0 2px #dbe4f4; }
/* 遮住：文字透明但**保留宽度** —— 版面不跳，宽度本身就是字数提示。
   user-select:none 是防止全选一下就把字露出来。 */
.zh-t.zh-b {
  background: #e9edf5;
  border-bottom: 2px solid var(--primary);
  color: transparent;
  user-select: none;
  -webkit-user-select: none;
  padding: 1px 3px;
  margin: 0 1px;
}
/* 有释义的字词：右上角「注」角标，点一下弹释义气泡 */
.zhg {
  cursor: help;
  color: var(--primary);
  font-size: 9px;
  vertical-align: super;
  font-weight: 700;
  margin-left: 1px;
  padding: 0 2px;
  border: 1px solid var(--primary);
  border-radius: 6px;
  user-select: none;
  -webkit-user-select: none;
  line-height: 1;
}
.zhg:hover { background: var(--primary); color: #fff; }
/* 释义气泡：fixed 定位，浮在角标下方 */
.zh-pop {
  position: fixed;
  z-index: 50;
  max-width: 280px;
  background: #fff;
  border: 1px solid var(--primary);
  border-radius: 8px;
  box-shadow: 0 6px 20px rgba(0,0,0,.15);
  padding: 8px 11px;
  font-size: 14px;
  line-height: 1.7;
  color: #222;
}
.zh-pop p { margin: 4px 0; }
/* 篇目讲解区 */
.zh-note {
  background: #fbfcfe;
  border-left: 3px solid var(--primary);
  font-size: 14.5px;
  line-height: 1.9;
  color: #2a2a2a;
}
.zh-note p { margin: 0 0 8px; }
.zh-note p:last-child { margin-bottom: 0; }
.zh-note b { color: var(--primary); }
.zh-note-btn {
  border: 1px solid var(--primary);
  background: #fff;
  color: var(--primary);
  border-radius: 14px;
  font-size: 12.5px;
  padding: 2px 10px;
  cursor: pointer;
  white-space: nowrap;
}
.zh-note-btn:hover { background: var(--primary); color: #fff; }

/* ---------- 语文配图（详见 docs §13） ----------
   一张图一块：位置 + 当前显示的图 + 一句话说明。
   图是本地的（data/images/），断网也在，所以这里不需要任何 loading 骨架。 */
.aip-top { display: flex; align-items: center; gap: 8px; margin-bottom: 10px; flex-wrap: wrap; }
.aip-top b { font-size: 14px; }
.aip-top .hint { flex: 1; }
.aip-seg { display: flex; border: 1px solid var(--border); border-radius: 999px; overflow: hidden; flex: none; }
.aip-seg button {
  border: 0; background: var(--surface); color: var(--muted);
  font-size: 12.5px; padding: 4px 12px;
}
.aip-seg button.on { background: var(--primary-soft); color: var(--primary); font-weight: 600; }
.aip-strip { display: flex; gap: 10px; overflow-x: auto; padding-bottom: 4px; }
.aip-card {
  flex: none; width: 132px; cursor: pointer;
  border: 1px solid var(--border); border-radius: 10px; overflow: hidden;
  background: var(--bg);
}
.aip-card:active { filter: brightness(.97); }
.aip-card img { width: 100%; height: 96px; object-fit: cover; display: block; }
.aip-card .aip-cap {
  font-size: 11.5px; color: var(--muted); padding: 5px 7px; line-height: 1.4;
  height: 42px; overflow: hidden;
}
.aip-card .aip-seq {
  position: absolute; margin: 5px; background: rgba(20, 22, 26, .55); color: #fff;
  border-radius: 6px; font-size: 11px; padding: 1px 6px;
}
.aip-wrap { position: relative; }
.aip-more {
  position: absolute; right: 5px; top: 5px;
  font-size: 11px; color: #fff; background: rgba(20, 22, 26, .55);
  border-radius: 6px; padding: 1px 6px;
}
.aip-big { width: 100%; border-radius: 10px; display: block; background: #fff; }
.aip-cand { display: flex; gap: 8px; overflow-x: auto; margin-top: 10px; }
.aip-cand img {
  width: 78px; height: 58px; object-fit: cover; border-radius: 8px; flex: none;
  border: 2px solid transparent; cursor: pointer;
}
.aip-cand img.on { border-color: var(--primary); }

/* ---------- 手绘画板 ---------- */
.draw {
  position: fixed; inset: 0; z-index: 60; background: var(--bg);
  display: flex; flex-direction: column; padding: 12px;
}
.draw-top { display: flex; align-items: center; gap: 8px; margin-bottom: 8px; }
.draw-top b { flex: 1; font-size: 14px; }
.draw-canvas {
  /* 3:2 横构图 —— 和 AI 出的图一个形状，将来「AI 图 / 我的画」切换时版面不跳 */
  width: 100%; max-width: 900px; margin: 0 auto;
  aspect-ratio: 3 / 2; max-height: 66vh;
  background: #fff; border: 1px solid var(--border); border-radius: var(--radius);
  touch-action: none;                 /* 关键：不然手指一画页面就跟着滚 */
  display: block;
}
.draw-tools {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  max-width: 900px; width: 100%; margin: 10px auto 0;
}
.draw-tools .d-pen {
  width: 30px; height: 30px; border-radius: 50%;
  border: 2px solid var(--border); padding: 0; flex: none;
}
.draw-tools .d-pen.on { border-color: var(--primary); transform: scale(1.12); }
.draw-tools .d-sz {
  min-width: 34px; padding: 4px 8px; border: 1px solid var(--border);
  background: var(--surface); border-radius: 8px; font-size: 12px;
}
.draw-tools .d-sz.on { border-color: var(--primary); color: var(--primary); font-weight: 600; }
.draw-tools select {
  border: 1px solid var(--border); border-radius: 8px; padding: 5px 8px;
  background: var(--surface); color: var(--text); font-size: 13px;
}

/* ---------- 英语跟读 ---------- */
.sec-row {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 10px;
  margin-bottom: 8px;
}
.aloud-sent {
  font-size: 18px;
  line-height: 1.9;
  letter-spacing: .2px;
  padding: 10px 12px;
  background: var(--primary-soft);
  border-radius: 10px;
  margin-bottom: 10px;
}
.aloud-rec { margin-top: 10px; }
.aloud-rec:empty { margin-top: 0; }
.aloud-rec audio { width: 100%; }
.aloud-rec .hint { margin-top: 6px; }
.aloud-warn { border-color: #f5c2c4; background: #fff8f8; }
.aloud-warn code {
  font-family: Consolas, Menlo, monospace;
  font-size: 12.5px;
  background: #fff;
  padding: 1px 5px;
  border-radius: 4px;
}

/* ---------- 复习日历（首页） ---------- */
.stats-btn { margin-left: auto; }
.cal-panel .hint { margin-top: 8px; text-align: center; }
.cal-empty { color: var(--primary); }
.cal-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 8px;
}
.cal-head b { font-size: 14.5px; }
/* 翻月：去掉按钮框，只留箭头，按下给个淡底反馈 */
.cal-nav {
  border: 0;
  background: transparent;
  color: #c4c2ba;
  font-size: 18px;
  line-height: 1;
  padding: 4px 12px;
  border-radius: 8px;
}
.cal-nav:active { background: var(--primary-soft); color: var(--primary); }
.cal-grid {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  gap: 5px;
  /* 收窄：720px 宽时每格会被拉成 95×54 的扁条，数字离角太远，很难看 */
  max-width: 420px;
  margin: 0 auto;
}
.cal-wd {
  text-align: center;
  font-size: 11.5px;
  color: var(--muted);
  padding: 2px 0;
}
/* 格子默认完全透明 —— 没任务的日子不该占视觉重量，
   只有"有量"的日子才被色阶点亮 */
.cal-cell {
  position: relative;
  min-height: 54px;
  border-radius: 10px;
  background: transparent;
  padding: 0;
}
.cal-cell.blank { background: transparent; }
.cal-cell b {
  position: absolute;
  top: 5px;
  left: 9px;
  font-weight: 400;
  font-size: 12px;
  color: #c4c2ba;
}
/* 量 = 底色深浅，四档：≤5 / ≤15 / ≤30 / 超过当日额度（转红＝这天超量了） */
.cal-cell.q1 { background: rgba(47, 111, 237, .16); }
.cal-cell.q1 b { color: #5b86dd; }
.cal-cell.q2 { background: rgba(47, 111, 237, .32); }
.cal-cell.q2 b { color: #3968cd; }
.cal-cell.q3 { background: rgba(47, 111, 237, .52); }
.cal-cell.q3 b { color: #1c4796; }
.cal-cell.q4 { background: rgba(229, 72, 77, .32); }
.cal-cell.q4 b { color: #a83a38; }
/* 虚线框 + 淡一档的底色 = 预测（新卡按日额度顺推出来的）；
   浓底实心 = FSRS 真排到这天。预测现在几乎铺满日历（还没开始背），
   等真复习过，实心格子才会一天天冒出来。 */
.cal-cell.fc { outline: 1px dashed rgba(47, 111, 237, .38); outline-offset: -1px; }
.cal-cell.fc.q1 { background: rgba(47, 111, 237, .10); }
.cal-cell.fc.q2 { background: rgba(47, 111, 237, .22); }
.cal-cell.fc.q3 { background: rgba(47, 111, 237, .36); }
.cal-cell.fc.q4 { background: rgba(229, 72, 77, .22); }
/* 今天：实线粗描边压过上面两种，一眼能找到 */
.cal-cell.today { outline: 2px solid var(--primary); outline-offset: -2px; }
.cal-cell.today b { color: var(--primary); font-weight: 500; }
/* 张数是格子里的主角：比日期大一号，放右下角 */
.cal-n {
  position: absolute;
  right: 9px;
  bottom: 5px;
  font-style: normal;
  font-size: 16px;
  font-weight: 500;
  line-height: 1.2;
  color: #1c4796;
}
.cal-cell.q1 .cal-n { color: #2f6fed; }
.cal-cell.q3 .cal-n { color: #16327a; }
.cal-cell.q4 .cal-n { color: #a3302f; }

/* ---------- 日历印章：那天把复习做完了，盖一只宝可梦 ----------
   做成"印章"的样子（圆环 + 暖色底 + 轻微倾斜），压在格子正中。
   日期数字抬到印章上面并加一圈白晕，免得被压糊。 */
.cal-cell b { z-index: 2; text-shadow: 0 0 3px rgba(255, 255, 255, .9); }
.cal-stamp {
  position: absolute;
  left: 50%;
  top: 50%;
  width: 32px;
  height: 32px;
  margin: -16px 0 0 -16px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  background: radial-gradient(circle at 50% 40%,
              rgba(255, 228, 156, .78), rgba(226, 160, 40, .34));
  box-shadow: inset 0 0 0 2px rgba(196, 136, 20, .55);
  transform: rotate(-8deg);
  pointer-events: none;
  z-index: 1;
}
.cal-stamp img {
  width: 25px;
  height: 25px;
  image-rendering: pixelated;
  filter: drop-shadow(0 1px 0 rgba(255, 255, 255, .5));
}
/* 来过、但没做完 —— 只留个浅脚印。不批评，但和"章"一眼分得开，
   小孩自己会想把它凑成章 */
.cal-track {
  position: absolute;
  left: 50%;
  top: 50%;
  margin: -8px 0 0 -8px;
  font-size: 15px;
  line-height: 1;
  opacity: .35;
  filter: grayscale(1);
  pointer-events: none;
  z-index: 1;
}
/* 已盖章的当天（同时有排期数字）：把数字挪到右上角，给印章让出格子正中，
   否则印章和数字会叠在一起 */
.cal-cell.stamped .cal-n {
  top: 5px;
  right: 7px;
  bottom: auto;
  font-size: 12px;
}
.lk.seal {
  border-radius: 50%;
  background: radial-gradient(circle at 50% 40%,
              rgba(255, 228, 156, .95), rgba(226, 160, 40, .6));
  box-shadow: inset 0 0 0 1px rgba(196, 136, 20, .7);
}
.cal-foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  flex-wrap: wrap;
  margin-top: 10px;
  font-size: 11.5px;
  color: var(--muted);
}
.cal-key { display: inline-flex; align-items: center; gap: 5px; }
.lk {
  width: 12px;
  height: 12px;
  border-radius: 3px;
  display: inline-block;
}
.lk.solid { background: rgba(47, 111, 237, .52); }
.lk.fc { background: rgba(47, 111, 237, .10); border: 1px dashed rgba(47, 111, 237, .5); }

/* 遗忘曲线：一张卡连续答「会」的间隔阶梯（柱高按 log 压，柱顶标真实天数） */
.cal-curve {
  margin-top: 10px;
  padding-top: 10px;
  border-top: 1px dashed var(--border);
}
.cc-head { font-size: 11.5px; color: var(--muted); margin-bottom: 8px; }
.cc-bars {
  display: flex;
  align-items: flex-end;
  gap: 8px;
}
.cc-b {
  flex: 1 1 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: flex-end;
}
.cc-v { font-size: 11.5px; font-weight: 500; color: var(--text); margin-bottom: 4px; }
.cc-b i {
  display: block;
  width: 100%;
  max-width: 44px;
  border-radius: 6px;
}
.cc1 { background: #b5d4f4; }
.cc2 { background: #85b7eb; }
.cc3 { background: #378add; }
.cc4 { background: #185fa5; }
.cc-x { font-size: 11px; color: var(--muted); margin-top: 5px; }
.cc-note { font-size: 11px; color: var(--muted); margin-top: 8px; }

/* ---------- 统计分析页（全部是内联 SVG 图表，见 app.js 的 CH/donutSvg/histSvg） ---------- */
.panel h3 { margin: 0 0 8px; font-size: 14.5px; }

/* 健康度：三个"体检数"（已毕业占比 / 积压天数 / 近 7 天完成率） */
.hk-grid {
  display: flex;
  gap: 8px;
}
.hk-cell {
  flex: 1 1 0;
  min-width: 0;
  border: 1px solid var(--border);
  border-left-width: 3px;
  border-radius: 10px;
  padding: 8px 6px 7px;
  text-align: center;
  background: #fff;
}
.hk-cell .hk-nm { display: block; font-size: 11.5px; color: var(--muted); margin-bottom: 3px; }
.hk-cell b { display: block; font-size: 19px; font-weight: 600; line-height: 1.15; }
.hk-cell em {
  display: block;
  font-style: normal;
  font-size: 10.5px;
  color: var(--muted);
  margin-top: 3px;
  line-height: 1.35;
}
.hk-cell.ok { border-left-color: #22b573; }
.hk-cell.ok b { color: #178a55; }
.hk-cell.warn { border-left-color: #f5a524; }
.hk-cell.warn b { color: #b8770d; }
.hk-cell.bad { border-left-color: #e5484d; }
.hk-cell.bad b { color: #c0353a; }

/* 日历「这些都是推算的计划」那句提示 */
.cal-plan { line-height: 1.5; }

/* 掌握分布：环形图 + 右侧图例 */
.donut-wrap {
  display: flex;
  align-items: center;
  gap: 14px;
}
.donut { flex: 0 0 124px; }
.donut-lg { flex: 1 1 auto; min-width: 0; }
.lg-row {
  display: flex;
  align-items: center;
  gap: 7px;
  font-size: 13px;
  padding: 3px 0;
}
.lg-row i {
  width: 10px;
  height: 10px;
  border-radius: 3px;
  flex: 0 0 auto;
}
.lg-row i.hollow {
  background: transparent;
  border: 1.5px solid var(--muted);
  border-radius: 999px;
}
.lg-row .lg-nm { color: var(--muted); flex: 1 1 auto; }
.lg-row b { font-weight: 600; }
.lg-row em { font-style: normal; color: var(--muted); font-size: 12px; min-width: 34px; text-align: right; }
.lg-row.ever { border-top: 1px dashed var(--border); margin-top: 4px; padding-top: 6px; }

/* 各卡组：横向堆叠条 */
.stk {
  display: flex;
  height: 12px;
  border-radius: 999px;
  overflow: hidden;
  background: #f0f1f3;
  margin: 4px 0 5px;
}
.stk i { display: block; height: 100%; }
.dk-row { margin-bottom: 14px; }
.dk-row:last-child { margin-bottom: 0; }
.dk-top {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 10px;
  font-size: 13.5px;
}
.dk-top .dk-nm { font-weight: 500; }
.dk-top b { font-weight: 600; }
.dk-meta { font-size: 11.5px; color: var(--muted); }
.dk-meta b { color: var(--text); font-weight: 600; }

/* 近 14 天：柱状图 */
.hist-lg {
  display: flex;
  gap: 14px;
  font-size: 11.5px;
  color: var(--muted);
  margin-bottom: 6px;
}
.hist-lg span { display: inline-flex; align-items: center; gap: 4px; }
.hist-lg i { width: 9px; height: 9px; border-radius: 2px; display: inline-block; }
.hist { width: 100%; height: auto; display: block; }
.sum {
  font-size: 13px;
  color: var(--muted);
  margin-bottom: 6px;
}
.sum b { color: var(--text); font-weight: 600; }

/* ---------- 复习前快速过一遍 ---------- */
.prev-panel { padding: 0; overflow: hidden; }
.prev-toggle {
  display: block;
  width: 100%;
  border: 0;
  background: transparent;
  font-size: 14.5px;
  font-weight: 500;
  color: var(--text);
  text-align: left;
  padding: 13px 15px;
  cursor: pointer;
}
.prev-list { max-height: 340px; overflow-y: auto; border-top: 1px solid var(--border); }
.prev-row {
  display: flex;
  align-items: baseline;
  gap: 8px;
  padding: 7px 15px;
  border-bottom: 1px solid var(--border);
  font-size: 14px;
}
.prev-row:last-child { border-bottom: 0; }
.prev-row .n { flex: 0 0 22px; color: var(--muted); font-size: 12px; }
.prev-row .w { font-weight: 600; white-space: nowrap; }
.prev-row .g {
  flex: 1;
  color: var(--muted);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.prev-row .tag-new {
  flex: 0 0 auto;
  font-style: normal;
  font-size: 10.5px;
  color: var(--primary);
  border: 1px solid var(--primary);
  border-radius: 999px;
  padding: 0 6px;
}

/* ---------- 弹窗输入框 / 登录页新建 ---------- */
.pf-input {
  width: 100%;
  box-sizing: border-box;
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 10px 12px;
  font-size: 15px;
  margin: 10px 0 4px;
}
.login-new {
  display: block;
  width: 100%;
  margin-top: 12px;
  border: 1.5px dashed var(--border);
  background: transparent;
  color: var(--muted);
  border-radius: 12px;
  padding: 10px;
  font-size: 14px;
  cursor: pointer;
}
.login-new:hover { color: var(--primary); border-color: var(--primary); }
.login-newform {
  margin-top: 12px;
  border: 1px solid var(--border);
  border-radius: 12px;
  padding: 12px;
}
.login-newform input {
  width: 100%;
  box-sizing: border-box;
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 10px 12px;
  font-size: 15px;
  margin-bottom: 10px;
}
.login-newform .btn-row { margin: 0; }

/* ---------------- 排行榜 ---------------- */
.lb-btn { margin-left: 6px; }
.podium { display: flex; align-items: flex-end; justify-content: center; gap: 8px; margin: 18px 0 12px; }
.pod {
  flex: 1; max-width: 33%; text-align: center;
  background: #fff; border: 1px solid var(--border); border-radius: 12px;
  padding: 10px 4px 8px; position: relative;
  display: flex; flex-direction: column; align-items: center; justify-content: flex-end;
}
.pod1 { min-height: 166px; border-color: #f6c343; box-shadow: 0 2px 0 #f6c343 inset; }
.pod2 { min-height: 154px; border-color: #cfd6dd; }
.pod3 { min-height: 142px; border-color: #e0a06a; }
.pod-medal { font-size: 26px; line-height: 1; margin-bottom: 6px; }
.pod-av { display: flex; justify-content: center; }
.pod-av img { width: 40px; height: 40px; border-radius: 50%; object-fit: cover; }
.pod-av { font-size: 30px; }
.pod-name { font-weight: 600; margin-top: 6px; font-size: 14px; }
.pod-score { color: var(--muted); font-size: 12px; }
.lb-mine { text-align: center; margin: 6px 0 10px; font-size: 14px; }
.lb-mine b { color: var(--primary); }
.lb-all { margin-top: 14px; border-top: 1px solid var(--border); padding-top: 10px; }
.lb-all-title { font-size: 12px; color: var(--muted); margin-bottom: 6px; }
.lb-row { display: flex; align-items: center; gap: 10px; padding: 6px 4px; border-radius: 8px; }
.lb-row.me { background: var(--primary-soft); }
.lb-rank { width: 22px; text-align: center; color: var(--muted); font-weight: 600; }
.lb-av img { width: 30px; height: 30px; border-radius: 50%; object-fit: cover; }
.lb-av { font-size: 22px; }
.lb-nm { flex: 1; font-weight: 500; }
.lb-sc { color: var(--muted); font-size: 13px; }

/* ---------- 化学速查图鉴 ----------
   移动优先：竖屏单列、chip 横向可滑（8 个分类一行放不下，横滑比换行省高度）；
   平板/宽屏自动两列。色卡是 SVG，用 object-fit: contain 保持 4:3 不变形。 */
/* 化学复习入口条（2026-10-19）：化学是独立学科域，不进英语每日队列，
   所以入口要显眼、还要直接说清"还有多少张能练"，不用孩子自己猜。 */
.chem-review {
  display: flex;
  align-items: center;
  gap: 10px;
  margin: 2px 0 10px;
  padding: 11px 12px;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--primary-soft);
}
.cr-ico { font-size: 20px; line-height: 1; }
.cr-txt {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.cr-txt b { font-size: 14px; }
.cr-txt span { font-size: 12px; color: var(--muted); line-height: 1.45; }
.chem-review .btn { flex: 0 0 auto; }

.chem-search input {
  width: 100%;
  padding: 12px 14px;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface);
  color: var(--text);
  font-size: 15px;
  outline: none;
}
.chem-search input:focus { border-color: var(--primary); }
.chem-search input::placeholder { color: var(--muted); }

.chem-chips {
  display: flex;
  gap: 8px;
  overflow-x: auto;
  padding: 10px 0 8px;
  scrollbar-width: none;
}
.chem-chips::-webkit-scrollbar { display: none; }
.chem-chips.sub { padding-top: 0; border-top: 1px solid var(--border); }

.chem-chip {
  flex: 0 0 auto;
  padding: 7px 14px;
  border: 1px solid var(--border);
  border-radius: 999px;
  background: var(--surface);
  color: var(--text);
  font-size: 14px;
  white-space: nowrap;
  line-height: 1.2;
}
.chem-chip.on { background: var(--primary); border-color: var(--primary); color: #fff; }
.chem-chip.sm { padding: 5px 11px; font-size: 13px; color: var(--muted); }
.chem-chip.sm.on { color: #fff; }

.chem-count { font-size: 12px; color: var(--muted); margin: 2px 2px 8px; }

.chem-list { display: flex; flex-direction: column; gap: 10px; }
@media (min-width: 620px) {
  .chem-list { display: grid; grid-template-columns: 1fr 1fr; }
}

.chem-row {
  display: flex;
  gap: 12px;
  align-items: center;
  padding: 10px 12px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
}
.chem-row:active { background: var(--primary-soft); }
.chem-thumb {
  width: 80px;
  height: 60px;
  flex: 0 0 auto;
  object-fit: contain;
  border-radius: 8px;
  background: #fafbfc;
}
.chem-body { min-width: 0; }
.chem-nm {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 8px;
  font-size: 15px;
  font-weight: 600;
}
.chem-fm { font-size: 13px; font-weight: 400; color: var(--muted); }
.chem-hot {
  font-size: 11px;
  font-weight: 400;
  color: var(--hard);
  border: 1px solid currentColor;
  border-radius: 6px;
  padding: 0 4px;
  line-height: 1.5;
}
.chem-meta {
  margin-top: 3px;
  font-size: 12.5px;
  color: var(--muted);
  line-height: 1.5;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.chem-big { display: block; width: 200px; max-width: 62%; margin: 4px auto 12px; }
.chem-tags { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 10px; }
.chem-tag {
  font-size: 12px;
  padding: 2px 9px;
  border-radius: 999px;
  background: var(--primary-soft);
  color: var(--primary);
}
.chem-f {
  display: flex;
  gap: 10px;
  padding: 7px 0;
  border-top: 1px solid var(--border);
  font-size: 14px;
  line-height: 1.6;
}
.chem-f > span { flex: 0 0 40px; color: var(--muted); font-size: 13px; }
.chem-f > div { flex: 1; min-width: 0; }

/* ---------- 物质总览大表 ----------
   手机上 6 列放不下，靠横向滚动；表头 sticky 住，滑到右边也知道在看哪一列。 */
.dialog.wide { max-width: 96vw; width: 96vw; }
.chem-table-wrap {
  overflow: auto;
  max-height: 62vh;
  -webkit-overflow-scrolling: touch;
  border: 1px solid var(--border);
  border-radius: 10px;
}
.chem-table {
  border-collapse: collapse;
  width: 100%;
  font-size: 12.5px;
  line-height: 1.55;
}
.chem-table th,
.chem-table td {
  border-bottom: 1px solid var(--border);
  padding: 8px 8px;
  text-align: left;
  vertical-align: top;
  min-width: 100px;
}
.chem-table th {
  position: sticky;
  top: 0;
  z-index: 1;
  background: var(--primary-soft);
  color: var(--primary);
  font-weight: 600;
  white-space: nowrap;
}
.chem-table td.nm { font-weight: 600; white-space: nowrap; }
.chem-table td.fm { color: var(--muted); white-space: nowrap; }
.chem-table tr:nth-child(even) td { background: rgba(0, 0, 0, .015); }

/* ---------- 元素表（短式周期表 + 金属活动性顺序） ----------
   8 列是有意的：ⅠA~ⅦA + 0 族，手机上（360~400px）正好一行放得下。
   真按长式 18 列摆，孩子得左右滑半天才看到铁，位置感反而没了。
   副族那几个（Fe Cu Zn Ag I Ba Hg Au…）在短式表里没格子，单独一组补上。 */
.chem-tools { display: flex; gap: 8px; margin: 10px 0 2px; }
.chem-tools .btn { flex: 1; font-size: 13.5px; padding: 9px 6px; }

.sec-title { font-size: 12px; color: var(--muted); margin: 16px 0 8px; }

.pt-grid { display: flex; flex-direction: column; gap: 5px; }
.pt-row,
.pt-head { display: grid; grid-template-columns: 16px repeat(8, 1fr); gap: 5px; }
.pt-head { margin-bottom: 1px; }
.pt-col { font-size: 9px; color: var(--muted); text-align: center; line-height: 1; }
.pt-period { font-size: 10px; color: var(--muted); align-self: center; }

.pt-cell {
  height: 48px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 1px;
  overflow: hidden;
  border: 1px solid transparent;
  border-radius: 8px;
}
.pt-cell.blank { border: 1px dashed rgba(128, 128, 128, .16); }
.pt-sym { font-size: 15px; font-weight: 700; line-height: 1.05; }
.pt-nm { font-size: 9px; color: var(--muted); line-height: 1.1; }

/* 三类底色：半透明叠在 --surface 上，浅色/深色主题都不刺眼 */
.k-metal    { background: rgba(198, 123, 92, .13); border-color: rgba(198, 123, 92, .30); }
.k-nonmetal { background: rgba(74, 144, 196, .13); border-color: rgba(74, 144, 196, .30); }
.k-rare     { background: rgba(142, 120, 196, .13); border-color: rgba(142, 120, 196, .30); }

.pt-legend-row { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin: 4px 0 10px; }
.pt-legend { font-size: 11px; padding: 3px 9px; border-radius: 999px; border: 1px solid transparent; }
.pt-hint { font-size: 11px; color: var(--muted); }

/* 金属活动性顺序：整条链一屏看完比横滑更有用 —— 记住的是「谁在谁前面」 */
.act-wrap { margin: 12px 0 6px; }
.act-title {
  display: flex; justify-content: space-between; align-items: baseline;
  font-size: 12.5px; color: var(--text); margin-bottom: 7px;
}
.act-title > span { font-size: 11px; color: var(--muted); }
.act-bar { display: flex; align-items: center; flex-wrap: wrap; gap: 4px; }
.act-cell {
  min-width: 30px; text-align: center; padding: 6px 6px; border-radius: 8px;
  background: var(--primary-soft); color: var(--primary);
  font-weight: 700; font-size: 13px; line-height: 1.1;
}
.act-cell.h { background: transparent; border: 1px dashed var(--muted); color: var(--muted); }
.act-sep { color: var(--muted); font-size: 11px; }
.act-note { font-size: 11.5px; color: var(--muted); margin-top: 7px; line-height: 1.5; }

.elem-badge {
  width: 52px; height: 52px; flex: 0 0 auto;
  display: flex; align-items: center; justify-content: center;
  border: 1px solid transparent; border-radius: 10px;
  font-weight: 700; font-size: 19px;
}
.elem-badge.big { width: 68px; height: 68px; font-size: 26px; }
.elem-hero { display: flex; gap: 14px; align-items: center; margin: 8px 0 12px; }
.elem-hero-info { font-size: 13px; line-height: 1.8; color: var(--muted); }
.elem-mass b { color: var(--text); font-size: 14px; }
.elem-list { display: flex; flex-direction: column; gap: 10px; }

/* 副族那一组最多 5 个（第 6 周期 Ba Pt Au Hg Pb），所以用 5 列而不是 8 列，
   单元格宽一些，符号不至于挤成一团 */
.pt-side-row { grid-template-columns: 16px repeat(5, 1fr); }

/* ---------------------------------------------------------------- 化学学习线路
   2026-10-20 第二十轮。线路条是「十单元 5×2 网格」：手机 430 宽放得下，
   一屏就能看到全部十个单元和各自进度，比横向滚动条更好用。 */

.chem-line {
  margin: 10px 12px 2px;
  padding: 10px 12px 8px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
}
.chem-line.err { font-size: 12.5px; color: var(--muted); }
.cl-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 10px;
  margin-bottom: 8px;
  overflow: hidden;
}
.cl-head b { flex: 0 0 auto; font-size: 13.5px; }
.cl-head span {
  flex: 1 1 auto;
  min-width: 0;
  font-size: 11.5px;
  color: var(--muted);
  text-align: right;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.cl-grid {
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  gap: 6px;
}
/* ⚠️ 2026-10-20 踩过的坑，别再走回头路：
   最初做成「横向滚动条」（flex + overflow-x:auto + 绝对定位进度条），
   布局坐标全对（格子 y=155、文字 Range y=163 都在框内），但 headless 下
   格子里的文字不绘制、底部 3px 进度条被画成大块灰矩形。
   加 translateZ(0) 提合成层、改绝对定位、改直接文本节点，五种方案都没治好。
   最后换成 5×2 网格（不滚动、不合成层）一次正常。
   所以：这里不要加 overflow / transform / 绝对定位的兄弟元素。 */
.cl-seg {
  position: relative;
  height: 44px;
  padding: 0 2px;
  background: #fafbfc;
  border: 1px solid var(--border);
  border-radius: 10px;
  font-size: 12px;
  line-height: 36px;
  text-align: center;
  white-space: nowrap;
  overflow: hidden;
  color: var(--text);
  cursor: pointer;
  user-select: none;
}
.cl-bar {
  position: absolute;
  left: 8px;
  right: 8px;
  bottom: 7px;
  height: 3px;
  background: #eceef1;
  border-radius: 2px;
  overflow: hidden;
}
.cl-bar i { display: block; height: 100%; background: var(--primary); }
.cl-bar.zero i { background: transparent; }
/* ☠️ 这里千万别再给子元素加 .empty 类：style.css:206 有一条全局
   `.empty { padding: 40px 0 }`（空状态占位），会把这个 3px 的进度条
   撑成 80px 高的灰块，正好盖住格子上的文字。2026-10-20 为此排查了半天。
   同理，给这里的元素起类名前先 grep 一下有没有同名全局规则。 */
.cl-seg.cur { border-color: var(--primary); background: var(--primary-soft); color: var(--primary); }
.cl-seg.done .cl-bar i { background: #1d9e75; }
.cl-seg.lock { opacity: .5; }

/* 单元页 */
.unit-empty {
  margin: 16px 12px;
  padding: 18px 14px;
  background: var(--surface);
  border: 1px dashed var(--border);
  border-radius: var(--radius);
  font-size: 13px;
  line-height: 1.65;
  color: var(--muted);
  text-align: center;
}
.unit-hero {
  margin: 10px 12px 0;
  padding: 12px 14px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
}
.uh-top { font-size: 13.5px; line-height: 1.55; }
.uh-bar {
  height: 6px;
  margin: 10px 0 6px;
  background: #eceef1;
  border-radius: 3px;
  overflow: hidden;
}
.uh-bar i { display: block; height: 100%; background: var(--primary); }
.uh-meta { font-size: 11.5px; color: var(--muted); }
/* 通关徽章（P3-①）：跟进度条同一层，不抢 .uh-top 的位置 */
.uh-clear {
  display: inline-block;
  margin-top: 8px;
  padding: 3px 10px;
  font-size: 12px;
  font-weight: 700;
  color: #0f7a55;
  background: #e3f7ef;
  border: 1px solid #9ad9c1;
  border-radius: 999px;
}

/* 通关小结（P3-②）：已通关单元页里的一块回顾卡。
   不铺绿色 —— 上面已经有徽章和庆祝条，再花就更吵。 */
.uc-box {
  padding: 12px 14px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  font-size: 13px;
}
.uc-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 8px;
}
.uc-head b { font-size: 13.5px; font-weight: 600; }
.uc-head span {
  font-size: 12px;
  font-weight: 700;
  color: #0f7a55;
  font-variant-numeric: tabular-nums;
}
.uc-tip { margin-top: 9px; font-size: 12px; color: var(--muted); }
.uc-weak { display: flex; flex-direction: column; gap: 6px; margin-top: 6px; }
/* 米黄 = 提醒色，和「已完成」的绿区分开 */
.uc-card {
  padding: 8px 10px;
  background: #fbf7ee;
  border: 1px solid #eee0c6;
  border-radius: 8px;
}
.uc-card em {
  display: block;
  font-style: normal;
  font-size: 11px;
  color: #96702f;
  margin-bottom: 3px;
}
/* 方程式题的题干动辄两行，夹到 3 行免得一张卡吃掉半屏 */
.uc-card p {
  margin: 0;
  font-size: 13px;
  line-height: 1.55;
  color: var(--text);
  display: -webkit-box;
  -webkit-line-clamp: 3;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

/* 通关庆祝条：刻意不做全屏弹层 —— 盖章与收尾页已经各占一个全屏层，再叠一个会抢屏。
   它是顶部浮条，4.5s 后由 JS 自己摘掉，不挡任何按钮。 */
.ucc-banner {
  position: fixed;
  left: 12px;
  right: 12px;
  bottom: 64px;
  z-index: 60;
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 11px 14px;
  background: #fff8e1;
  border: 1px solid #f0c36d;
  border-radius: var(--radius);
  box-shadow: 0 6px 18px rgba(0, 0, 0, .12);
  animation: ucc-in .28s ease-out;
}
.ucc-banner b { font-size: 14px; color: #8a5a00; }
.ucc-banner span { font-size: 12px; color: #a07400; }
@keyframes ucc-in {
  from { opacity: 0; transform: translateY(10px); }
  to { opacity: 1; transform: none; }
}

.unit-lock {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  margin: 10px 12px 0;
  padding: 9px 12px;
  background: #fff8e8;
  border: 1px solid #f3e2b8;
  border-radius: var(--radius);
  font-size: 12.5px;
  color: #8a6a1f;
}

/* 课本目录：课题 + 起始页。页码帮孩子回书里翻，九年级查不到页码就只显示课题 */
.unit-toc {
  margin: 10px 12px 0;
  padding: 8px 12px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
}
.ut-row {
  display: flex;
  align-items: baseline;
  gap: 8px;
  padding: 4px 0;
  font-size: 12.5px;
  line-height: 1.5;
}
.ut-row + .ut-row { border-top: 1px dashed var(--border); }
.ut-row b { flex: 0 0 auto; font-weight: 600; color: var(--muted); }
.ut-row span { flex: 1 1 auto; min-width: 0; }
.ut-row em {
  flex: 0 0 auto;
  font-style: normal;
  font-size: 11.5px;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
}

.unit-sec { margin: 14px 12px 0; }.unit-sec h3 {
  display: flex;
  align-items: baseline;
  gap: 8px;
  margin: 0 0 8px;
  font-size: 13.5px;
  font-weight: 600;
}
.unit-sec h3 em {
  font-style: normal;
  font-size: 11.5px;
  font-weight: 400;
  color: var(--muted);
}
.unit-goals {
  margin: 0;
  padding: 12px 14px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  font-size: 13px;
  line-height: 1.7;
  list-style: none;
  counter-reset: ug;
}
/* 用 ::before 计数器，不用原生 ol 标记。
   原生标记是 outside 定位，编号到两位数（10. 11. 12.）时它会被挤到单独一行，
   内容整块下沉 —— 实测 U08 的 12 条目标里后三条全错位。计数器没有这个问题。 */
.unit-goals li {
  position: relative;
  padding-left: 24px;
  margin: 0 0 6px;
  counter-increment: ug;
}
.unit-goals li::before {
  content: counter(ug) ".";
  position: absolute;
  left: 0;
  top: 0;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
}
.unit-goals li:last-child { margin-bottom: 0; }

.unit-rx, .unit-kb {
  padding: 10px 12px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  margin-bottom: 8px;
  font-size: 13.5px;
  line-height: 1.6;
}
.unit-rx span { display: block; font-weight: 500; }
/* 方程式卡片：类型徽标 + 式子 + 现象 + 易错点四层。
   式子里的条件写在箭头上（4P + 5O₂ —点燃→ 2P₂O₅），所以不用再单列「条件」行。 */
.ur-eq { display: flex; align-items: baseline; gap: 6px; }
.ur-eq span { flex: 1 1 auto; min-width: 0; font-weight: 500; }
.ur-rt {
  flex: 0 0 auto;
  font-size: 11px;
  font-weight: 500;
  padding: 1px 5px;
  border-radius: 4px;
  background: var(--primary-soft);
  color: var(--primary);
}
.ur-ph { margin-top: 5px; font-size: 12px; line-height: 1.55; color: var(--muted); }
.ur-note { margin-top: 4px; font-size: 12px; line-height: 1.55; color: #8a6a1f; }
.ur-note i {
  font-style: normal;
  font-size: 10.5px;
  padding: 0 4px;
  margin-right: 4px;
  border: 1px solid #f3e2b8;
  border-radius: 3px;
  background: #fff8e8;
}
.unit-rx em { display: block; margin-top: 3px; font-style: normal; font-size: 12px; color: var(--muted); }
.unit-kb b { display: block; font-weight: 500; margin-bottom: 3px; }
/* 知识卡正文：口诀要读得清，所以不用 muted 灰；换行要保留（body 里的空行是分段），
   所以 pre-wrap 而不是普通的 white-space。 */
.unit-kb span {
  display: block;
  font-size: 12.5px;
  line-height: 1.75;
  color: #3d434b;
  white-space: pre-wrap;
}

.unit-foot { margin: 16px 12px 24px; }
.unit-foot .btn { width: 100%; }
/* 按钮里的张数：压小、不加粗，别抢「练这一关」这四个字 */
.unit-foot .btn em { font-style: normal; opacity: .75; font-size: 12px; margin-left: 4px; }

/* ---------- 历史（2026-10-20 试点） ---------- */
.hist-bar {
  height: 8px;
  border-radius: 999px;
  background: var(--border);
  overflow: hidden;
  margin: 10px 0 6px;
}
.hist-bar i { display: block; height: 100%; background: var(--hard); border-radius: 999px; }
.hist-tl { list-style: none; margin: 8px 0 2px; padding: 0 0 0 18px; position: relative; }
.hist-tl::before { content: ""; position: absolute; left: 5px; top: 6px; bottom: 6px; width: 2px; background: var(--border); border-radius: 2px; }
.hist-tl-row { position: relative; padding: 0 0 14px 0; }
.hist-tl-row:last-child { padding-bottom: 0; }
.hist-tl-dot { position: absolute; left: -17px; top: 6px; width: 9px; height: 9px; border-radius: 50%; background: var(--hard); border: 2px solid var(--surface); box-sizing: content-box; }
.hist-tl-body { display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap; }
.hist-tl-body b { font-size: 14px; color: var(--text); }
.hist-tl-body em { font-style: normal; font-size: 12px; color: var(--muted); }
.hist-home { border-left: 3px solid var(--hard); }
.hist-home-top { display: flex; align-items: center; justify-content: space-between; gap: 10px; margin-bottom: 4px; }
.hist-book { margin: 18px 2px 8px; font-size: 13px; font-weight: 600; color: var(--muted); letter-spacing: .04em; }
.hist-unit-card { display: flex; gap: 12px; align-items: flex-start; }
.hist-cover { width: 104px; height: 78px; border-radius: 10px; object-fit: cover; flex: 0 0 auto; }
.hist-unit-body { min-width: 0; flex: 1; }
.hist-hero { width: 100%; max-height: 220px; object-fit: cover; border-radius: 14px; display: block; margin: 0 0 14px; }
.hist-item { display: flex; gap: 10px; align-items: flex-start; }
.hist-item-img { width: 76px; height: 76px; border-radius: 8px; object-fit: cover; flex: 0 0 auto; }
.hist-item-body { min-width: 0; flex: 1; }

/* ---------- 家长视角（管理员只读总览） ---------- */
/* 纯展示：整页没有一个能改数据的控件，样式也只负责把数字排清楚。 */
.pf-right { display: flex; align-items: center; gap: 8px; margin-left: auto; min-width: 0; }
/* 家长入口：一个窄图标按钮，不跟「统计 / 排行榜」抢标题行的宽度 */
.pf-parent {
  flex: 0 0 auto; width: 30px; height: 26px; padding: 0;
  display: inline-flex; align-items: center; justify-content: center;
  font-size: 14px; line-height: 1;
  border: 1px solid var(--border); border-radius: 999px;
  background: var(--surface); color: var(--text);
}
.pf-parent:active { filter: brightness(.95); }
.p-note { font-size: 12.5px; color: var(--muted); margin: 0 2px 10px; }
.p-tip { color: var(--muted); font-size: 14px; }
.p-tip.err { color: var(--again); }

.p-card { padding: 14px 14px 12px; }
.p-head { display: flex; align-items: center; gap: 10px; margin-bottom: 10px; }
.p-av {
  width: 42px; height: 42px; border-radius: 50%; object-fit: cover;
  flex: 0 0 auto; background: var(--bg);
}
.p-av.ph {
  display: flex; align-items: center; justify-content: center;
  font-size: 18px; font-weight: 600; color: var(--muted);
}
.p-who { flex: 1; min-width: 0; }
.p-name {
  font-size: 15.5px; font-weight: 600; display: flex; align-items: center;
  gap: 8px; flex-wrap: wrap;
}
.p-streak {
  font-size: 11.5px; font-weight: 500; color: var(--hard);
  background: #fff7e8; border-radius: 999px; padding: 1px 7px;
}
.p-today { font-size: 12.5px; color: var(--muted); margin-top: 1px; }
.p-today b { color: var(--text); font-weight: 600; }
.p-stamp {
  flex: 0 0 auto; font-size: 11.5px; color: var(--muted);
  border: 1px solid var(--border); border-radius: 999px; padding: 2px 9px;
  white-space: nowrap;
}
.p-stamp.on { color: var(--good); border-color: #c8ebd9; background: #f0fbf5; }

.p-rows { margin: 0 0 10px; }
.p-row {
  display: flex; align-items: baseline; gap: 10px;
  padding: 4px 0; border-top: 1px solid var(--bg); font-size: 13.5px;
}
.p-row:first-child { border-top: none; }
.p-k { flex: 0 0 52px; color: var(--muted); font-size: 12.5px; }
.p-v { flex: 1; min-width: 0; color: var(--text); }
.p-v b { font-weight: 600; }
.p-dim { color: var(--muted); font-size: 12px; }

/* ---------- 事实短文（L2 分级英语阅读，只读） ----------
   四色 = 原文 docx 里标词的颜色（红高频 / 蓝中频 / 绿低频 / 紫词组）。
   正文里只存字符偏移，音标和释义是**渲染时**插进去的 —— 所以加不加、怎么加都不用重新导库。 */
.fact-list { display: flex; flex-direction: column; gap: 10px; }
.fact-item {
  display: flex; gap: 12px; align-items: flex-start;
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius); padding: 10px 12px;
}
.fact-thumb {
  width: 92px; height: 62px; border-radius: 8px; object-fit: cover;
  flex: 0 0 auto; background: var(--bg);
}
.fact-item-body { min-width: 0; flex: 1; }
.fact-t { font-size: 14.5px; font-weight: 600; }
.fact-te {
  font-size: 12.5px; color: var(--muted); margin-top: 1px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.fact-meta { font-size: 11.5px; color: var(--muted); margin-top: 4px; }

.fact-card { padding: 12px 14px; }
.fact-hero {
  width: 100%; display: block; border-radius: 10px; margin-bottom: 10px;
  max-height: 260px; object-fit: cover; background: var(--bg);
}
.fact-en { font-size: 17px; font-weight: 600; }
.fact-zh { font-size: 13.5px; color: var(--muted); margin-top: 2px; }

.fx-pills { display: flex; flex-wrap: wrap; gap: 6px; margin: 10px 0 4px; }
.fx-pill {
  font-size: 13px; padding: 3px 10px; border-radius: 999px;
  border: 1px solid var(--border); background: var(--bg);
}
.fx-pill.ghost { color: var(--muted); border-style: dashed; }

/* 正文：默认纯英文，切到「+音标 / +音标释义」时用绝对定位把音标顶上去、释义压下去，
   词本身还留在基线上（不然 60 个标注会把整段撑高一大截、读起来散架）。 */
.fx-p { font-size: 16px; line-height: 1.9; margin: 0 0 8px; }
.fx-p:last-child { margin-bottom: 0; }
.fx-p.ann { line-height: 3.1; }
.fx-zh {
  display: block; font-size: 13.5px; line-height: 1.7;
  color: var(--muted); margin-top: -4px;
}
.fx { font-style: normal; white-space: nowrap; border-radius: 3px; padding: 0 1px; }
.fx[data-fx] { cursor: pointer; }
.fx-hi { color: #d0356b; }
.fx-mid { color: #2f6fed; }
.fx-lo { color: #1f9a5b; }
.fx-phrase { color: #8a4fd8; }
.fx.ann { position: relative; }
.fx-up, .fx-dn {
  position: absolute; left: 0; right: 0; text-align: center;
  font-size: 10.5px; line-height: 1.3; font-weight: 400; font-style: normal;
  text-decoration: none; color: var(--muted); pointer-events: none;
}
.fx-up { bottom: 100%; }
.fx-dn { top: 100%; }

.fx-list { display: flex; flex-direction: column; }
.fx-row {
  display: flex; align-items: flex-start; gap: 10px;
  padding: 8px 2px; border-top: 1px solid var(--bg);
}
.fx-row:first-child { border-top: none; }
.fx-row-l { flex: 0 0 44%; min-width: 0; display: flex; flex-direction: column; }
.fx-row-l b { font-weight: 600; font-size: 14.5px; }
.fx-ph { font-size: 11.5px; color: var(--muted); }
.fx-row-r { flex: 1; min-width: 0; display: flex; align-items: baseline; gap: 8px; }
.fx-row-r span { font-size: 13.5px; flex: 1; }

.fx-tag, em[class^='fx-lv-'] {
  font-style: normal; font-size: 11.5px; padding: 2px 8px; border-radius: 999px;
  border: 1px solid var(--border); color: var(--muted); background: var(--bg);
  white-space: nowrap; flex: 0 0 auto;
}
.fx-tag.ph { color: #8a4fd8; border-color: #e3d4f7; background: #f6f1fd; }
.fx-lv-zk { color: var(--good); border-color: #c8ebd9; background: #f0fbf5; }
.fx-lv-gk { color: var(--hard); border-color: #f6e2bd; background: #fff8ec; }
.fx-lv-none { color: var(--muted); }

.fx-ipa-big { font-size: 15px; color: var(--muted); margin-bottom: 8px; }
.fx-tags { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 10px; }
.fx-sec { margin-bottom: 10px; }
.fx-lab { display: block; font-size: 11.5px; color: var(--muted); margin-bottom: 2px; }
.fx-sense { font-size: 14px; }
.fx-sense.big { font-size: 16px; font-weight: 600; }
.fact-read .chem-chips { padding-bottom: 2px; }
.fact-modes { margin-top: 4px; }

/* 「听全文」：整篇朗读按钮。播放中靠 .on 变主色（.chem-chip.on 已有），
   这里只加字重 + 一呼一吸的呼吸感，让孩子知道"它正在念"。 */
.fact-audio { font-weight: 600; letter-spacing: .2px; }
.fact-audio.on { animation: faBreath 1.8s ease-in-out infinite; }
@keyframes faBreath { 0%, 100% { opacity: 1; } 50% { opacity: .68; } }
@media (prefers-reduced-motion: reduce) { .fact-audio.on { animation: none; } }

/* ---- 跟读高亮：正在念的那一句 ----
   span 是行内的，背景没法加 padding，用同色 box-shadow 往外撑一圈达到留白效果。 */
.fx-s { border-radius: 3px; }
.fx-s.cur {
  background: #ffe9a8;
  box-shadow: 0 0 0 2px #ffe9a8;
  transition: background .18s ease;
}
.fx-p.ann .fx-s.cur { box-shadow: 0 0 0 2px #ffe9a8; }

/* ---- 悬浮小唱片 ----
   文章一屏读不完，页内的暂停滚上去就够不着了。这个挂在边上、能上下拖、
   松手贴最近的一边，位置每个孩子各记各的。外圈是进度，转起来说明在念。 */
.fa-fab {
  position: fixed;
  display: none;
  align-items: center;
  justify-content: center;
  width: 58px; height: 58px;
  border-radius: 50%;
  background: conic-gradient(var(--primary) calc(var(--p, 0) * 1%), rgba(120, 120, 130, .22) 0);
  box-shadow: 0 4px 16px rgba(0, 0, 0, .22);
  z-index: 70;
  touch-action: none;
  -webkit-user-select: none; user-select: none;
  cursor: pointer;
}
.fa-fab.side-right { right: 12px; }
.fa-fab.side-left { left: 12px; }
.fa-fab.drag { box-shadow: 0 8px 24px rgba(0, 0, 0, .3); transform: scale(1.06); }
.fa-disc {
  display: flex; align-items: center; justify-content: center;
  width: 46px; height: 46px; border-radius: 50%;
  color: #fff; font-size: 15px; line-height: 1;
  background:
    radial-gradient(circle at 50% 50%, #f2f2f5 0 4.5px, #2f2f38 5px 8px, #26262e 8px 100%);
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, .14);
}
.fa-fab.playing .fa-disc { animation: faSpin 3.6s linear infinite; }
.fa-fab.drag .fa-disc { animation-play-state: paused; }
@keyframes faSpin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) { .fa-fab.playing .fa-disc { animation: none; } }

/* 短文消消乐的网格：词比复习那版短，用 3 列（复习那版是 2 列），
   20 张牌也能一眼看完大半，不用滚半天。 */
.fact-grid { grid-template-columns: repeat(auto-fill, minmax(112px, 1fr)); }

/* 消消乐「本轮：高频+中频」那行说明：比普通提示再淡一点，别抢牌的注意力 */
.fact-tier { opacity: .85; margin-top: -6px; }

/* ---------- 伙伴页二级页（2026-10-26 信息架构整理）---------- */
/* 二级页顶端：返回箭头 + 标题 + 进度（进度靠右）。
   topbar 默认 baseline + space-between，这里改成居中对齐，箭头才不会比标题低半行。 */
.sub-top { align-items: center; justify-content: flex-start; gap: 10px; flex-wrap: nowrap; }
.sub-top .back-btn {
  border: 0; background: none; padding: 0 4px 2px; margin: 0;
  font-size: 26px; line-height: 1; color: var(--text); cursor: pointer;
  font-family: inherit;
}
.sub-top .sub { margin-left: auto; white-space: nowrap; }

/* 玩法入口网格：2 列，每格「图标 / 名字 / 进度 / 一句话」。
   折叠区拆走后，进度必须在入口上看得见，否则等于把东西藏得更深。 */
.pt-menu { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; margin: 4px 0 14px; }
.pm-card {
  display: flex; flex-direction: column; align-items: flex-start; gap: 1px;
  padding: 11px 12px 10px; border: 1px solid var(--border);
  border-radius: 12px; background: var(--surface);
  text-align: left; font-family: inherit; cursor: pointer;
}
.pm-card:active { background: var(--surface2, rgba(0,0,0,.03)); }
.pm-card .pm-ico { font-size: 20px; line-height: 1.1; margin-bottom: 2px; }
.pm-card b { font-size: 14px; font-weight: 600; color: var(--text); }
.pm-card .pm-prog { font-size: 12px; font-weight: 600; color: var(--good); }
.pm-card .pm-desc { font-size: 11px; color: var(--muted); line-height: 1.35; }

/* ---------- 家长端 日 / 周 / 月报表（2026-10-27）---------- */
.pr-tabs { display: flex; gap: 8px; margin: 4px 0 10px; }
.pr-range { font-size: 12px; color: var(--muted); margin: 0 0 8px; }
.pr-card { margin-bottom: 12px; }
.pr-head { display: flex; align-items: baseline; justify-content: space-between; }
.pr-head b { font-size: 16px; }
/* 一句话结论：家长要判断，不要一堆数。行高压到 1.5 就够，别做成大段落。 */
.pr-verdict { font-size: 13px; line-height: 1.5; margin: 6px 0 10px; }
.pr-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 8px; margin-bottom: 10px; }
.pr-grid > div {
  text-align: center; padding: 6px 2px; border-radius: 8px;
  background: rgba(0, 0, 0, .035);
}
.pr-grid b { display: block; font-size: 17px; line-height: 1.25; }
.pr-grid span { font-size: 11px; color: var(--muted); }
.pr-line { font-size: 12px; line-height: 1.6; margin-top: 6px; color: var(--muted); }
.pr-line b { color: var(--text); }
.pr-line.warn { color: #b4780f; }
.pr-tip { font-size: 11px; }
.pr-unused { font-size: 11px; margin-top: 2px; }
/* 每日条形：纯 CSS 高度表达动作量，不引图表库（手机端 2C2G） */
.pr-bars { display: flex; align-items: flex-end; gap: 3px; height: 38px; margin: 10px 0 2px; }
.pr-bar { flex: 1; display: flex; align-items: flex-end; }
.pr-bar i { display: block; width: 100%; border-radius: 2px; background: #c9d3dd; }
.pr-bar.on i { background: #58b368; }
.pr-bar.zero i { background: #e9edf2; }
.pr-bar-x { display: flex; justify-content: space-between; font-size: 10px; color: var(--muted); }

/* 经验来源 / 战斗明细（2026-10-27） */
.pr-lab { font-size: 12px; font-weight: 600; color: var(--muted); margin: 12px 0 6px; }
.pr-src { display: flex; align-items: center; gap: 8px; font-size: 11px; margin-bottom: 3px; }
.pr-src span { width: 66px; flex: none; color: var(--muted); }
.pr-src i { display: block; height: 8px; border-radius: 2px; background: #7fb3e0; flex: none; max-width: 60%; }
.pr-src b { font-size: 11px; color: var(--text); }
.pr-tb { width: 100%; border-collapse: collapse; font-size: 11px; }
.pr-tb th { text-align: left; font-weight: 500; color: var(--muted); padding: 3px 4px; }
.pr-tb td { padding: 3px 4px; border-top: 1px solid var(--border); }

/* 时段柱状图（2026-10-27）：24 根，看几点在学 */
.ph-wrap { display: flex; align-items: flex-end; gap: 2px; height: 54px; margin: 4px 0 0; }
.ph-col { flex: 1; display: flex; align-items: flex-end; height: 100%; }
.ph-col i { display: block; width: 100%; border-radius: 1px; background: #b9c6d4; }
.ph-col.am i { background: #7fb3e0; }
.ph-col.pm i { background: #9fc98a; }
.ph-col.eve i { background: #7f9ede; }
.ph-col.night i { background: #a9b6c8; }
.ph-col.zero i { background: #e9edf2; }
.ph-x { display: flex; justify-content: space-between; font-size: 9px; color: var(--muted); margin-top: 2px; }

/* 词类型比例条：灰（该练）vs 白（会的） */
.pw-mix { display: flex; height: 10px; border-radius: 3px; overflow: hidden; margin: 4px 0 4px; }
.pw-mix i { display: block; height: 100%; }
.pw-mix i.g { background: #e8a33d; }
.pw-mix i.w { background: #c9d3dd; }

/* 没场景素材的节点（5 只宝主）：野外兜底，别让舞台变纯黑。
   `--hz` 是后端给的地平线（0.30），上半段用与天空同色的淡绿接上，看不出接缝。 */
.story-stage.ss-bare .ss-sky {
  height: 100%;
  background: linear-gradient(180deg, #a9d3ef 0%, #dff0fb 58%, #e9f4cf 100%);
}
.story-stage.ss-bare .ss-ground {
  /* ★ 别用 `--hz` 切上半透明：舞台是 1:1 窗口 + world 5:8 底对齐，
     地平线（0.30）在**被裁掉的那半截**里，可见区域整块都是地面。
     所以这里只做「远处沙土 → 近处草」的纵深，再压一层柔光。 */
  background:
    radial-gradient(85% 38% at 50% 44%, rgba(255, 255, 255, .50), rgba(255, 255, 255, 0) 64%),
    linear-gradient(180deg, #c9ce96 0%, #b7c17e 46%, #9dab6c 70%, #7e8c56 100%);
  background-size: 100% 100%, 100% 100%;
  /* 纯渐变没有纹理，推轨放大只会把整块颜色推糊 ⇒ 兜底场景干脆不缩放，
     让「远→近」的层次一直看得见。有真图之后这条不生效。 */
  transform: none;
}

/* ---------- 火箭队三人组 · 热气球乱入（2026-10-30） ----------
   三块：地图上飞的气球（.rk-craft）、念台词的弹层（.rk-motto）、
   打赢之后被打飞的动画（.rk-blast）。气球是 CSS 画的，人用的是立绘拼图 —— 
   这样气球形状永远干净（生成图里的气球经常歪），而三个人还是原来那三张脸。 */
.rk-craft {
  position: absolute;
  width: 120px;
  margin-left: -60px;              /* 锚点 = 底部中心，和 .map-me 同一套定位方式 */
  z-index: 40;
  pointer-events: none;
  transition: transform 1.5s cubic-bezier(.3, .05, .35, 1);
  will-change: transform;
}
.rk-env {
  position: relative;
  height: 96px;
  border-radius: 50% 50% 44% 44% / 54% 54% 46% 46%;
  background:
    repeating-linear-gradient(90deg, rgba(255,255,255,.18) 0 2px, rgba(0,0,0,0) 2px 22px),
    radial-gradient(circle at 34% 28%, #ff9a86, #e8442f 58%, #a51f18 100%);
  box-shadow: inset -10px -12px 22px rgba(0,0,0,.25);
}
/* 气球正中间那个红底白 R —— 隔着 300px 也能认出是哪伙人 */
.rk-env::after {
  /* ★ 2026-11-01：字母从 `data-emblem` 取，别写死。只有火箭队坐气球，
     但万一以后给别的组织也做了气球，写死 R 就得回来改 CSS。 */
  content: attr(data-emblem);
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font: 800 42px/1 "Segoe UI", "Microsoft YaHei", sans-serif;
  color: #fff3ea;
  text-shadow: 0 2px 6px rgba(0,0,0,.35);
}
/* 三个人站在篮沿上：图往上压进球体，腿被下面的吊篮盖住 */
.rk-crew {
  display: block;
  width: 100px;
  margin: -36px auto 0;
  position: relative;
  z-index: 2;
}
.rk-basket {
  position: relative;
  z-index: 3;
  width: 66px;
  height: 24px;
  margin: -16px auto 0;
  background: linear-gradient(#c08246, #7a4a22);
  border-radius: 2px 2px 7px 7px;
  clip-path: polygon(6% 0, 94% 0, 84% 100%, 16% 100%);
  box-shadow: inset 0 2px 0 rgba(255,255,255,.3);
}
/* ---------- 「冲过来拦路」（2026-11-01 各代反派） ----------
   火箭队坐热气球，别的组织没有气球 ⇒ 他们从**右边冲进画面**，脚下扬一团土。
   ★ 立绘只有一张（组织成员），所以这里没有 .rk-env / .rk-basket，只有 .rk-crew。
   ★ 锚点还是「底部中心」：`margin-top:-146px` 让 150px 高的立绘**脚落在锚点上**，
     和 .map-me（小人的脚）对齐。改宽度时这个数要跟着改（约等于 -(高-4)）。 */
.rk-craft.rk-charge {
  /* ★ 尺寸按**地图小人**定：`.map-me` 是 26px 高，这里 64px ≈ 2.5 倍 ——
     看起来是「一个人站在你面前」，还认得出红黑/蓝白的大色块。
     第一版给了 150px（5.8 倍），像往地图上贴了张立绘，人不像站在地上。 */
  width: 64px;
  margin-left: -32px;
  transition: transform 1.05s cubic-bezier(.2, .75, .3, 1);
  filter: drop-shadow(0 3px 4px rgba(0, 0, 0, .45));
}
/* 立绘是 512×512 方图、脚底贴边 ⇒ margin-top 约等于 -(高-2)，脚才落在锚点上 */
.rk-craft.rk-charge .rk-crew {
  width: 64px;
  margin: -62px auto 0;
}
/* 脚下那团土：只在「刹住」那一下炸开一次，不循环（循环会一直冒烟，像着火） */
.rk-dust {
  position: absolute; left: 50%; bottom: -5px;
  width: 58px; height: 14px; margin-left: -29px;
  border-radius: 50%;
  background: radial-gradient(50% 60% at 50% 70%,
              rgba(214, 196, 166, .85), rgba(214, 196, 166, 0) 72%);
  animation: rkDust .55s ease-out .9s both;
}
@keyframes rkDust {
  from { opacity: 0; transform: scale(.45); }
  to   { opacity: .9; transform: scale(1.35); }
}
/* 退场：没有气球可飞，就「往后撤一步淡出」 */
.rk-bye-crew {
  width: 130px;
  filter: drop-shadow(0 6px 12px rgba(0, 0, 0, .45));
  animation: rkByeCrew 1.7s ease-out forwards;
}
@keyframes rkByeCrew {
  0%   { transform: scale(1) translateY(0); opacity: 1; }
  60%  { transform: scale(1.05) translateY(-4px); opacity: 1; }
  100% { transform: scale(.8) translateY(-30px); opacity: 0; }
}

/* 撞上那一下：整张地图抖两下（只抖不缩放，缩放会让地图边缘露白） */
@keyframes rkHit {
  0%, 100% { transform: translate(0, 0); }
  20% { transform: translate(-5px, 3px); }
  45% { transform: translate(5px, -3px); }
  70% { transform: translate(-3px, 2px); }
}
.story-map.rk-hit { animation: rkHit .22s 2; }

/* ---------- 人物图鉴（2026-10-31） ----------
   3 列方形格子：立绘是 512×512 方画布、脚底零透明留白，所以方框 + contain 正好全身。
   ★ 别改成圆形裁切 —— 会把帽檐和披风切掉，孩子认人靠的就是帽子和发型。
   ★ 也不要用 `cover`：立绘左右是透明区，cover 会把手臂切边。 */
.cast-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px; }
.cast-cell {
  display: flex; flex-direction: column; align-items: center; gap: 1px;
  padding: 6px 4px 7px; border: 1px solid var(--border); border-radius: 10px;
  background: var(--surface); font-family: inherit; cursor: pointer; text-align: center;
}
.cast-cell:active { background: var(--surface2, rgba(0,0,0,.03)); }
.cast-cell b { font-size: 13px; font-weight: 600; line-height: 1.25; }
.cast-role { font-size: 11px; color: var(--muted); line-height: 1.2; }
.cast-pic {
  display: block; width: 100%; aspect-ratio: 1 / 1;
  background: #fff; border-radius: 8px; overflow: hidden;
}
.cast-pic img { width: 100%; height: 100%; object-fit: contain; display: block; }

/* 看大图：整屏压暗，立绘按 contain 放到最大（手机竖屏约 88vw 见方） */
.cast-mask {
  position: fixed; inset: 0;
  /* 70 = 和火箭队过场同一层，压住 tabbar(60) */
  z-index: 70;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 10px; padding: 18px;
  background: rgba(14, 16, 20, .88);
}
.cast-mask img {
  width: min(88vw, 64vh); height: min(88vw, 64vh);
  object-fit: contain;
  /* 立绘白底会被压暗的背景衬出来一圈，给它一块自己的浅色板 */
  background: #fff; border-radius: 14px;
}
.cast-cap { text-align: center; color: #f2f4f8; line-height: 1.4; }
.cast-cap b { font-size: 20px; }
.cast-cap span { display: block; font-size: 13px; color: #a9b0bd; }
.cast-tip { font-size: 12px; color: #7d8798; }

.rk-mask {
  position: fixed;
  inset: 0;
  /* 70 = 压住 tabbar(60) 和 dialog(50)：这是一整屏的过场，不能露出下面的导航 */
  z-index: 70;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 20px;
  background: rgba(18, 20, 26, .62);
}
.rk-motto {
  width: 100%;
  max-width: 440px;
  max-height: 84vh;
  overflow-y: auto;
  padding: 18px 18px 14px;
  border-radius: 14px;
  border: 1px solid rgba(232, 68, 47, .55);
  background: #171a21;
  color: #f7f1e6;
  text-align: center;
  box-shadow: 0 18px 50px rgba(0, 0, 0, .45);
}
.rk-kicker {
  margin-bottom: 10px;
  color: #ff8f7a;
  font-size: 12px;
  letter-spacing: .2em;
}
/* 逐行浮现：没 .on 之前**整个不占位**（display:none）。
   ★ 第一版用的是 opacity:0 占位，结果 8 句一起撑高弹层，前 3 秒是一个巨大的空黑框
     （下面留 500px 空白），比"弹层一抖一抖"难看得多。现在是像聊天记录一样往下长。 */
.rk-line {
  display: none;
  font-size: 15px;
  line-height: 1.8;
  font-weight: 600;
}
/* 开场旁白：小一号、暗一档，跟在标题下面。不参与逐行浮现，弹层一开就在。 */
.rk-intro {
  margin: 0 2px 12px;
  font-size: 12.5px;
  line-height: 1.75;
  color: #b9b2a4;
  text-align: left;
}
.rk-motto .btn-row { justify-content: center; }
.rk-line.on {
  display: block;
  animation: rkLine .3s ease-out both;
}
@keyframes rkLine {
  from { opacity: 0; transform: translateY(6px); }
  to { opacity: 1; transform: none; }
}

/* 被打飞：原地转起来缩成一个点飞向天边 */
.rk-blastmask {
  position: fixed;
  inset: 0;
  z-index: 72;
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(18, 20, 26, .28);
  pointer-events: none;
}
.rk-blast {
  position: relative;
  left: auto;
  top: auto;
  margin: 0;
  transition: none;                /* 别让 .rk-craft 的 transition 和动画打架 */
  transform-origin: 50% 60%;
  animation: rkBlast 2.2s cubic-bezier(.42, 0, .72, 1) forwards;
}
@keyframes rkBlast {
  0% { transform: translate(0, 0) rotate(0deg) scale(1); opacity: 1; }
  18% { transform: translate(-8px, 6px) rotate(-14deg) scale(1.05); }
  55% { transform: translate(50px, -110px) rotate(200deg) scale(.6); opacity: 1; }
  100% { transform: translate(230px, -400px) rotate(760deg) scale(.1); opacity: 0; }
}
.rk-bye {
  position: absolute;
  left: 50%;
  top: 22%;                       /* 放上半屏：第一版放 bottom:16% 直接压在选项卡上 */
  transform: translateX(-50%);
  font-size: 18px;
  font-weight: 800;
  color: #fff;
  text-shadow: 0 2px 0 #c4451f, 0 0 18px rgba(255, 140, 90, .9);
  animation: rkBye 2.4s ease-out forwards;
  white-space: nowrap;
}
@keyframes rkBye {
  0% { opacity: 0; transform: translate(-50%, 10px) scale(.9); }
  18%, 70% { opacity: 1; transform: translate(-50%, 0) scale(1); }
  100% { opacity: 0; transform: translate(-50%, -14px) scale(1.02); }
}

/* ================= 密阿雷夜战（2026-11-01） =================
   卡洛斯八馆通关后的夜间三连战：入口卡挂在地图上，点进去是选伴页，战斗复用 story 舞台。
   ★ 配色**故意偏离全局**（深蓝夜/暖金），因为玩法本身就发生在夜里 ——
     用白底卡片会像"另一个普通功能"，用户要的是"晚上出门打架"。 */
.night-card {
  position: relative;
  display: flex; align-items: center; gap: 10px; width: 100%;
  margin-top: 12px; padding: 8px;
  border: 1px solid var(--border); border-radius: var(--radius);
  background: var(--surface); text-align: left;
}
.night-card.on {
  border-color: #3b4874;
  background: linear-gradient(160deg, #182140 0%, #2b3861 100%);
}
.night-card:disabled { opacity: .78; }
.night-card .nc-pic {
  flex: 0 0 auto; width: 62px; height: 76px; border-radius: 8px; overflow: hidden;
  background: #0d1428;
}
.night-card .nc-pic img {
  width: 100%; height: 100%; object-fit: cover; object-position: 50% 42%; display: block;
}
.night-card .nc-txt { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
.night-card .nc-txt b { font-size: 15px; line-height: 1.3; }
.night-card .nc-txt i { font-style: normal; font-size: 12px; color: var(--muted); }
.night-card .nc-txt u { text-decoration: none; font-size: 11px; color: var(--muted); }
.night-card.on .nc-txt b { color: #eef2ff; }
.night-card.on .nc-txt i { color: #c3cdf0; }
.night-card.on .nc-txt u { color: #9aa6cc; }
/* 徽章**绝对定位到右上角**：放流里会跟三行说明挤同一行，把
   「只上 1 只 · 三连战不回血 · 带 Mega 血 ×2」压成两行（实测 390px 宽就折）。 */
.night-card .nc-badge {
  position: absolute; right: 8px; top: 6px;
  font-size: 11px; color: #d9a53a; white-space: nowrap;
}

.night-hero { position: relative; border-radius: var(--radius); overflow: hidden; margin-bottom: 12px;
  /* ★ 地景 webp 的顶部 34% 是**透明**的（`prep_story_scene` 把那一截抠掉，交给
     `.ss-sky` 层去画，否则推轨会把天空一起放大）。战斗页有天空层，这里没有 ⇒
     透明区直接露出页面底色，在浅色主题下是**一条横贯卡片的空白带**（阿罗拉那张
     最明显，因为它的天空最黑）。垫一层同色竖向渐变，透明处就当夜空看。 */
  background: linear-gradient(180deg, #070a18 0%, #12192c 34%, #1a2238 100%); }
.night-hero img {
  width: 100%; aspect-ratio: 5 / 4; object-fit: cover; object-position: 50% 46%; display: block;
}
.night-hero .nh-cap {
  position: absolute; left: 0; right: 0; bottom: 0; padding: 30px 12px 10px;
  background: linear-gradient(180deg, rgba(6, 10, 24, 0) 0%, rgba(6, 10, 24, .88) 70%);
  color: #eef2ff;
}
.night-hero .nh-cap b { font-size: 15px; display: block; }
.night-hero .nh-cap i { font-style: normal; font-size: 12px; color: #b9c3e4; }

.night-rules {
  display: flex; flex-direction: column; gap: 3px;
  padding: 9px 12px; margin-bottom: 10px;
  border: 1px solid var(--border); border-radius: var(--radius);
  background: var(--surface); font-size: 13px;
}
.night-rules b { color: var(--primary); font-weight: 600; }
.night-lock {
  padding: 9px 12px; margin-bottom: 10px; border-radius: var(--radius);
  background: rgba(140, 100, 20, .10); color: #8a6316; font-size: 13px;
}
/* 规则块下面那句过场旁白（「今晚为什么只能带一只」）。
   ★ 故意做成**深色块**：它讲的是故事、不是规则，得跟上面那张浅色规则卡分开；
     配色沿用夜战那张入口卡的深蓝，孩子一眼就知道"这是夜里的话"，不是又要读的条款。
   ⚠️ 别放进 `.night-rules` 里面 —— 那里每行都挂 ①②③④ 的编号，塞进去会多出个空号。 */
.night-why {
  margin: 0 0 12px; padding: 10px 12px;
  border-left: 3px solid #c9a44c; border-radius: 0 10px 10px 0;
  background: linear-gradient(100deg, #16203a 0%, #232f52 100%);
  color: #dfe4f5; font-size: 13px; line-height: 1.8;
}
.night-h { font-size: 13px; color: var(--muted); margin: 12px 0 8px; }
.night-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px; }
.night-mon {
  display: flex; flex-direction: column; align-items: center; gap: 1px;
  padding: 8px 4px; border: 1px solid var(--border); border-radius: 10px;
  background: var(--surface); font-family: inherit; cursor: pointer; text-align: center;
}
.night-mon.on { border-color: var(--primary); background: var(--primary-soft); }
.night-mon img { width: 62px; height: 62px; object-fit: contain; display: block; }
.night-mon b { font-size: 13px; font-weight: 600; line-height: 1.25; }
.night-mon i { font-style: normal; font-size: 11px; color: var(--muted); line-height: 1.2; }

/* 我方带 Mega：角标挂**我方这一侧**（左上）。极巨化那个是对面变大，挂右上。 */
.ss-mega-tag {
  position: absolute; left: 10px; top: 10px; z-index: 9; pointer-events: none;
  display: flex; align-items: baseline; gap: 5px;
  font-size: 11px; letter-spacing: .12em; font-weight: 600;
  padding: 2px 9px; border-radius: 999px;
  color: #fff3d6;
  background: linear-gradient(90deg, #b4381a 0%, #9d2c8f 100%);
  border: .5px solid rgba(255, 205, 130, .6);
}
.ss-mega-tag span { font-size: 9px; letter-spacing: 0; opacity: .85; }
