/* ============================================================
 * 知识星球大冒险 —— 样式表
 * 面向小学生的卡通游戏风格
 * ============================================================ */

/* ---------------- 主题变量 ---------------- */
:root {
  --p1: #8b7bf7;
  --p2: #5b8def;
  --p-soft: #efeaff;
  --c1: #8b7bf7;
  --c2: #5b8def;

  --bg1: #eef2ff;
  --bg2: #fdf2f8;
  --ink: #2f2a4a;
  --ink-2: #6b6488;
  --ink-3: #9d97b5;
  --card: #ffffff;
  --line: #ece9fb;

  --gold: #ffb703;
  --green: #22c55e;
  --red: #f43f5e;
  --cyan: #06b6d4;

  --r-lg: 24px;
  --r-md: 18px;
  --r-sm: 12px;
  --shadow: 0 8px 24px rgba(90, 80, 170, .12);
  --shadow-sm: 0 3px 10px rgba(90, 80, 170, .10);
  --shadow-btn: 0 5px 0 rgba(0, 0, 0, .13);
  --safe-b: env(safe-area-inset-bottom, 0px);
}

* { box-sizing: border-box; -webkit-tap-highlight-color: transparent; }

html, body {
  margin: 0; padding: 0; height: 100%;
  overscroll-behavior-y: none;
}

body {
  font-family: "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "Noto Sans SC",
               system-ui, -apple-system, "Segoe UI", sans-serif;
  color: var(--ink);
  background: linear-gradient(170deg, var(--bg1) 0%, var(--bg2) 55%, var(--bg1) 100%);
  background-attachment: fixed;
  -webkit-font-smoothing: antialiased;
  overflow: hidden;
}

button, input { font-family: inherit; }
button { cursor: pointer; border: none; background: none; color: inherit; }

/* 背景装饰光斑 */
.blobs { position: fixed; inset: 0; overflow: hidden; pointer-events: none; z-index: 0; }
.blob {
  position: absolute; border-radius: 50%; filter: blur(38px); opacity: .40;
  animation: floaty 14s ease-in-out infinite;
}
.blob.b1 { width: 260px; height: 260px; background: #c7b9ff; top: -70px; left: -70px; }
.blob.b2 { width: 220px; height: 220px; background: #ffc7e6; top: 30%; right: -80px; animation-delay: -4s; }
.blob.b3 { width: 200px; height: 200px; background: #b9e6ff; bottom: -60px; left: 10%; animation-delay: -8s; }
.blob.b4 { width: 180px; height: 180px; background: #ffe7b9; bottom: 20%; right: 12%; animation-delay: -6s; }

@keyframes floaty {
  0%, 100% { transform: translate(0, 0) scale(1); }
  33% { transform: translate(18px, -22px) scale(1.08); }
  66% { transform: translate(-16px, 14px) scale(.95); }
}

/* ---------------- 布局骨架 ---------------- */
#app {
  position: relative; z-index: 1;
  height: 100%;
  max-width: 760px;
  margin: 0 auto;
  display: flex; flex-direction: column;
  background: transparent;
}

#stage {
  flex: 1 1 auto;
  overflow-y: auto;
  overflow-x: hidden;
  -webkit-overflow-scrolling: touch;
  padding: 0 14px 12px;
  scroll-behavior: smooth;
}

.screen { display: none; animation: screenIn .28s ease both; }
.screen.active { display: block; }
@keyframes screenIn {
  from { opacity: 0; transform: translateY(12px); }
  to { opacity: 1; transform: none; }
}

/* ---------------- 顶栏 ---------------- */
#topbar {
  flex: 0 0 auto;
  padding: 10px 14px 8px;
  display: flex; align-items: center; gap: 10px;
}

.player-chip {
  display: flex; align-items: center; gap: 9px;
  background: var(--card);
  border-radius: 999px;
  padding: 5px 14px 5px 5px;
  box-shadow: var(--shadow-sm);
  flex: 1 1 auto; min-width: 0;
  border: 2px solid rgba(255, 255, 255, .8);
}
.avatar {
  width: 42px; height: 42px; flex: 0 0 auto;
  border-radius: 50%;
  background: linear-gradient(145deg, var(--p1), var(--p2));
  display: grid; place-items: center;
  font-size: 22px; line-height: 1;
  box-shadow: inset 0 -2px 6px rgba(0, 0, 0, .12);
}
.pinfo { min-width: 0; flex: 1 1 auto; }
.pname {
  font-size: 14px; font-weight: 800; white-space: nowrap;
  overflow: hidden; text-overflow: ellipsis;
}

.xpwrap { display: flex; align-items: center; gap: 6px; margin-top: 2px; }
.xpbar {
  flex: 1 1 auto; height: 7px; border-radius: 99px;
  background: var(--p-soft); overflow: hidden;
}
.xpbar > i {
  display: block; height: 100%; border-radius: 99px;
  background: linear-gradient(90deg, var(--p1), var(--p2));
  transition: width .5s cubic-bezier(.34, 1.4, .64, 1);
}
.lvbadge {
  font-size: 10px; font-weight: 900; color: #fff;
  background: linear-gradient(135deg, var(--p1), var(--p2));
  padding: 1px 7px; border-radius: 99px;
  flex: 0 0 auto;
}

.coinchip {
  flex: 0 0 auto;
  display: flex; align-items: center; gap: 4px;
  background: linear-gradient(135deg, #fff6dc, #ffe9b0);
  border-radius: 999px; padding: 7px 13px;
  font-weight: 900; font-size: 14px; color: #9a6b00;
  box-shadow: var(--shadow-sm);
  border: 2px solid #fff;
}
.coinchip .ico { font-size: 15px; }

/* ---------------- 底部导航 ---------------- */
#tabbar {
  flex: 0 0 auto;
  display: grid; grid-template-columns: repeat(5, 1fr);
  background: rgba(255, 255, 255, .93);
  backdrop-filter: blur(12px);
  border-top: 1px solid var(--line);
  padding: 6px 4px calc(6px + var(--safe-b));
}
.tab {
  display: flex; flex-direction: column; align-items: center; gap: 2px;
  padding: 6px 0; border-radius: 14px;
  font-size: 10.5px; font-weight: 700; color: var(--ink-3);
  transition: transform .15s, color .15s, background .15s;
  position: relative;
}
.tab .ti { font-size: 20px; line-height: 1; transition: transform .2s; }
.tab.active { color: var(--p2); background: var(--p-soft); }
.tab.active .ti { transform: translateY(-2px) scale(1.14); }
.tab:active { transform: scale(.94); }
.tab .dot {
  position: absolute; top: 3px; right: 50%; margin-right: -18px;
  min-width: 16px; height: 16px; padding: 0 4px;
  border-radius: 99px; background: var(--red); color: #fff;
  font-size: 10px; font-weight: 800; line-height: 16px; text-align: center;
}

/* ---------------- 通用卡片 / 标题 ---------------- */
.card {
  background: var(--card);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow);
  padding: 16px;
  margin-bottom: 14px;
  border: 2px solid rgba(255, 255, 255, .9);
}
.sec-title {
  display: flex; align-items: center; gap: 7px;
  font-size: 16px; font-weight: 900; margin: 18px 4px 10px;
}
.sec-title .em { font-size: 19px; }
.sec-title .more { margin-left: auto; font-size: 12px; color: var(--ink-3); font-weight: 700; }

/* ---------------- 欢迎横幅 ---------------- */
.hero {
  position: relative; overflow: hidden;
  border-radius: var(--r-lg);
  padding: 16px 18px;
  margin: 6px 0 14px;
  background: linear-gradient(135deg, var(--p1), var(--p2));
  color: #fff;
  box-shadow: 0 10px 26px rgba(110, 90, 220, .30);
}
.hero h1 { margin: 0 0 4px; font-size: 19px; font-weight: 900; letter-spacing: .5px; }
.hero p { margin: 0; font-size: 12.5px; opacity: .92; line-height: 1.55; }
.hero .deco {
  position: absolute; right: -6px; bottom: -14px; font-size: 78px; opacity: .22;
  transform: rotate(-12deg); pointer-events: none;
}
.hero .streak {
  display: inline-flex; align-items: center; gap: 4px; margin-top: 10px;
  background: rgba(255, 255, 255, .22); border-radius: 99px;
  padding: 4px 12px; font-size: 12px; font-weight: 800;
}
.hero .gorow { display: flex; gap: 8px; margin-top: 12px; flex-wrap: wrap; }
.hero .gobtn {
  background: #fff; color: var(--p2); font-weight: 900; font-size: 13px;
  padding: 9px 18px; border-radius: 99px;
  box-shadow: 0 4px 0 rgba(0, 0, 0, .13);
  transition: transform .1s;
}
.hero .gobtn:active { transform: translateY(3px); box-shadow: 0 1px 0 rgba(0, 0, 0, .13); }
.hero .gobtn.ghost { background: rgba(255, 255, 255, .2); color: #fff; box-shadow: none; border: 2px solid rgba(255, 255, 255, .55); }
/* 「今天该复习」是首页最该被点的那一个，给它最强的对比度 */
.hero .gobtn.due {
  background: linear-gradient(135deg, #ffc93c, #ff9f1c);
  color: #6b3d00; font-size: 14px; padding: 11px 22px;
  box-shadow: 0 4px 0 rgba(160, 90, 0, .35);
  animation: duePulse 2.2s ease-in-out infinite;
}
@keyframes duePulse {
  0%, 100% { transform: scale(1); }
  50% { transform: scale(1.035); }
}
@media (prefers-reduced-motion: reduce) {
  .hero .gobtn.due { animation: none; }
}

/* ---------------- 学科卡片 ---------------- */
.subjects { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
@media (max-width: 380px) { .subjects { grid-template-columns: 1fr; } }

.subject {
  position: relative; overflow: hidden;
  border-radius: var(--r-lg);
  padding: 14px;
  color: #fff; text-align: left;
  box-shadow: 0 8px 20px rgba(80, 70, 160, .18);
  transition: transform .16s cubic-bezier(.34, 1.4, .64, 1);
  min-height: 118px;
  display: flex; flex-direction: column; justify-content: space-between;
}
.subject:active { transform: scale(.96); }
.subject .sico { font-size: 30px; line-height: 1; }
.subject .sname { font-size: 16px; font-weight: 900; margin-top: 8px; }
/* .sdesc = "次要说明文字"的通用类。
   ★ 这里踩过一个很显眼的坑：这个类原来**没有基础样式** —— 只有
   `.subject .sdesc` 和 `.setting-row .sdesc` 两个带前缀的变体。
   于是全站 25 处单独用的 `.sdesc` 全都继承了 body 的字号（浏览器默认
   16px），在页面上跟正文一样大，跟读页那段"课本原文有版权…"甚至比
   标题还显眼，用户直接说"太难看"。
   基础样式补在这里；两个带前缀的变体各自 11px 不变。 */
.sdesc { font-size: 11.5px; color: var(--ink-3); font-weight: 600; line-height: 1.65; }

.subject .sdesc { font-size: 11px; opacity: .9; margin-top: 3px; line-height: 1.45; }
.subject .sbar {
  margin-top: 9px; height: 6px; border-radius: 99px;
  background: rgba(255, 255, 255, .32); overflow: hidden;
}
.subject .sbar > i { display: block; height: 100%; background: #fff; border-radius: 99px; transition: width .6s; }
.subject .sstars {
  position: absolute; top: 12px; right: 12px;
  font-size: 11px; font-weight: 800;
  background: rgba(0, 0, 0, .16); padding: 3px 9px; border-radius: 99px;
}
.subject .sdeco {
  position: absolute; right: -10px; bottom: -16px; font-size: 64px; opacity: .16;
  transform: rotate(-10deg); pointer-events: none;
}

/* ---------------- 每日任务 ---------------- */
.task {
  display: flex; align-items: center; gap: 11px;
  padding: 11px 4px; border-bottom: 1px dashed var(--line);
}
.task:last-child { border-bottom: none; }
.task .tico { font-size: 22px; flex: 0 0 auto; width: 28px; text-align: center; }
.task .tbody { flex: 1 1 auto; min-width: 0; }
.task .tname { font-size: 13.5px; font-weight: 800; }
.task .tprog { font-size: 11px; color: var(--ink-3); margin-top: 2px; }
.task .tbar { height: 6px; border-radius: 99px; background: var(--p-soft); margin-top: 6px; overflow: hidden; }
.task .tbar > i { display: block; height: 100%; border-radius: 99px; background: linear-gradient(90deg, #ffd166, #ff9f1c); transition: width .4s; }
.task .tbtn {
  flex: 0 0 auto; font-size: 12px; font-weight: 900;
  padding: 7px 13px; border-radius: 99px;
  background: linear-gradient(135deg, var(--p1), var(--p2)); color: #fff;
  box-shadow: 0 3px 0 rgba(0, 0, 0, .13);
}
.task .tbtn:active { transform: translateY(2px); box-shadow: 0 1px 0 rgba(0, 0, 0, .13); }
.task .tbtn.done { background: #e9e7f5; color: var(--ink-3); box-shadow: none; }
.task .tbtn.claim { background: linear-gradient(135deg, #ffc93c, #ff9f1c); color: #6b3d00; animation: pulse 1.2s infinite; }
@keyframes pulse {
  0%, 100% { transform: scale(1); }
  50% { transform: scale(1.06); }
}

/* ---------------- 当前课本（年级 / 学期） ----------------
   换课本只有「我的」里那一张卡（.pg 里的 bookCard）。
   首页和地图原来各有一行"正在学 X 年级X册 · 换课本去「我的」"，
   已经删掉了：用户说去「我的」换是常识不用提示，而且课本在哪一册
   各页本来就有地方写着。 */

.gc-title { font-size: 14.5px; font-weight: 900; }
.gc-title b { color: var(--p2); }
.gc-sub { font-size: 11.5px; color: var(--ink-3); margin-top: 3px; line-height: 1.55; }

.chips { display: flex; flex-wrap: wrap; gap: 7px; }
.chip {
  font-size: 12.5px; font-weight: 800; color: var(--ink-2);
  background: #f4f2fb; border-radius: 99px; padding: 8px 14px;
  border: 2px solid transparent;
  transition: transform .12s cubic-bezier(.34,1.5,.64,1), background .15s, color .15s, box-shadow .15s;
}
.chip:active { transform: scale(.93); }
.chip.active {
  background: linear-gradient(135deg, var(--p1), var(--p2));
  color: #fff; box-shadow: 0 3px 10px rgba(90, 80, 170, .28);
}
.chip.all { background: #fff; border-color: var(--line); }
.chip.all.active { background: linear-gradient(135deg, var(--p1), var(--p2)); border-color: transparent; }
.chip.sm { padding: 6px 13px; font-size: 12px; }
.chip.big { padding: 11px 19px; font-size: 14px; }
.chips.terms {
  margin-top: 11px; padding-top: 11px;
  border-top: 1px dashed var(--line); align-items: center;
}
.chip-label { font-size: 12px; color: var(--ink-3); font-weight: 800; }
.modal-chips { justify-content: center; margin-top: 16px; }

/* 上册 / 下册 / 期末 标签 */
.term-badge {
  display: inline-block; font-size: 10px; font-weight: 900;
  padding: 1.5px 7px; border-radius: 99px; margin-right: 5px;
  vertical-align: 1.5px;
}
.term-badge.tup { background: #e6f0ff; color: #2563eb; }
.term-badge.tdown { background: #e7f9ef; color: #15803d; }
.term-badge.trev { background: #fff2e0; color: #b45309; }
.term-badge.extend { background: linear-gradient(135deg,#fff1d6,#ffe0b2); color: #b45309; }

/* 期末 Boss 关 */
.node.boss {
  background: linear-gradient(145deg, #fff6d8, #ffe1a0);
  box-shadow: 0 6px 0 rgba(200, 150, 0, .30), 0 8px 20px rgba(220, 160, 0, .28);
  border-color: #ffe9a8;
}
.node.boss.locked { background: linear-gradient(145deg, #f2f1f7, #e6e4ef); box-shadow: 0 6px 0 rgba(140, 135, 165, .18); border-color: #fff; }
.node.boss::after {
  content: ''; position: absolute; inset: -8px; border-radius: 50%;
  border: 2px dashed rgba(255, 183, 3, .55);
}
.node.boss.locked::after { display: none; }

/* 学科卡片底部小字 / 未开课状态 */
.sfoot { font-size: 10.5px; font-weight: 800; opacity: .88; margin-top: 6px; }
.subject { min-height: 128px; }
.subject.locked-subject .sico { filter: grayscale(.5); opacity: .8; }

/* ---------------- 关卡地图 ---------------- */
.maphead {
  border-radius: var(--r-lg);
  padding: 16px 18px; margin: 6px 0 16px;
  color: #fff; position: relative; overflow: hidden;
  box-shadow: 0 10px 24px rgba(80, 70, 160, .22);
}
.maphead h2 { margin: 0; font-size: 20px; font-weight: 900; }
.maphead p { margin: 5px 0 0; font-size: 12px; opacity: .92; }
.maphead .mdeco { position: absolute; right: -4px; top: -8px; font-size: 76px; opacity: .22; }
.backbtn {
  display: inline-flex; align-items: center; gap: 5px;
  font-size: 13px; font-weight: 800; color: var(--ink-2);
  background: var(--card); padding: 8px 15px; border-radius: 99px;
  box-shadow: var(--shadow-sm); margin: 4px 0 6px;
}
.backbtn:active { transform: scale(.95); }

.gradegroup { margin-bottom: 8px; }
.gradelabel {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: 12.5px; font-weight: 900; color: var(--ink-2);
  background: var(--card); padding: 5px 14px; border-radius: 99px;
  box-shadow: var(--shadow-sm); margin: 14px 0 6px 4px;
}
.gradelabel .gl-bar { font-size: 11px; color: var(--ink-3); font-weight: 700; }

/* 年级主题：拼音启蒙 · 汉字乐园 */
.gradetheme {
  font-size: 11.5px; font-weight: 700; color: var(--ink-3);
  margin: 0 0 2px 6px; line-height: 1.5;
}

/* 关卡分段小标题：上册·课本基础 / 上册·拓展提升 / 期末冲刺 */
.chaphead {
  display: flex; align-items: center; gap: 8px;
  font-size: 11px; font-weight: 900; letter-spacing: .5px;
  color: var(--p2); margin: 14px 0 4px 6px;
}
.chaphead::after {
  content: ''; flex: 1 1 auto; height: 0;
  border-top: 1.5px dashed #ded9f0;
}

.path { position: relative; padding: 4px 0 10px; }
.node-row {
  display: flex; align-items: center; gap: 12px;
  padding: 7px 0; position: relative;
}
.node-row.right { flex-direction: row-reverse; }
.node-row.right .node-info { text-align: right; }

.node {
  position: relative; flex: 0 0 auto;
  width: 68px; height: 68px; border-radius: 50%;
  display: grid; place-items: center;
  font-size: 28px;
  background: linear-gradient(145deg, #fff, #f1eeff);
  box-shadow: 0 6px 0 rgba(120, 105, 200, .18), 0 8px 18px rgba(90, 80, 170, .16);
  border: 3px solid #fff;
  transition: transform .16s cubic-bezier(.34, 1.5, .64, 1);
}
.node:active { transform: scale(.93); }
.node.cleared { background: linear-gradient(145deg, #fff8e1, #ffe9a8); }
.node.perfect { background: linear-gradient(145deg, #fff3c4, #ffd76e); box-shadow: 0 6px 0 rgba(200, 150, 0, .28), 0 8px 20px rgba(220, 160, 0, .28); }
.node.locked { background: linear-gradient(145deg, #f2f1f7, #e6e4ef); color: #b6b1c9; box-shadow: 0 6px 0 rgba(140, 135, 165, .18); }
.node .lock { font-size: 24px; }
.node .badge-lv {
  position: absolute; top: -6px; left: -6px;
  min-width: 22px; height: 22px; padding: 0 5px;
  border-radius: 99px; background: linear-gradient(135deg, var(--p1), var(--p2));
  color: #fff; font-size: 10.5px; font-weight: 900; line-height: 22px; text-align: center;
  box-shadow: 0 2px 6px rgba(0, 0, 0, .2);
}
.node.current { animation: nodepulse 1.6s ease-in-out infinite; }
@keyframes nodepulse {
  0%, 100% { box-shadow: 0 6px 0 rgba(120, 105, 200, .18), 0 0 0 0 rgba(139, 123, 247, .55); }
  50% { box-shadow: 0 6px 0 rgba(120, 105, 200, .18), 0 0 0 12px rgba(139, 123, 247, 0); }
}

.node-info { flex: 1 1 auto; min-width: 0; }
.node-info .nname { font-size: 14.5px; font-weight: 900; }
.node-info .ntip { font-size: 11.5px; color: var(--ink-3); margin-top: 3px; line-height: 1.5; }
.node-info .nstars { font-size: 14px; letter-spacing: 1px; margin-top: 4px; }
.star-on { color: var(--gold); }
.star-off { color: #ddd8ec; }

.connector {
  width: 3px; height: 16px; margin: 0 0 0 33px;
  border-left: 3px dashed #d8d3ee;
}
.node-row.right + .connector { margin-left: auto; margin-right: 33px; }

/* ---------------- 答题界面 ---------------- */
.quiz-top { display: flex; align-items: center; gap: 10px; margin: 8px 0 12px; }
.icon-btn {
  width: 38px; height: 38px; flex: 0 0 auto;
  border-radius: 50%; background: var(--card);
  display: grid; place-items: center; font-size: 17px;
  box-shadow: var(--shadow-sm); font-weight: 800; color: var(--ink-2);
}
.icon-btn:active { transform: scale(.92); }

.qbar { flex: 1 1 auto; height: 12px; border-radius: 99px; background: var(--card); box-shadow: inset 0 2px 4px rgba(90, 80, 170, .10); overflow: hidden; }
.qbar > i { display: block; height: 100%; border-radius: 99px; background: linear-gradient(90deg, var(--p1), var(--p2)); transition: width .35s ease; }

.hearts { flex: 0 0 auto; display: flex; gap: 2px; font-size: 17px; }
.hearts .h { transition: transform .3s, opacity .3s, filter .3s; }
.hearts .h.off { filter: grayscale(1); opacity: .32; transform: scale(.8); }
.hearts .h.breaking { animation: heartbreak .55s ease; }
@keyframes heartbreak {
  0% { transform: scale(1.5); }
  40% { transform: scale(.6) rotate(-18deg); }
  100% { transform: scale(.8); }
}

.quiz-meta {
  display: flex; align-items: center; justify-content: space-between;
  font-size: 12px; font-weight: 800; color: var(--ink-3);
  margin: 0 4px 10px;
}
.combo-badge {
  display: inline-flex; align-items: center; gap: 3px;
  background: linear-gradient(135deg, #ff9a3c, #ff5f6d); color: #fff;
  padding: 3px 11px; border-radius: 99px; font-size: 12px; font-weight: 900;
  animation: pop .35s cubic-bezier(.34, 1.6, .64, 1);
}
@keyframes pop {
  0% { transform: scale(.4); opacity: 0; }
  70% { transform: scale(1.18); }
  100% { transform: scale(1); opacity: 1; }
}

.qcard {
  background: var(--card); border-radius: var(--r-lg);
  padding: 20px 18px; box-shadow: var(--shadow);
  border: 2px solid rgba(255, 255, 255, .9);
  margin-bottom: 14px;
}
.qtype {
  display: inline-block; font-size: 11px; font-weight: 900;
  padding: 3px 10px; border-radius: 99px; margin-bottom: 10px;
}
.qtype.choice { background: #e6f0ff; color: #2563eb; }
.qtype.input { background: #e7f9ef; color: #15803d; }
.qtype.judge { background: #fff2e0; color: #b45309; }

.qtext {
  font-size: 19px; font-weight: 800; line-height: 1.65;
  word-break: break-word; white-space: pre-wrap;
}
.qtext .blank { color: var(--p2); font-weight: 900; }

/* 题干/选项/解析里的英文片段。
   中文字体会把 ’ “ ” 这类标点按全角宽度排版，It’s 会变成「It’ s」。
   这里显式指定拉丁字体，让西文标点恢复正常的窄宽度。
   只影响被包起来的英文片段，中文标点不受影响。 */
.en {
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
               "Helvetica Neue", Arial, "Liberation Sans", "DejaVu Sans",
               "Noto Sans", sans-serif;
}

.qspeak {
  display: inline-flex; align-items: center; gap: 5px;
  margin-top: 12px; font-size: 13px; font-weight: 800;
  background: var(--p-soft); color: var(--p2);
  padding: 7px 14px; border-radius: 99px;
}
.qspeak:active { transform: scale(.95); }

/* 选项 */
.options { display: flex; flex-direction: column; gap: 10px; margin-top: 4px; }
.opt {
  display: flex; align-items: center; gap: 12px;
  background: var(--card); border: 2.5px solid var(--line);
  border-radius: var(--r-md); padding: 14px 15px;
  font-size: 16px; font-weight: 700; text-align: left;
  box-shadow: 0 3px 0 rgba(120, 105, 200, .10);
  transition: transform .12s, border-color .15s, background .15s;
  line-height: 1.5;
}
.opt:active { transform: scale(.98); }
.opt .key {
  flex: 0 0 auto; width: 28px; height: 28px; border-radius: 50%;
  display: grid; place-items: center;
  background: var(--p-soft); color: var(--p2);
  font-size: 13px; font-weight: 900;
}
.opt.correct { border-color: var(--green); background: #eafaf0; }
.opt.correct .key { background: var(--green); color: #fff; }
.opt.wrong { border-color: var(--red); background: #ffedf0; animation: shake .42s; }
.opt.wrong .key { background: var(--red); color: #fff; }
.opt[disabled] { cursor: default; }
.opt.dim { opacity: .5; }
@keyframes shake {
  0%, 100% { transform: translateX(0); }
  20% { transform: translateX(-8px); }
  40% { transform: translateX(7px); }
  60% { transform: translateX(-5px); }
  80% { transform: translateX(3px); }
}

/* 填空 */
.input-area { margin-top: 12px; }

/* 答题框：高度**钉死**。
   这里踩过一次坑：原来只写了 min-height，盒子实际多高由"字体默认行高"决定，
   而空状态的提示语是 15px、填了数字是 22px —— 于是孩子一按数字，
   行高一大盒子就变高，下面的数字键盘跟着往下跳，手指正按着的位置就跑了。
   所以这里 height + line-height 都给死值，两个状态只准改颜色和字号，
   不许碰任何影响高度的属性。.answerbox.empty 里加 height/padding/line-height
   会被冒烟测试当场拦下。

   为什么这个状态类叫 is-idle 而不是 empty：
   原来它叫 .answerbox.empty，结果撞上了全站通用的空状态类
   `.empty { padding: 44px 20px }`（在本文件后面）。两者优先级都是
   "一个类"，后面的赢 —— 于是那个 44px 的上下内边距盖掉了这里的
   padding: 0 14px，盒子被撑到 92px（54px 的 height 也救不了：
   border-box 下内边距比 height 大时，高度只能跟着内边距走）。
   症状就是"一填数字盒子就矮 38px、键盘跟着跳"。
   教训：组件内部的状态类一律加前缀（is- / has-），别用 empty、on、
   active 这种通用词，否则早晚撞上某个全局类。 */

.answerbox {
  height: 54px;
  line-height: 50px;              /* 54 - 上下各 2px 边框 = 50，正好一行文字垂直居中 */
  padding: 0 14px;
  background: #faf9ff; border: 2px dashed #d8d3ee;
  border-radius: var(--r-md);
  font-size: 22px; font-weight: 900; letter-spacing: 1px;
  color: var(--p2);
  text-align: center;
  white-space: nowrap;            /* 长答案不许折行把盒子撑高 */
  overflow: hidden;
}
/* 只准改这三样 —— 一个都不影响高度 */
.answerbox.is-idle { color: var(--ink-3); font-size: 14.5px; font-weight: 700; }
/* 答案长了自己缩小，而不是把盒子撑高（14 位数字也能一行放下） */
.answerbox.long { font-size: 16px; letter-spacing: 0; }

.keypad { display: grid; grid-template-columns: repeat(4, 1fr); gap: 8px; margin-top: 10px; }
.keypad .k {
  background: var(--card); border-radius: var(--r-sm);
  padding: 12px 0; font-size: 19px; font-weight: 900; line-height: 1.15;
  box-shadow: 0 4px 0 rgba(120, 105, 200, .16);
  transition: transform .08s;
}
.keypad .k:active { transform: translateY(3px); box-shadow: 0 1px 0 rgba(120, 105, 200, .16); }
.keypad .k.wide { grid-column: span 2; }
.keypad .k.go { background: linear-gradient(135deg, var(--p1), var(--p2)); color: #fff; box-shadow: 0 4px 0 rgba(60, 50, 130, .35); }
.keypad .k.del { background: #fff0f3; color: var(--red); }

.textinput {
  width: 100%; font-size: 18px; font-weight: 800;
  padding: 14px 16px; border-radius: var(--r-md);
  border: 2.5px solid var(--line); background: #faf9ff;
  color: var(--ink); outline: none;
}
.textinput:focus { border-color: var(--p1); background: #fff; }

/* 输入框没填时的就地提示：直接显示在输入框下面，
   比顶部的 toast 离眼睛近得多，也不会被弹窗遮罩糊掉 */
.textinput.bad {
  border-color: var(--red);
  background: #fff5f7;
  animation: fieldShake .4s ease;
}
@keyframes fieldShake {
  0%, 100% { transform: translateX(0); }
  20% { transform: translateX(-7px); }
  40% { transform: translateX(6px); }
  60% { transform: translateX(-4px); }
  80% { transform: translateX(2px); }
}
.field-err {
  display: flex; align-items: center; justify-content: center; gap: 5px;
  margin-top: 9px; font-size: 13px; font-weight: 800;
  color: var(--red);
  animation: fieldErrIn .22s ease both;
}
@keyframes fieldErrIn {
  from { opacity: 0; transform: translateY(-4px); }
  to { opacity: 1; transform: none; }
}

.bigbtn {
  display: block; width: 100%; margin-top: 12px;
  padding: 16px; border-radius: var(--r-md);
  font-size: 17px; font-weight: 900; color: #fff;
  background: linear-gradient(135deg, var(--p1), var(--p2));
  box-shadow: 0 5px 0 rgba(60, 50, 130, .32);
  transition: transform .1s;
}
.bigbtn:active { transform: translateY(3px); box-shadow: 0 2px 0 rgba(60, 50, 130, .32); }
.bigbtn.ghost { background: var(--card); color: var(--p2); box-shadow: 0 5px 0 rgba(120, 105, 200, .18); }
.bigbtn.gold { background: linear-gradient(135deg, #ffc93c, #ff9f1c); color: #6b3d00; box-shadow: 0 5px 0 rgba(180, 110, 0, .35); }
.bigbtn[disabled] { opacity: .45; box-shadow: none; }

/* 反馈条 */
.feedback {
  border-radius: var(--r-lg); padding: 15px 17px; margin-bottom: 14px;
  animation: fbIn .3s cubic-bezier(.34, 1.5, .64, 1) both;
  border: 2.5px solid;
}
.feedback.ok { background: #eafaf0; border-color: #a8e6c1; }
.feedback.no { background: #fff0f3; border-color: #ffc4cf; }
@keyframes fbIn {
  from { opacity: 0; transform: translateY(14px) scale(.96); }
  to { opacity: 1; transform: none; }
}
.feedback .fhead { display: flex; align-items: center; gap: 8px; font-size: 16px; font-weight: 900; }
.feedback.ok .fhead { color: #15803d; }
.feedback.no .fhead { color: #be123c; }
.feedback .fbody { font-size: 14px; line-height: 1.65; margin-top: 8px; color: var(--ink-2); }
.feedback .fbody b { color: var(--ink); }
.feedback .fans {
  display: inline-block; margin-top: 8px; font-size: 14px; font-weight: 900;
  background: #fff; padding: 5px 13px; border-radius: 99px; color: var(--p2);
}

/* ---------------- 结算 ---------------- */
.result-wrap { text-align: center; padding: 8px 0 20px; }
.stars-big { display: flex; justify-content: center; gap: 10px; margin: 16px 0 6px; }
.stars-big .s {
  font-size: 46px; line-height: 1;
  opacity: 0; transform: scale(.2) rotate(-40deg);
  animation: starPop .55s cubic-bezier(.34, 1.7, .64, 1) forwards;
}
.stars-big .s.off { filter: grayscale(1); opacity: .28; animation: none; transform: none; }
@keyframes starPop {
  0% { opacity: 0; transform: scale(.2) rotate(-40deg); }
  70% { opacity: 1; transform: scale(1.35) rotate(8deg); }
  100% { opacity: 1; transform: scale(1) rotate(0); }
}
.result-title { font-size: 24px; font-weight: 900; margin: 6px 0 4px; }
.result-sub { font-size: 13.5px; color: var(--ink-3); font-weight: 700; }

.score-ring {
  width: 130px; height: 130px; margin: 18px auto 6px; position: relative;
  border-radius: 50%;
  display: grid; place-items: center;
  background: conic-gradient(var(--p1) calc(var(--p, 0) * 1%), #eceaf7 0);
}
.score-ring::before {
  content: ''; position: absolute; inset: 12px; border-radius: 50%; background: var(--card);
}
.score-ring .sv { position: relative; font-size: 30px; font-weight: 900; color: var(--p2); }
.score-ring .sl { position: relative; font-size: 11px; color: var(--ink-3); font-weight: 700; }

.reward-row { display: flex; justify-content: center; gap: 12px; margin: 16px 0 4px; flex-wrap: wrap; }
.reward {
  background: var(--card); border-radius: var(--r-md); padding: 12px 18px;
  box-shadow: var(--shadow-sm); min-width: 92px;
}
.reward .rv { font-size: 21px; font-weight: 900; }
.reward .rl { font-size: 11px; color: var(--ink-3); font-weight: 700; margin-top: 2px; }
.reward.coin .rv { color: #d99500; }
.reward.xp .rv { color: var(--p2); }
.reward.acc .rv { color: var(--green); }

.banner-lvup {
  background: linear-gradient(135deg, #ffd166, #ff9f1c);
  color: #6b3d00; font-weight: 900; font-size: 14px;
  border-radius: var(--r-md); padding: 12px; margin: 14px 0;
  animation: pulse 1.4s infinite;
}

.review-list { text-align: left; margin-top: 8px; }
.review-item {
  background: var(--card); border-radius: var(--r-md);
  padding: 12px 14px; margin-bottom: 9px;
  box-shadow: var(--shadow-sm); border-left: 4px solid var(--red);
}
.review-item.ok { border-left-color: var(--green); }
.review-item .rq { font-size: 13.5px; font-weight: 800; line-height: 1.55; }
.review-item .ra { font-size: 12.5px; margin-top: 6px; color: var(--ink-2); line-height: 1.6; }
.review-item .ra .bad { color: var(--red); font-weight: 800; }
.review-item .ra .good { color: var(--green); font-weight: 800; }
.review-item .rex { font-size: 12px; color: var(--ink-3); margin-top: 5px; line-height: 1.6; }

.result-actions { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; margin-top: 18px; }
.result-actions .bigbtn { margin-top: 0; }
.result-actions .full { grid-column: span 2; }

/* ---------------- 成就 ---------------- */
.ach-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(104px, 1fr)); gap: 11px; }
.ach {
  background: var(--card); border-radius: var(--r-md);
  padding: 14px 9px; text-align: center;
  box-shadow: var(--shadow-sm);
  transition: transform .15s;
}
.ach:active { transform: scale(.96); }
.ach .aico { font-size: 32px; line-height: 1; filter: grayscale(1); opacity: .35; }
.ach.got { background: linear-gradient(160deg, #fff8e6, #fff2cc); box-shadow: 0 6px 16px rgba(220, 170, 40, .22); }
.ach.got .aico { filter: none; opacity: 1; }
.ach .aname { font-size: 12.5px; font-weight: 900; margin-top: 7px; }
.ach .adesc { font-size: 10.5px; color: var(--ink-3); margin-top: 3px; line-height: 1.45; }
.ach .adate { font-size: 10px; color: var(--gold); font-weight: 800; margin-top: 4px; }

/* ---------------- 商店 ---------------- */
.shop-tabs { display: flex; gap: 8px; margin-bottom: 14px; }
.shop-tab {
  flex: 1 1 0; padding: 10px 0; border-radius: 99px;
  background: var(--card); font-size: 13px; font-weight: 900; color: var(--ink-3);
  box-shadow: var(--shadow-sm);
}
.shop-tab.active { background: linear-gradient(135deg, var(--p1), var(--p2)); color: #fff; }

.shop-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(112px, 1fr)); gap: 11px; }
.shop-item {
  background: var(--card); border-radius: var(--r-md);
  padding: 14px 10px; text-align: center;
  box-shadow: var(--shadow-sm); position: relative;
  border: 2.5px solid transparent;
  transition: transform .15s;
}
.shop-item:active { transform: scale(.96); }
.shop-item.equipped { border-color: var(--green); background: #f2fdf6; }
.shop-item.owned { opacity: .95; }
.shop-item .si { font-size: 34px; line-height: 1; }
.shop-item .stitle { font-size: 15px; font-weight: 900; margin-top: 6px; }
.shop-item .sname { font-size: 12.5px; font-weight: 800; margin-top: 6px; }
.shop-item .price {
  display: inline-flex; align-items: center; gap: 3px;
  font-size: 12.5px; font-weight: 900; color: #d99500;
  background: #fff6dc; padding: 4px 11px; border-radius: 99px; margin-top: 8px;
}
.shop-item .price.free { color: #15803d; background: #e7f9ef; }
.shop-item .tag {
  position: absolute; top: 7px; right: 7px;
  font-size: 10px; font-weight: 900; padding: 2px 7px; border-radius: 99px;
  background: var(--green); color: #fff;
}
.theme-swatch { display: flex; height: 34px; border-radius: 10px; overflow: hidden; margin-bottom: 8px; }
.theme-swatch i { flex: 1; }

/* ---------------- 我的 ---------------- */
.stat-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 10px; }
.stat {
  background: var(--card); border-radius: var(--r-md);
  padding: 13px 8px; text-align: center; box-shadow: var(--shadow-sm);
}
.stat .sv { font-size: 20px; font-weight: 900; color: var(--p2); }
.stat .sl { font-size: 10.5px; color: var(--ink-3); font-weight: 700; margin-top: 3px; }

.setting-row {
  display: flex; align-items: center; gap: 10px;
  padding: 13px 2px; border-bottom: 1px dashed var(--line);
  font-size: 14px; font-weight: 800;
}
.setting-row:last-child, .card .setting-row:last-of-type { border-bottom: none; }
.setting-row .sdesc { font-size: 11px; color: var(--ink-3); font-weight: 600; margin-top: 2px; }
.setting-row .grow { flex: 1 1 auto; }
.setting-row.col { flex-direction: column; align-items: stretch; gap: 10px; }
.sr-line { display: flex; align-items: center; gap: 10px; }

/* 音色下拉 */
.select {
  width: 100%;
  font-size: 13.5px; font-weight: 700;
  padding: 11px 13px; border-radius: var(--r-sm);
  border: 2.5px solid var(--line); background: #faf9ff;
  color: var(--ink); outline: none;
  appearance: none;
  background-image:
    linear-gradient(45deg, transparent 50%, var(--ink-3) 50%),
    linear-gradient(135deg, var(--ink-3) 50%, transparent 50%);
  background-position: calc(100% - 18px) 50%, calc(100% - 12px) 50%;
  background-size: 6px 6px, 6px 6px;
  background-repeat: no-repeat;
  padding-right: 34px;
}
.select:focus { border-color: var(--p1); background-color: #fff; }

/* 当前正在使用的音色 */
.voice-now {
  margin: 12px 0 4px; padding: 13px 14px;
  background: linear-gradient(135deg, #eef4ff, #f6f2ff);
  border: 2px solid #dfe6ff; border-radius: var(--r-md);
}
.voice-now.bad { background: #fff8e6; border-color: #ffe1a0; }
/* 用上神经网络语音时的"好"状态：绿色，一眼看出跟机械音色的区别 */
.voice-now.good { background: linear-gradient(135deg, #eafaef, #f2fdf6); border-color: #a8e6bd; }
.voice-now.good .vn-name { color: #15803d; }
.vn-row { display: flex; align-items: flex-start; gap: 11px; }
.vn-ico { font-size: 24px; line-height: 1.1; flex: 0 0 auto; }
.vn-body { min-width: 0; flex: 1 1 auto; }
.vn-name {
  font-size: 14.5px; font-weight: 900; word-break: break-word;
  color: var(--p2);
}
.voice-now.bad .vn-name { color: #b45309; }
.vn-meta {
  font-size: 11.5px; color: var(--ink-3); font-weight: 700;
  margin-top: 4px; line-height: 1.55; word-break: break-word;
}
.vn-hint {
  margin-top: 10px; padding-top: 10px;
  border-top: 1px dashed #ffd88a;
  font-size: 12.5px; line-height: 1.7; color: #8a5b00;
}
.vn-hint b { color: #6b3d00; }
.vn-hint.good { border-top-color: #a8e6bd; color: #15803d; }
.vn-hint.good b { color: #14532d; }
.vn-hint code, .voice-warn code {
  background: rgba(0, 0, 0, .06); padding: 1px 5px; border-radius: 4px;
  font-size: 11.5px;
  font-family: ui-monospace, Menlo, Consolas, monospace;
}

.voice-warn {
  margin: 10px 0 4px;
  background: #fff8e6; border: 2px solid #ffe1a0;
  border-radius: var(--r-sm); padding: 11px 13px;
  font-size: 12.5px; line-height: 1.65; color: #8a5b00;
}
.voice-warn b { color: #6b3d00; }

/* 答题页的朗读按钮 */
.speak-row { display: flex; gap: 8px; margin-top: 12px; flex-wrap: wrap; }
.speak-row .qspeak { margin-top: 0; }
.qspeak.slow { background: #fff4e6; color: #b45309; }
.switch {
  width: 50px; height: 29px; border-radius: 99px; background: #ddd8ec;
  position: relative; transition: background .22s; flex: 0 0 auto;
}
.switch::after {
  content: ''; position: absolute; top: 3px; left: 3px;
  width: 23px; height: 23px; border-radius: 50%; background: #fff;
  box-shadow: 0 2px 5px rgba(0, 0, 0, .2); transition: transform .22s;
}
.switch.on { background: var(--green); }
.switch.on::after { transform: translateX(21px); }
/* 设置开着、但依赖的服务现在用不了（例如判题服务器没连上）：
   保持"开"的位置，只把颜色变淡，表示"开着但暂时不生效" */
.switch.on.pending { background: #a8d9bd; }
.switch.on.pending::after { opacity: .72; }

/* AI 判题页：把"程序到底探测到了什么"直接摊开写 */
.gprobe {
  margin-top: 10px; padding: 9px 12px; border-radius: 10px;
  background: #f6f4ff; border: 1px dashed #ded9f0;
  font-size: 11.5px; line-height: 1.75; color: var(--ink-2); word-break: break-all;
}
.gprobe code { background: #ece8ff; padding: 1px 5px; border-radius: 4px; font-size: 11px; }

/* 热力图 */
.heat { display: grid; grid-template-columns: repeat(auto-fill, minmax(13px, 1fr)); gap: 4px; }
.heat i { aspect-ratio: 1; border-radius: 3px; background: #eceaf7; display: block; }
.heat i.on { background: var(--p1); opacity: .75; }
.heat i.today { background: var(--gold); opacity: 1; }

/* 进度条通用 */
.bar-mini { height: 8px; border-radius: 99px; background: var(--p-soft); overflow: hidden; }
.bar-mini > i { display: block; height: 100%; border-radius: 99px; background: linear-gradient(90deg, var(--p1), var(--p2)); transition: width .5s; }

/* 空状态 */
.empty { text-align: center; padding: 44px 20px; color: var(--ink-3); }
.empty .eico { font-size: 56px; opacity: .45; }
.empty .etxt { font-size: 14px; font-weight: 800; margin-top: 14px; color: var(--ink-2); }
.empty .esub { font-size: 12px; margin-top: 6px; line-height: 1.6; }

/* ---------------- 弹层 ---------------- */
/* 层级必须高于 #modal-layer(95)：提示条如果压在弹窗遮罩底下，
   会连带被那层 rgba(40,34,70,.5) + blur 一起糊掉，弹窗里弹出的
   "名字不能为空" 之类就完全看不清了。 */
#toast-layer {
  position: fixed; left: 0; right: 0; top: 12px; z-index: 200;
  display: flex; flex-direction: column; align-items: center; gap: 8px;
  pointer-events: none;
}
.toast {
  background: rgba(47, 42, 74, .94); color: #fff;
  font-size: 13.5px; font-weight: 800;
  padding: 11px 20px; border-radius: 99px;
  box-shadow: 0 8px 22px rgba(0, 0, 0, .25);
  animation: toastIn .3s cubic-bezier(.34, 1.5, .64, 1) both;
  max-width: 88vw; text-align: center;
}
.toast.ok { background: linear-gradient(135deg, #22c55e, #16a34a); }
.toast.no { background: linear-gradient(135deg, #f43f5e, #e11d48); }
.toast.gold { background: linear-gradient(135deg, #ffc93c, #ff9f1c); color: #6b3d00; }
@keyframes toastIn {
  from { opacity: 0; transform: translateY(-16px) scale(.9); }
  to { opacity: 1; transform: none; }
}
.toast.out { animation: toastOut .3s ease forwards; }
@keyframes toastOut { to { opacity: 0; transform: translateY(-14px) scale(.92); } }

#modal-layer {
  position: fixed; inset: 0; z-index: 95;
  display: none; align-items: center; justify-content: center;
  background: rgba(40, 34, 70, .5); backdrop-filter: blur(3px);
  padding: 22px;
}
#modal-layer.show { display: flex; animation: screenIn .22s ease both; }
.modal {
  background: var(--card); border-radius: 26px;
  padding: 24px 20px; max-width: 400px; width: 100%;
  text-align: center; box-shadow: 0 20px 50px rgba(0, 0, 0, .3);
  animation: modalIn .34s cubic-bezier(.34, 1.5, .64, 1) both;
  max-height: 86vh; overflow-y: auto;
}
@keyframes modalIn {
  from { opacity: 0; transform: scale(.85) translateY(20px); }
  to { opacity: 1; transform: none; }
}
.modal .mico { font-size: 52px; line-height: 1; }
.modal h3 { margin: 12px 0 6px; font-size: 19px; font-weight: 900; }
.modal p { margin: 0; font-size: 13.5px; color: var(--ink-2); line-height: 1.65; }
.modal .macts { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; margin-top: 18px; }
.modal .macts .bigbtn { margin-top: 0; }
.modal .macts .full { grid-column: span 2; }
.ach-poplist { display: flex; flex-direction: column; gap: 10px; margin: 16px 0 4px; }
.ach-pop {
  display: flex; align-items: center; gap: 11px; text-align: left;
  background: linear-gradient(135deg, #fff8e6, #fff2cc);
  border-radius: var(--r-md); padding: 11px 14px;
}
.ach-pop .apico { font-size: 28px; }
.ach-pop .apname { font-size: 14px; font-weight: 900; }
.ach-pop .apdesc { font-size: 11.5px; color: var(--ink-3); margin-top: 2px; }

/* 彩带 */
.confetti {
  position: fixed; top: -12px; z-index: 80;
  width: 9px; height: 14px; border-radius: 2px;
  pointer-events: none;
  animation: fall linear forwards;
}
@keyframes fall {
  0% { transform: translateY(0) rotate(0); opacity: 1; }
  100% { transform: translateY(102vh) rotate(720deg); opacity: .85; }
}

/* 飘分 */
.floatscore {
  position: fixed; z-index: 85; font-size: 22px; font-weight: 900;
  pointer-events: none; animation: floatUp 1s ease-out forwards;
}
@keyframes floatUp {
  0% { opacity: 0; transform: translateY(0) scale(.6); }
  25% { opacity: 1; transform: translateY(-14px) scale(1.15); }
  100% { opacity: 0; transform: translateY(-70px) scale(1); }
}

/* 滚动条 */
#stage::-webkit-scrollbar { width: 5px; }
#stage::-webkit-scrollbar-thumb { background: #d8d3ee; border-radius: 99px; }
#stage::-webkit-scrollbar-track { background: transparent; }

/* 主题皮肤 */
body[data-theme="ocean"] { --p1: #38bdf8; --p2: #2563eb; --p-soft: #e0f2fe; --bg1: #eff9ff; --bg2: #eef6ff; }
body[data-theme="forest"] { --p1: #4ade80; --p2: #16a34a; --p-soft: #dcfce7; --bg1: #f0fdf4; --bg2: #ecfdf5; }
body[data-theme="sunset"] { --p1: #fb923c; --p2: #f43f5e; --p-soft: #ffe8d9; --bg1: #fff7ed; --bg2: #fff1f2; }
body[data-theme="candy"] { --p1: #f472b6; --p2: #a855f7; --p-soft: #fce7f3; --bg1: #fdf2f8; --bg2: #faf5ff; }
body[data-theme="night"] { --p1: #818cf8; --p2: #4f46e5; --p-soft: #e0e7ff; --bg1: #eef2ff; --bg2: #e8eaff; }

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation-duration: .01ms !important; transition-duration: .01ms !important; }
}

/* ---------------- 家庭成员档案 ---------------- */
.fam-list { display: flex; flex-direction: column; gap: 10px; }
.fam {
  display: flex; align-items: center; gap: 11px;
  padding: 11px 12px; border-radius: var(--r-md);
  background: #faf9ff; border: 2.5px solid transparent;
  transition: border-color .15s, background .15s;
}
.fam.active { background: linear-gradient(135deg, #f0ecff, #eef4ff); border-color: var(--p1); }
.fam-avatar {
  width: 42px; height: 42px; flex: 0 0 auto; border-radius: 50%;
  display: grid; place-items: center; font-size: 22px;
  background: linear-gradient(145deg, var(--p1), var(--p2));
  box-shadow: inset 0 -2px 6px rgba(0, 0, 0, .12);
}
.fam-body { flex: 1 1 auto; min-width: 0; }
.fam-name {
  font-size: 14.5px; font-weight: 900;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.fam-badge {
  font-size: 10px; font-weight: 900; color: #fff;
  background: var(--green); padding: 1.5px 7px; border-radius: 99px;
  vertical-align: 1.5px;
}
.fam-meta {
  font-size: 11px; color: var(--ink-3); font-weight: 700;
  margin-top: 3px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.fam-btn {
  flex: 0 0 auto; font-size: 12px; font-weight: 900;
  padding: 7px 13px; border-radius: 99px;
  background: #efeaf9; color: var(--ink-2);
}
.fam-btn.go { background: linear-gradient(135deg, var(--p1), var(--p2)); color: #fff; }
.fam-btn:active { transform: scale(.94); }
.fam-del {
  flex: 0 0 auto; width: 26px; height: 26px; border-radius: 50%;
  background: #fff0f3; color: var(--red); font-size: 13px; font-weight: 900;
  display: grid; place-items: center;
}
.fam-del:active { transform: scale(.9); }

/* ---------------- AI 判题 ---------------- */
.grading-card {
  text-align: center; padding: 26px 18px;
  background: var(--card); border-radius: var(--r-lg);
  box-shadow: var(--shadow); border: 2px solid rgba(255,255,255,.9);
}
.gspin {
  font-size: 44px; line-height: 1;
  animation: gspinPulse 1.1s ease-in-out infinite;
}
@keyframes gspinPulse {
  0%, 100% { transform: scale(1) rotate(-6deg); opacity: .85; }
  50% { transform: scale(1.18) rotate(6deg); opacity: 1; }
}
.gtext { font-size: 15.5px; font-weight: 900; margin-top: 12px; }
.gsub { font-size: 12px; color: var(--ink-3); margin-top: 6px; line-height: 1.6; }

.aicomment {
  background: linear-gradient(135deg, #eef4ff, #f3eeff);
  border-radius: var(--r-sm); padding: 9px 12px;
  font-size: 13px; font-weight: 700; color: var(--p2);
  margin-bottom: 9px; line-height: 1.6;
}

/* 判题状态行 */
.gstatus {
  display: flex; align-items: center; gap: 8px;
  font-size: 12.5px; font-weight: 800;
  padding: 11px 2px; border-bottom: 1px dashed var(--line);
}
.gdot {
  width: 9px; height: 9px; border-radius: 50%; flex: 0 0 auto;
  background: var(--ink-3);
}
.gstatus.on { color: #15803d; }
.gstatus.on .gdot { background: var(--green); box-shadow: 0 0 0 4px rgba(34,197,94,.16); }
.gstatus.warn { color: #b45309; }
.gstatus.warn .gdot { background: var(--gold); box-shadow: 0 0 0 4px rgba(255,183,3,.18); }
.gstatus.off { color: var(--ink-3); }
.gstatus.wait .gdot { background: var(--p1); animation: pulse 1.2s infinite; }

.gdesc {
  font-size: 11.5px; color: var(--ink-3); line-height: 1.7;
  padding: 10px 2px 2px;
}
.gdesc b { color: var(--ink-2); }

.voice-warn code {
  display: inline-block;
  background: rgba(0,0,0,.06); border-radius: 5px;
  padding: 1px 6px; margin: 2px 0;
  font-family: ui-monospace, Menlo, Consolas, monospace;
  font-size: 11.5px; word-break: break-all;
}

/* ---------------- 题型 / 难度 / 能力 标签 ---------------- */
.qmeta-row { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; margin-bottom: 10px; }
.qmeta-row .qtype { margin-bottom: 0; }
.qtype.multi { background: #f3e8ff; color: #7c3aed; }
.qtype.order { background: #e0f7fa; color: #0e7490; }
.tier-badge, .skill-badge {
  font-size: 10.5px; font-weight: 900; padding: 3px 9px; border-radius: 99px;
}
.tier-badge.base { background: #eef2ff; color: #4f46e5; }
.tier-badge.extend { background: linear-gradient(135deg, #fff1d6, #ffe0b2); color: #b45309; }
.skill-badge { background: #f1f0f7; color: var(--ink-3); }

/* ---------------- 多选题 ---------------- */
.opt.multi .key.box {
  border-radius: 7px; background: #fff; border: 2.5px solid var(--line);
  color: transparent; font-size: 14px;
}
.opt.multi.picked { border-color: var(--p1); background: #f5f2ff; }
.opt.multi.picked .key.box { background: var(--p1); border-color: var(--p1); color: #fff; }
.pick-hint { font-size: 11.5px; color: var(--ink-3); text-align: center; margin: 12px 0 8px; }

/* ---------------- 排序题 ---------------- */
.order-wrap { margin-top: 4px; }
.order-slots {
  display: flex; flex-wrap: wrap; gap: 8px; align-items: center;
  min-height: 62px; padding: 12px 13px; border-radius: var(--r-md);
  background: #faf9ff; border: 2.5px dashed #d8d3ee;
}
.order-slots.empty { justify-content: center; }
.order-hint { font-size: 12.5px; color: var(--ink-3); font-weight: 700; }
.order-pool { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 12px; }
.order-chip {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: 15px; font-weight: 800; color: var(--ink);
  background: var(--card); border: 2.5px solid var(--line);
  border-radius: 99px; padding: 10px 16px;
  box-shadow: 0 3px 0 rgba(120,105,200,.10);
  transition: transform .12s, border-color .15s, background .15s;
}
.order-chip:active { transform: scale(.95); }
.order-chip b {
  display: inline-grid; place-items: center;
  width: 19px; height: 19px; border-radius: 50%;
  background: var(--p1); color: #fff; font-size: 11px;
}
.order-chip.placed { background: linear-gradient(135deg,#f0ecff,#eef4ff); border-color: var(--p1); }
.order-chip.used { opacity: .35; }
.order-actions { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; margin-top: 12px; }
.order-actions .bigbtn { margin-top: 0; }

/* ---------------- 能力条 ---------------- */
.skill-row { display: flex; align-items: center; gap: 10px; padding: 9px 2px; }
.skill-name { font-size: 12.5px; font-weight: 900; width: 42px; flex: 0 0 auto; }
.skill-track {
  flex: 1 1 auto; height: 12px; border-radius: 99px;
  background: var(--p-soft); overflow: hidden;
}
.skill-track > i {
  display: block; height: 100%; border-radius: 99px;
  transition: width .6s cubic-bezier(.34,1.4,.64,1);
}
.skill-row .skill-pct {
  font-size: 11.5px; font-weight: 900; color: var(--ink-2);
  width: 62px; text-align: right; flex: 0 0 auto;
}

/* ---------------- 题库总览 ---------------- */
.bk-stat-row { display: flex; gap: 8px; }
.bk-stat {
  flex: 1 1 0; text-align: center;
  background: #faf9ff; border-radius: var(--r-sm); padding: 10px 6px;
}
.bk-stat .bsv { font-size: 20px; font-weight: 900; color: var(--p2); }
.bk-stat .bsl { font-size: 10.5px; color: var(--ink-3); font-weight: 700; margin-top: 2px; }

.bk-level-head { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.bk-level-head b { font-size: 15px; font-weight: 900; }
.bk-pool {
  font-size: 10.5px; font-weight: 800; color: var(--ink-3);
  background: #f1f0f7; padding: 3px 9px; border-radius: 99px;
}
.bk-stars { margin-left: auto; font-size: 13px; letter-spacing: 1px; }

.bk-list { margin-top: 12px; display: flex; flex-direction: column; gap: 8px; }
.bk-q {
  background: #faf9ff; border-radius: var(--r-sm);
  border: 2px solid var(--line); overflow: hidden;
}
.bk-q[open] { border-color: var(--p1); background: #fff; }
.bk-q > summary {
  display: flex; align-items: flex-start; gap: 9px;
  padding: 11px 12px; cursor: pointer; list-style: none;
}
.bk-q > summary::-webkit-details-marker { display: none; }
.bk-idx {
  flex: 0 0 auto; width: 22px; height: 22px; border-radius: 50%;
  background: var(--p-soft); color: var(--p2);
  font-size: 11px; font-weight: 900; display: grid; place-items: center;
  margin-top: 1px;
}
.bk-main { flex: 1 1 auto; min-width: 0; }
.bk-badges { display: flex; gap: 5px; flex-wrap: wrap; margin-bottom: 5px; }
.bk-text { display: block; font-size: 13.5px; font-weight: 700; line-height: 1.6; }
.bk-caret { flex: 0 0 auto; color: var(--ink-3); font-size: 13px; transition: transform .2s; }
.bk-q[open] .bk-caret { transform: rotate(180deg); }
.bk-body { padding: 0 12px 12px 43px; }
.bk-opts { display: flex; flex-direction: column; gap: 4px; margin-bottom: 8px; }
.bk-opt {
  font-size: 12.5px; font-weight: 700; color: var(--ink-2);
  padding: 6px 10px; border-radius: 8px; background: #f4f2fb;
}
.bk-opt.right { background: #eafaf0; color: #15803d; }
.bk-explain { font-size: 12px; color: var(--ink-3); line-height: 1.65; }

/* ---------------- 错题本按学科分组 ---------------- */
.wrong-group { margin-bottom: 18px; }
.wrong-head {
  display: flex; align-items: center; gap: 9px;
  padding: 11px 15px; border-radius: var(--r-md) var(--r-md) 0 0;
  color: #fff; font-weight: 900;
  box-shadow: 0 4px 12px rgba(80, 70, 160, .18);
}
.wrong-head .wh-ico { font-size: 20px; line-height: 1; }
.wrong-head .wh-name { font-size: 15px; flex: 1 1 auto; }
.wrong-head .wh-count {
  font-size: 11.5px; background: rgba(255,255,255,.26);
  padding: 3px 11px; border-radius: 99px;
}
.wrong-group .review-item:first-of-type { border-radius: 0; margin-top: 0; }

/* ---------------- 新版本提示条 ---------------- */
#update-banner {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 96;
  display: flex; align-items: center; gap: 11px;
  padding: 13px 16px calc(13px + env(safe-area-inset-bottom, 0px));
  background: linear-gradient(135deg, #ffc93c, #ff9f1c);
  color: #6b3d00;
  box-shadow: 0 -6px 22px rgba(180, 110, 0, .28);
  animation: bannerUp .35s cubic-bezier(.34,1.4,.64,1) both;
}
@keyframes bannerUp {
  from { transform: translateY(100%); }
  to { transform: none; }
}
#update-banner .ub-ico { font-size: 24px; flex: 0 0 auto; }
#update-banner .ub-body { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; }
#update-banner .ub-body b { font-size: 14px; font-weight: 900; }
#update-banner .ub-sub { font-size: 11.5px; margin-top: 2px; line-height: 1.5; opacity: .9; }
#update-banner .ub-btn {
  flex: 0 0 auto;
  background: #6b3d00; color: #ffd76e;
  font-size: 13px; font-weight: 900;
  padding: 9px 16px; border-radius: 99px;
  box-shadow: 0 3px 0 rgba(0,0,0,.2);
}
#update-banner .ub-btn:active { transform: translateY(2px); box-shadow: none; }

/* ---------------- 使用统计：同意提示条 ---------------- */
/* 做成底部小条而不是弹窗：小学生家长看到全屏同意框大概率直接关掉。
   它是 fixed 定位，不占页面流，不挡操作。 */
/* 同意条不是浮层，是 #app 这个 flex 列里的一格，占在正文和底部导航之间。
   这样它不会被任何遮罩盖住、不会被底部导航压住，也不会跟着正文滚走。
   （以前是 position:fixed + z-index:60，结果首次进入时被引导弹窗的
    全屏遮罩 z-index:95 盖得一点都看不见 —— 那正是最需要它出现的时候。） */
#consent-layer { flex: 0 0 auto; padding: 0 10px 10px; }
#consent-layer:empty { display: none; }
.consent-bar {
  display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
  padding: 12px 14px; border-radius: var(--r-md);
  background: rgba(255, 255, 255, .97);
  border: 2px solid #ddd8ee;
  box-shadow: 0 10px 30px rgba(60, 50, 110, .18);
  backdrop-filter: blur(8px);
  animation: consentIn .28s cubic-bezier(.34, 1.4, .64, 1);
}
@keyframes consentIn { from { transform: translateY(120%); opacity: 0; } to { transform: none; opacity: 1; } }
.consent-bar .cb-ico { font-size: 20px; flex: 0 0 auto; }
.consent-bar .cb-body { flex: 1 1 260px; min-width: 0; }
.consent-bar .cb-title { font-size: 13px; font-weight: 900; }
.consent-bar .cb-desc { font-size: 11.5px; color: var(--ink-3); line-height: 1.6; margin-top: 3px; }
.consent-bar .cb-desc b { color: var(--p2); }
.consent-bar .cb-acts { display: flex; gap: 8px; flex-wrap: wrap; }
.cb-btn {
  font-family: inherit; font-size: 12.5px; font-weight: 800;
  padding: 8px 14px; border-radius: 99px; cursor: pointer;
  background: #f1eefb; color: var(--ink-2); border: none;
}
.cb-btn:active { transform: scale(.95); }
.cb-btn.primary { background: linear-gradient(135deg, var(--p1), var(--p2)); color: #fff; }
.cb-btn.link { background: transparent; color: var(--ink-3); text-decoration: underline; padding: 8px 6px; }

/* 隐私说明页 */
.pv-h {
  font-size: 13px; font-weight: 900; color: var(--p2);
  margin: 16px 0 6px;
}
.pv-ul { margin: 0 0 4px; padding-left: 20px; }
.pv-ul li { margin: 5px 0; }
.pv-ul code, .card code {
  background: #f1eefb; padding: 1px 5px; border-radius: 4px;
  font-family: ui-monospace, Menlo, Consolas, monospace; font-size: 12px;
}

/* 错题本里的「间隔重复」状态标签 */
.srs-tag { font-weight: 900; }
.srs-tag.due { color: #b45309; }
.srs-tag.near { color: #15803d; }

/* ---------------- 学习周报 ---------------- */
.rep-hero {
  display: grid; grid-template-columns: repeat(3, 1fr); gap: 10px;
  margin: 2px 0 12px;
}
.rep-big {
  background: var(--card); border-radius: var(--r-md);
  padding: 15px 8px; text-align: center;
  box-shadow: 0 2px 10px rgba(90, 78, 150, .07);
}
.rep-big-num { font-size: 27px; font-weight: 900; color: var(--p2); line-height: 1.1; }
.rep-big-num .u { font-size: 13px; margin-left: 1px; }
.rep-big-label { font-size: 11.5px; color: var(--ink-3); font-weight: 700; margin-top: 5px; }
.rep-d { font-weight: 900; margin-left: 4px; }
.rep-d.up { color: #16a34a; }
.rep-d.down { color: var(--red); }
.rep-d.flat { color: var(--ink-3); }
.rep-sub {
  text-align: center; font-size: 12.5px; color: var(--ink-2);
  font-weight: 700; margin: -4px 0 14px;
}
.rep-sub b { color: var(--p2); }
.rep-note {
  background: var(--p-soft); border-radius: var(--r-md);
  padding: 10px 14px; font-size: 12px; color: var(--ink-2);
  line-height: 1.6; margin-bottom: 12px;
}
.rep-card { margin-bottom: 12px; }
.rep-h { font-size: 14px; font-weight: 900; margin-bottom: 12px; }
.rep-kp { margin-bottom: 13px; }
.rep-kp:last-child { margin-bottom: 4px; }
.rep-kp-name { font-size: 12.5px; font-weight: 800; margin-bottom: 5px; }
.rep-kp-bar {
  height: 7px; background: var(--line); border-radius: 99px; overflow: hidden;
}
.rep-kp-bar i {
  display: block; height: 100%; border-radius: 99px;
  background: linear-gradient(90deg, #a7f3d0, #22c55e);
}
.rep-kp-bar.low i { background: linear-gradient(90deg, #fecdd3, #fb7185); }
.rep-kp-num { font-size: 11.5px; font-weight: 800; margin-top: 4px; }
.rep-kp-num .was { color: var(--ink-3); }
.rep-kp-num .now { color: #16a34a; }
.rep-kp-num .low { color: var(--red); }
.rep-tip {
  font-size: 11.5px; color: var(--ink-3); line-height: 1.6;
  margin-top: 6px; padding-top: 10px; border-top: 1px dashed var(--line);
}
.rep-sub-row {
  display: flex; align-items: center; gap: 9px;
  padding: 8px 0; font-size: 13px;
  border-bottom: 1px solid var(--line);
}
.rep-sub-row:last-child { border-bottom: none; }
.rep-sub-ico { font-size: 17px; }
.rep-sub-name { font-weight: 800; flex: 1; min-width: 0; }
.rep-sub-num { font-size: 12px; color: var(--ink-3); font-weight: 700; }

/* ---------------- 知识星球 ---------------- */
.pl-card { padding: 14px 16px 16px; }
.pl-head { display: flex; align-items: baseline; justify-content: space-between; margin-bottom: 6px; }
.pl-title { font-size: 14px; font-weight: 900; }
.pl-progress { font-size: 12px; font-weight: 900; color: var(--p2); }
.pl-stage {
  position: relative; width: 100%; max-width: 260px;
  aspect-ratio: 1 / 1; margin: 4px auto 10px;
}
.pl-stage.big { max-width: 300px; }
.pl-globe {
  position: absolute; inset: 17%; border-radius: 50%;
  background: radial-gradient(circle at 34% 28%, #b9a9ff, #7c6cf0 46%, #4c3fae);
  box-shadow: inset -12px -10px 26px rgba(0, 0, 0, .28),
              0 8px 26px rgba(124, 108, 240, .35);
}
.pl-ring {
  position: absolute; left: -22%; top: 44%; width: 144%; height: 22%;
  border: 3px solid rgba(255, 255, 255, .3);
  border-radius: 50%; transform: rotate(-18deg);
}
.pl-spot {
  position: absolute; width: 30px; height: 30px; margin: -15px 0 0 -15px;
  border-radius: 50%; display: grid; place-items: center;
  background: rgba(255, 255, 255, .9);
  box-shadow: 0 2px 6px rgba(60, 40, 140, .22);
  font-size: 17px; line-height: 1;
  transition: transform .15s;
}
.pl-spot .pl-ico { display: block; transform: translateY(-1px); }
.pl-spot.built {
  background: #fff; box-shadow: 0 0 0 2px #ffd76a, 0 3px 9px rgba(200, 140, 0, .35);
  animation: plPop .4s cubic-bezier(.34, 1.5, .64, 1) both;
}
@keyframes plPop { from { transform: scale(.3); } to { transform: scale(1); } }
.pl-spot.locked {
  background: rgba(255, 255, 255, .16);
  box-shadow: none; color: rgba(255, 255, 255, .5);
  font-size: 15px;
}
.pl-spot.ready {
  background: #fffbe8; box-shadow: 0 0 0 2px #ffc93c, 0 3px 9px rgba(200, 140, 0, .3);
  animation: duePulse 2s ease-in-out infinite;
}
.pl-spot.needCoins { background: rgba(255, 255, 255, .5); }

/* 首页那条"今天有客人来" —— 只有一行，不是入口卡片 */
.pl-strip {
  display: flex; align-items: center; gap: 10px; width: 100%;
  font-family: inherit; text-align: left; cursor: pointer;
  margin: 0 0 13px; padding: 11px 14px;
  border-radius: var(--r-md);
  background: linear-gradient(135deg, #fff6e0, #ffe9c2);
  border: 1.5px solid rgba(255, 190, 80, .45);
  box-shadow: 0 6px 16px -10px rgba(200, 140, 20, 1);
  animation: plStripIn .4s cubic-bezier(.34, 1.4, .64, 1) both;
}
@keyframes plStripIn { from { opacity: 0; transform: translateY(-6px); } }
.pl-strip:active { transform: translateY(2px); }
.pl-strip .pls-ico { font-size: 24px; line-height: 1; flex: 0 0 auto; }
.pl-strip .pls-body { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; }
.pl-strip .pls-name { font-size: 12.5px; font-weight: 900; color: #8a5a12; }
.pl-strip .pls-line { font-size: 11px; color: #a9762a; margin-top: 2px; line-height: 1.4; }
.pl-strip .pls-coin {
  flex: 0 0 auto; font-size: 12px; font-weight: 900; color: #7a4b00;
  padding: 4px 11px; border-radius: 99px;
  background: linear-gradient(180deg, #ffe9a8, #ffc93c);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .7);
}

.pl-visitor {
  display: flex; align-items: center; gap: 11px; width: 100%;
  background: linear-gradient(135deg, #fff9e8, #fff3d1);
  border: 2px solid #ffe1a0; border-radius: var(--r-md);
  padding: 10px 13px; text-align: left; cursor: pointer;
  animation: plPop .35s cubic-bezier(.34, 1.5, .64, 1) both;
}
.pl-visitor .pv-ico { font-size: 26px; line-height: 1; }
.pl-visitor .pv-body { flex: 1; min-width: 0; display: block; }
.pl-visitor .pv-name { display: block; font-size: 13px; font-weight: 900; color: #7c4a00; }
.pl-visitor .pv-line { display: block; font-size: 11px; color: #a06a1a; margin-top: 2px; line-height: 1.4; }
.pl-visitor .pv-coin { font-size: 13px; font-weight: 900; color: #b45309; white-space: nowrap; }
.pl-empty {
  font-size: 11.5px; color: var(--ink-3); text-align: center;
  line-height: 1.6; padding: 2px 0 4px;
}
.pl-next {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  width: 100%; margin-top: 10px; padding: 11px 14px;
  border-radius: var(--r-md); border: none;
  background: var(--p-soft); color: var(--p2);
  font-size: 12.5px; font-weight: 800; text-align: left; cursor: pointer;
}
.pl-next.ready { background: linear-gradient(135deg, #ffc93c, #ff9f1c); color: #6b3d00; }
.pl-next.done { background: #eafaef; color: #15803d; }
.pl-next-num { font-size: 11.5px; opacity: .85; white-space: nowrap; }
.pl-bar { height: 8px; background: var(--line); border-radius: 99px; overflow: hidden; margin-top: 2px; }
.pl-bar i { display: block; height: 100%; border-radius: 99px;
  background: linear-gradient(90deg, #c4b5fd, #7c6cf0); }
.pl-bar-txt { font-size: 11.5px; color: var(--ink-3); font-weight: 700; text-align: center; margin-top: 7px; }

.pl-list { display: flex; flex-direction: column; gap: 9px; }
.pl-item {
  display: flex; align-items: center; gap: 11px;
  background: var(--card); border-radius: var(--r-md);
  padding: 11px 13px; box-shadow: 0 2px 10px rgba(90, 78, 150, .06);
}
.pl-item.built { background: linear-gradient(135deg, #fffdf4, #fff8e4); }
.pl-item.locked { opacity: .72; }
.pli-ico { font-size: 25px; width: 32px; text-align: center; flex: 0 0 auto; }
.pli-body { flex: 1; min-width: 0; }
.pli-name { font-size: 13.5px; font-weight: 900; }
.pli-done { font-size: 10.5px; color: #15803d; font-weight: 800; margin-left: 6px; }
.pli-need { font-size: 11px; color: var(--ink-3); margin-top: 2px; line-height: 1.5; }
.pli-prog { height: 5px; background: var(--line); border-radius: 99px; overflow: hidden; margin-top: 6px; }
.pli-prog i { display: block; height: 100%; border-radius: 99px;
  background: linear-gradient(90deg, #c4b5fd, #7c6cf0); }
.pli-act { flex: 0 0 auto; }
.pli-btn {
  font-size: 11.5px; font-weight: 900; padding: 8px 12px;
  border-radius: 99px; border: none; cursor: pointer; white-space: nowrap;
}
.pli-btn.ready { background: linear-gradient(135deg, #ffc93c, #ff9f1c); color: #6b3d00; }
.pli-btn.needCoins { background: var(--line); color: var(--ink-3); }
.pli-btn.locked { background: var(--line); color: var(--ink-3); }

/* ---------------- 「还是不懂」讲题区 ----------------
   家长讲不清、孩子看解析还是不懂时的出口。 */
.explain {
  margin-top: 11px; padding-top: 11px;
  border-top: 1px dashed rgba(0, 0, 0, .12);
}
.ex-btn {
  display: block; width: 100%;
  font-family: inherit; font-size: 13px; font-weight: 800;
  padding: 10px 14px; border-radius: var(--r-md);
  border: 2px solid var(--line); background: #fff; color: var(--ink-2);
  cursor: pointer;
}
.ex-btn.main { border-color: #c7bdf7; color: var(--p2); background: #f7f5ff; }
.ex-btn:active { transform: translateY(1px); }
.ex-loading {
  font-size: 12.5px; font-weight: 700; color: var(--ink-3);
  text-align: center; padding: 8px 0;
}
.ex-head { font-size: 12.5px; font-weight: 900; color: var(--p2); margin-bottom: 6px; }
.ex-text {
  font-size: 13.5px; line-height: 1.75; color: var(--ink);
  background: #f7f5ff; border-radius: var(--r-md); padding: 11px 13px;
  white-space: pre-wrap;
}
.ex-acts { margin-top: 9px; }
.ex-hint { font-size: 11.5px; color: var(--ink-3); line-height: 1.6; }

/* ---------------- 家长布置任务 ---------------- */
.ptask {
  background: linear-gradient(135deg, #fff8e8, #fff2d6);
  border: 2px solid #ffe1a0; border-radius: var(--r-md);
  padding: 12px 15px; margin-bottom: 12px;
}
.ptask.done { background: linear-gradient(135deg, #eafaef, #f2fdf6); border-color: #a8e6bd; }
.pt-head { display: flex; align-items: center; gap: 7px; }
.pt-ico { font-size: 17px; }
.pt-title { flex: 1; min-width: 0; font-size: 13px; font-weight: 900; color: #7c4a00; }
.ptask.done .pt-title { color: #15803d; }
.pt-num { font-size: 12px; font-weight: 900; color: #b45309; }
.ptask.done .pt-num { color: #15803d; }
.pt-label { font-size: 13.5px; font-weight: 800; color: var(--ink); margin: 7px 0 8px; }
.pt-bar { height: 7px; background: rgba(0, 0, 0, .08); border-radius: 99px; overflow: hidden; }
.pt-bar i { display: block; height: 100%; border-radius: 99px;
  background: linear-gradient(90deg, #ffd76a, #ff9f1c); transition: width .35s; }
.ptask.done .pt-bar i { background: linear-gradient(90deg, #a7f3d0, #22c55e); }
.pt-foot { font-size: 11px; color: #a06a1a; margin-top: 6px; }
/* 任务卡上"现在就开始"的按钮：原来这张卡一个能点的地方都没有 */
.pt-go {
  display: block; width: 100%; margin-top: 10px;
  font-family: inherit; font-size: 13.5px; font-weight: 900;
  padding: 11px 14px; border-radius: var(--r-md); cursor: pointer;
  color: #fff; text-align: center;
  background: linear-gradient(135deg, #ffb020, #ff7a45);
  box-shadow: 0 4px 0 rgba(180, 90, 10, .35), 0 8px 18px -10px rgba(255, 130, 40, .9);
  transition: transform .1s, box-shadow .1s;
}
.pt-go:active { transform: translateY(3px); box-shadow: 0 1px 0 rgba(180, 90, 10, .3); }
.ptask.done .pt-foot { color: #15803d; }

.pt-now { background: var(--p-soft); border-radius: var(--r-md); padding: 12px 14px; }
.pt-now.done { background: #eafaef; }
.ptn-row { display: flex; justify-content: space-between; align-items: center;
  font-size: 13px; font-weight: 800; gap: 10px; }
.pt-now.done .ptn-row { color: #15803d; }
.ptn-foot { font-size: 11px; color: var(--ink-3); margin-top: 7px; }
.pt-hist { border-top: 1px dashed var(--line); margin-top: 4px; }
.pt-hrow { display: flex; justify-content: space-between; align-items: center;
  font-size: 12px; padding: 7px 0; border-bottom: 1px solid var(--line); }
.pt-hrow:last-child { border-bottom: none; }
.pt-hdate { color: var(--ink-3); font-size: 11px; }

/* ---------------- 英语跟读打分 ----------------
   家长不敢教发音，这件事只有 App 能替。 */
.qspeak.read {
  background: linear-gradient(135deg, #ffe9c9, #ffd9a0);
  color: #7c4a00; border-color: #ffcf87;
}
.read-box {
  display: flex; align-items: center; gap: 11px; flex-wrap: wrap;
  margin-top: 9px; padding: 12px 14px;
  background: #fff; border: 2px solid var(--line);
  border-radius: var(--r-md);
}
.read-box.recording { border-color: #f0a6b4; background: #fff6f8; }
.read-box.scored { display: block; }
.rb-mic { font-size: 24px; line-height: 1; }
.read-box.recording .rb-mic { animation: rbPulse 1s ease-in-out infinite; }
@keyframes rbPulse { 0%, 100% { transform: scale(1); } 50% { transform: scale(1.22); } }
.rb-body { flex: 1; min-width: 0; }
.rb-title { font-size: 13px; font-weight: 900; }
.rb-sub { font-size: 11px; color: var(--ink-3); margin-top: 2px; }
.rb-btn {
  font-family: inherit; font-size: 12.5px; font-weight: 800;
  padding: 8px 14px; border-radius: 99px; cursor: pointer;
  border: 2px solid var(--line); background: #fff; color: var(--ink-2);
}
.rb-btn.stop { background: linear-gradient(135deg, #f43f5e, #e11d48); color: #fff; border: none; }
.rb-btn:active { transform: translateY(1px); }
.rb-score { font-size: 34px; font-weight: 900; text-align: center; line-height: 1.1; }
.rb-score .rb-unit { font-size: 14px; margin-left: 2px; }
.rb-metrics {
  display: flex; justify-content: center; gap: 14px;
  font-size: 11.5px; color: var(--ink-3); font-weight: 700; margin-top: 6px;
}
.rb-words {
  display: flex; flex-wrap: wrap; gap: 6px; justify-content: center;
  margin-top: 11px; line-height: 1.6;
}
.rb-word {
  font-size: 14px; font-weight: 800; padding: 2px 7px; border-radius: 6px;
  background: #f3f1fb; color: var(--ink-2);
}
.rb-word.ok { background: #eafaef; color: #15803d; }
.rb-word.low { background: #fff4e5; color: #b45309; }
.rb-word.missed { background: #fff1f3; color: #e11d48; text-decoration: line-through; }
.rb-comment { font-size: 12px; color: var(--ink-2); text-align: center; margin-top: 10px; line-height: 1.6; }
.rb-acts { display: flex; gap: 8px; justify-content: center; margin-top: 11px; flex-wrap: wrap; }

/* ---------------- 家长中心 + 门禁 ---------------- */
.pg-wrap { text-align: center; padding: 30px 20px 20px; }
.pg-ico { font-size: 46px; line-height: 1; }
.pg-title { font-size: 17px; font-weight: 900; margin-top: 12px; }
.pg-sub { font-size: 12.5px; color: var(--ink-3); line-height: 1.7; margin-top: 8px; }
.pg-q { font-size: 26px; font-weight: 900; color: var(--p2); margin: 22px 0 12px; letter-spacing: 1px; }
.pg-input { max-width: 220px; margin: 0 auto; text-align: center; font-size: 20px !important; }
.pg-err { font-size: 12.5px; font-weight: 800; color: var(--red); margin-top: 9px; }
.pg-wrap .bigbtn { max-width: 220px; margin: 16px auto 0; }
.pg-tip { font-size: 11.5px; color: var(--ink-3); margin-top: 16px; }
.pg-lock {
  font-family: inherit; font-size: 11.5px; font-weight: 800;
  border: none; background: var(--line); color: var(--ink-2);
  padding: 5px 11px; border-radius: 99px; cursor: pointer;
}
.ptn-who { font-size: 11.5px; font-weight: 900; color: var(--p2); margin-bottom: 5px; }
.ptn-note {
  font-size: 12.5px; color: var(--ink-2); margin-top: 8px;
  padding-left: 9px; border-left: 3px solid var(--p1); line-height: 1.6;
}
.pt-from { font-size: 11px; color: #a06a1a; font-weight: 800; margin-bottom: 3px; }
.ptask.done .pt-from { color: #15803d; }
.pt-note {
  font-size: 12.5px; color: var(--ink-2); margin: 6px 0 8px;
  padding-left: 9px; border-left: 3px solid var(--p1); line-height: 1.6;
}

/* ---------------- 英语跟读（独立模块） ----------------
   跟读的入口只在「探索」页（首页不再放第二份），所以首页那个
   大卡片入口（.ai-entry / .read-entry）的样式整块删掉了。 */
.rd-card { padding: 16px 18px; }
.rd-head { display: flex; align-items: baseline; justify-content: space-between; gap: 10px; margin-bottom: 12px; }
.rd-unit { font-size: 11.5px; font-weight: 800; color: var(--ink-3); }
.rd-count { font-size: 11.5px; font-weight: 900; color: var(--p2); white-space: nowrap; }
.rd-en { font-size: 21px; font-weight: 800; line-height: 1.5; letter-spacing: .2px; }
.rd-ipa {
  font-size: 13.5px; color: var(--p2); margin-top: 7px;
  font-family: "Segoe UI", "Lucida Sans Unicode", system-ui, sans-serif;
  letter-spacing: .3px; line-height: 1.5; word-break: break-word;
}
.rd-zh { font-size: 13.5px; color: var(--ink-2); margin-top: 7px; line-height: 1.6; }
.rd-best {
  font-size: 11.5px; color: var(--ink-3); margin-top: 11px;
  padding-top: 10px; border-top: 1px dashed var(--line);
}
.rd-best b { color: #16a34a; font-size: 14px; }
.rd-nav { display: flex; gap: 10px; margin-top: 14px; }
.rd-btn {
  flex: 1; font-family: inherit; font-size: 13.5px; font-weight: 800;
  padding: 12px; border-radius: var(--r-md); cursor: pointer;
  border: 2px solid var(--line); background: #fff; color: var(--ink-2);
}
.rd-btn.go { background: var(--p-soft); border-color: #c7bdf7; color: var(--p2); }
.rd-btn:disabled { opacity: .4; cursor: default; }
.rd-btn:active:not(:disabled) { transform: translateY(1px); }

/* ---------------- 扫描导入读物 ---------------- */
.scan-btn {
  background: linear-gradient(135deg, #7c6cf0, #5b8def);
  color: #fff; margin-top: 4px;
}
.scan-btn:disabled { opacity: .6; }
.scan-note {
  font-size: 12.5px; line-height: 1.6; text-align: center;
  margin: 10px 0 2px; padding: 9px 12px; border-radius: var(--r-md);
}
.scan-note.ok { background: #eafaef; color: #15803d; font-weight: 700; }
.scan-note.bad { background: #fff1f3; color: #e11d48; font-weight: 700; }
.rd-units {
  flex-wrap: nowrap; overflow-x: auto; margin-bottom: 14px;
  padding-bottom: 2px;
  -webkit-overflow-scrolling: touch; scrollbar-width: none;
}
.rd-units::-webkit-scrollbar { display: none; }
.rd-units .chip {
  flex: 0 0 auto;
  /* 单元按钮小一号：6 个单元要尽量一屏放下 —— 藏起来还得让人知道能滑，
     不如直接都摆出来 */
  font-size: 10.5px; padding: 5px 8px; letter-spacing: -.2px;
}

/* 显示开关：一行两个，紧凑 */
.rd-toggles {
  display: flex; align-items: center; gap: 8px;
  margin-top: 6px; padding: 10px 14px !important;
}
.rd-tg {
  flex: 1 1 0; min-width: 0;
  display: flex; align-items: center; justify-content: space-between; gap: 8px;
}
.rd-tg-name { font-size: 12.5px; font-weight: 800; color: var(--ink-2); white-space: nowrap; }

.rd-del {
  font-family: inherit; font-size: 11px; font-weight: 800;
  border: none; background: transparent; color: var(--red);
  cursor: pointer; padding: 2px 6px;
}

/* ---------------- 探索 & 宠物 ---------------- */
.ex-badge {
  font-size: 11.5px; font-weight: 900; color: var(--p2);
  background: var(--p-soft); padding: 3px 9px; border-radius: 99px;
  margin-right: 6px; white-space: nowrap;
}

/* ============================================================
 * 宠物小天地：纯 CSS 等距 3D
 *
 * 不用 WebGL、不用 canvas、不用任何图片 —— 只有 perspective、
 * rotateX(65deg) rotate(45deg) 和一层层 translateZ 堆出来的立体地面。
 * 原理和几个关键数字都写在 js/core/habitat.js 顶部。
 *
 * 改这个文件时最容易踩的两个坑：
 *   1) 地面是斜的，立在上面的东西必须用 rotateZ(-45deg) rotateX(-65deg)
 *      抵消掉，否则会跟着躺倒。抵消的原点必须**正好落在格子中心**
 *      （所以 .hab-bb 是个 0×0 的盒子），否则立牌会整体偏出去。
 *   2) transform-style: preserve-3d 不会继承。中间任何一层忘了写，
 *      整棵子树就被压平，立牌全部躺倒。
 * ============================================================ */
.hab {
  /* 一个格子的边长，整个场景的度量单位。
     7 格的方块转成等距菱形之后，宽度 = 7×√2×格子 ≈ 9.9×格子，
     而可用宽度 = 100vw - 页面左右内边距(28) - 相框内边距(10) - 余量(6)。
     以前这里写的是 10.1vw，没算这一步 —— 菱形比框宽 38px，
     左右两个角一直被 overflow:hidden 裁掉（草皮是空的，截图上看不出来）。 */
  --hu: min(calc((100vw - 44px) / 9.9), 42px);
  --soil: calc(var(--hu) * .8);     /* 岛的泥土厚度 */
  position: relative;
  height: calc(var(--hu) * 7.5);
  margin: 4px 0 12px;
  border-radius: var(--r-lg);
  overflow: hidden;
  background: linear-gradient(180deg, var(--sky1), var(--sky2) 58%, var(--sky3));
  box-shadow: inset 0 -14px 30px rgba(40, 30, 90, .10);
}

/* 动画总开关：设置里关掉动效，或者系统要求减少动效，就全停 */
.hab[data-anim="0"] *,
.hab[data-anim="0"] *::before,
.hab[data-anim="0"] *::after { animation: none !important; }
@media (prefers-reduced-motion: reduce) {
  .hab *, .hab *::before, .hab *::after { animation: none !important; }
}

/* ---------------- 天空 ---------------- */
.hab-sky { position: absolute; inset: 0; }
.hab[data-night="1"] .hab-sky { filter: saturate(.92) brightness(.88); }
/* 白天的蓝天到了夜里要真的暗下来；本来就暗的地块（月面/火山/夜林）
   不再压第二层，否则会糊成一团黑 */
.hab[data-night="1"][data-dark="0"] .hab-sky::after {
  content: ''; position: absolute; inset: 0;
  background: linear-gradient(180deg,
    rgba(22, 30, 74, .58), rgba(38, 48, 100, .34) 52%, rgba(70, 80, 130, .14));
}

.hab-sun {
  position: absolute; left: 58%; top: 10%;
  font-size: calc(var(--hu) * .95); line-height: 1;
  filter: drop-shadow(0 0 12px rgba(255, 226, 130, .85));
  animation: habSun 7s ease-in-out infinite;
}
@keyframes habSun {
  0%, 100% { transform: translateY(0) rotate(-4deg); }
  50%      { transform: translateY(-5px) rotate(4deg); }
}

.hab-stars { position: absolute; inset: 0; }
.hab-stars i {
  position: absolute;
  width: calc(3px * var(--ss, 1)); height: calc(3px * var(--ss, 1));
  border-radius: 50%;
  background: #fff; opacity: .8;
  box-shadow: 0 0 5px rgba(255, 255, 255, .9);
  animation: habTwinkle 3s ease-in-out infinite;
}
@keyframes habTwinkle { 0%, 100% { opacity: .18; } 50% { opacity: .95; } }

/* 云：一个圆角矩形 + 两个圆形伪元素，就是一朵蓬松的云 */
.hab-cloud {
  position: absolute; left: 0;
  width: calc(var(--hu) * 2.1); height: calc(var(--hu) * .72);
  background: #fff; border-radius: 99px; opacity: .8;
  box-shadow: 0 6px 18px rgba(120, 160, 220, .18);
  animation: habDrift 30s linear infinite;
}
.hab-cloud::before, .hab-cloud::after {
  content: ''; position: absolute; background: inherit; border-radius: 50%;
}
.hab-cloud::before { width: 62%; height: 165%; left: 6%; bottom: 22%; }
.hab-cloud::after  { width: 46%; height: 132%; right: 12%; bottom: 26%; }
.hab-cloud { transform: scale(var(--cs, 1)); }
.hab-cloud.c1 { animation-duration: 34s; }
.hab-cloud.c2 { animation-duration: 46s; animation-delay: -12s; }
.hab-cloud.c3 { animation-duration: 58s; animation-delay: -26s; }
/* 百分比 margin 是相对容器宽度算的，所以云能真的横穿整个画面 */
@keyframes habDrift {
  from { margin-left: -36%; }
  to   { margin-left: 128%; }
}

/* 彩虹：半个椭圆 + 一圈圈同心弧 */
.hab-rainbow {
  position: absolute; left: 5%; right: 5%; top: 4%;
  height: calc(var(--hu) * 3.6);
  border-radius: 50% 50% 0 0 / 100% 100% 0 0;
  background: radial-gradient(ellipse 48% 96% at 50% 100%,
    transparent 0 62%, #ff6b6b 62% 68%, #ffb347 68% 74%, #ffe066 74% 80%,
    #7bd88f 80% 86%, #6ec6ff 86% 92%, #a98bf5 92% 100%, transparent 100%);
  opacity: .5;
  animation: habRainbow 9s ease-in-out infinite;
}
@keyframes habRainbow {
  0%, 100% { transform: translateY(0); opacity: .42; }
  50%      { transform: translateY(-4px); opacity: .6; }
}

/* 远处的山：顶边透明，位置差一点也看不出来 */
.hab-hill {
  position: absolute; left: -14%; right: -14%;
  height: calc(var(--hu) * 2.6);
  border-radius: 50% 50% 0 0 / 70% 70% 0 0;
}
.hab-hill.h1 {
  bottom: 58%; background: linear-gradient(180deg, transparent, var(--hill1) 72%);
  opacity: .75;
}
.hab-hill.h2 {
  bottom: 53%; background: linear-gradient(180deg, transparent, var(--hill2) 68%);
  opacity: .55; height: calc(var(--hu) * 3.1);
}

/* ---------------- 3D 舞台 ----------------
   .hab-stage 是 0×0 的：透视的消失点正好落在这一个点上，
   .hab-floor 再以它为中心摆正，整块地就居中在容器里。 */
.hab-stage {
  position: absolute; left: 50%; top: 56%;
  width: 0; height: 0;
  perspective: 8000px;
}
.hab-stage, .hab-floor, .hab-z, .hab-grid, .hab-cell, .hab-bb, .hab-soil {
  transform-style: preserve-3d;
}

.hab-floor {
  position: absolute;
  left: calc(var(--hu) * -3.5); top: calc(var(--hu) * -3.5);
  width: calc(var(--hu) * 7); height: calc(var(--hu) * 7);
  transform: rotateX(65deg) rotate(45deg);
}

.hab-z { position: absolute; inset: 0; }

/* 岛的泥土：两块板从草皮边缘往下垂，整块地就有了厚度 */
.hab-sf { position: absolute; }
.hab-sf.sf-front {
  left: 0; top: 100%; width: 100%; height: var(--soil);
  transform-origin: 0 0; transform: rotateX(-90deg);
  background: linear-gradient(90deg, var(--s1), var(--s2));
}
.hab-sf.sf-right {
  left: 100%; top: 0; width: var(--soil); height: 100%;
  transform-origin: 0 0; transform: rotateY(90deg);
  background: linear-gradient(180deg, var(--s2), var(--s3));
}

/* 草皮：一格一格的浅浅棋盘，加上一点从中间散开的高光 */
.hab-grass {
  position: absolute; inset: 0;
  background-color: var(--g2);
  background-image:
    repeating-conic-gradient(from 0deg, var(--g1) 0% 25%, var(--g2) 0% 50%);
  background-size: calc(var(--hu) * 2) calc(var(--hu) * 2);
  box-shadow: inset 0 0 0 calc(var(--hu) * .14) var(--g3);
}
.hab-grass::after {
  content: ''; position: absolute; inset: 0;
  /* 只压边缘，不在中间加高光 —— 中间加白会整块地发灰，
     看起来像蒙了一层磨砂玻璃，草色全被洗掉了 */
  background: radial-gradient(ellipse at 50% 118%, rgba(0, 0, 0, .16), transparent 55%);
}

/* 网格只负责定位，不画任何东西 */
.hab-grid {
  position: absolute; inset: 0;
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  grid-template-rows: repeat(7, 1fr);
}
.hab-cell { position: relative; }

/* 影子平躺在地上（**不**抵消旋转，这才是立体感的来源） */
.hab-shadow {
  position: absolute; left: 50%; top: 50%;
  width: calc(var(--hu) * var(--sh, .6) * 1.6);
  height: calc(var(--hu) * var(--sh, .6) * 1.6);
  margin: calc(var(--hu) * var(--sh, .6) * -.8) 0 0 calc(var(--hu) * var(--sh, .6) * -.8);
  border-radius: 50%;
  background: radial-gradient(ellipse at 50% 50%,
    rgba(28, 22, 10, .38), rgba(28, 22, 10, .17) 52%, transparent 72%);
  transform: translateZ(.6px);
}
.hab-shadow.s-pet {
  width: calc(var(--hu) * 1.3); height: calc(var(--hu) * 1.3);
  margin: calc(var(--hu) * -.65) 0 0 calc(var(--hu) * -.65);
}

/* 立牌：0×0 的锚点 + 抵消旋转，就变成一张正对镜头的贴纸，
   而它的**位置**仍然是三维的，所以近大远小依然成立。 */
.hab-bb {
  position: absolute; left: 50%; top: 50%;
  width: 0; height: 0;
  transform-origin: 0 0;
  transform: rotateZ(-45deg) rotateX(-65deg);
}
.hab-prop, .hab-pet, .hab-wear, .hab-mood {
  position: absolute; left: 0; bottom: 0;
  transform: translateX(-50%);   /* 水平居中；带动画的那几个每帧都带上这一句 */
  line-height: 1; white-space: nowrap;
  /* emoji 字形底部离 em 盒底还有一条缝，往下压一丢丢才像踩在地上 */
  margin-bottom: -.06em;
}
.hab-prop {
  filter: drop-shadow(0 2px 1px rgba(30, 24, 8, .18));
}
.hab-pet {
  font-size: calc(var(--hu) * 1.7);
  filter: drop-shadow(0 3px 2px rgba(30, 24, 8, .22));
  animation: habBob 2.9s ease-in-out infinite;
}
@keyframes habBob {
  0%, 100% { transform: translateX(-50%) translateY(0) scaleY(1); }
  46%      { transform: translateX(-50%) translateY(-9%) scaleY(1.03); }
  54%      { transform: translateX(-50%) translateY(-9%) scaleY(1); }
}
.hab-wear.w-hat {
  bottom: calc(var(--hu) * 1.24);
  font-size: calc(var(--hu) * .78);
}
/* 宠物大多是"一个头"的 emoji（🦊🐼🐯），围巾挂高了会盖住嘴，
   压到最底下当项圈才自然 */
.hab-wear.w-neck {
  bottom: calc(var(--hu) * .06);
  font-size: calc(var(--hu) * .50);
}
.hab-mood {
  bottom: calc(var(--hu) * 1.82);
  width: calc(var(--hu) * .72); height: calc(var(--hu) * .72);
  display: grid; place-items: center;
  font-size: calc(var(--hu) * .46);
  background: rgba(255, 255, 255, .94);
  border: 2px solid #fff;
  border-radius: 50% 50% 50% 6px;
  box-shadow: 0 3px 8px rgba(40, 30, 80, .3);
  animation: habFloat 3.6s ease-in-out infinite;
}
/* 气泡底下的小尾巴，让它像"从它头顶冒出来的" */
.hab-mood::after {
  content: ''; position: absolute; left: 22%; bottom: -5px;
  width: 0; height: 0;
  border: 5px solid transparent;
  border-top-color: #fff;
  border-right: 0;
}
@keyframes habFloat {
  0%, 100% { transform: translateX(-50%) translateY(0); }
  50%      { transform: translateX(-50%) translateY(-22%); }
}

/* 心情差的时候玩具蔫在一边 */
.hab-cell.hab-dim { filter: grayscale(.7) opacity(.65); }

/* ---------------- 天气粒子 ---------------- */
.hab-fx { position: absolute; left: 0; right: 0; top: 0; bottom: 16%;
  overflow: hidden; pointer-events: none; }
.hab-fx i {
  position: absolute; top: 0; left: 0;
  font-size: calc(var(--hu) * var(--ps, .8));
  font-style: normal; line-height: 1;
}
.hab-fx[data-kind="leaf"] i,
.hab-fx[data-kind="snow"] i { animation: habFall linear infinite; }
.hab-fx[data-kind="rain"] i {
  width: 2px; height: calc(var(--hu) * .9); border-radius: 2px;
  background: linear-gradient(180deg, transparent, rgba(190, 228, 255, .85));
  animation: habFall linear infinite;
}
.hab-fx[data-kind="sparkle"] i { animation: habTwinkle ease-in-out infinite; }
.hab-fx[data-kind="bubble"] i { animation: habFallUp linear infinite; }
.hab-fx[data-kind="firefly"] { --fxglow: #ffe066; }
.hab-fx[data-kind="ember"]   { --fxglow: #ff9a3c; }
.hab-fx[data-kind="star"]    { --fxglow: #ffffff; }
.hab-fx[data-kind="firefly"] i,
.hab-fx[data-kind="ember"] i,
.hab-fx[data-kind="star"] i {
  width: calc(4px * var(--ps, .8)); height: calc(4px * var(--ps, .8));
  border-radius: 50%; background: var(--fxglow, #fff);
  box-shadow: 0 0 8px var(--fxglow, #fff);
}
.hab-fx[data-kind="ember"] i { animation: habFallUp ease-in-out infinite; }
.hab-fx[data-kind="firefly"] i { animation: habDriftSoft ease-in-out infinite; }
.hab-fx[data-kind="star"] i { animation: habTwinkle ease-in-out infinite; }

@keyframes habFall {
  0%   { transform: translateY(calc(var(--hu) * -1)) rotate(0deg); opacity: 0; }
  14%  { opacity: .95; }
  100% { transform: translateY(calc(var(--hu) * 8.4)) rotate(300deg); opacity: 0; }
}
@keyframes habDriftSoft {
  0%, 100% { transform: translateY(0) scale(.7); opacity: .25; }
  50%      { transform: translateY(calc(var(--hu) * -1.6)) scale(1.15); opacity: 1; }
}
@keyframes habFallUp {
  0%   { transform: translateY(calc(var(--hu) * 1.2)); opacity: 0; }
  16%  { opacity: .9; }
  100% { transform: translateY(calc(var(--hu) * -8)); opacity: 0; }
}

/* ---------------- 场景上的游戏 HUD ---------------- */
/* 场景上的 HUD：圆形头像（带等级角标）+ 名字 + 升级进度条，右边是金币。
   做成游戏里那种"一条"的样子，而不是场景外面另起一行小字。 */
.hab-hud {
  position: absolute; left: 9px; right: 9px; top: 9px;
  display: flex; align-items: center; gap: 8px;
}
.hab-plate {
  display: flex; align-items: center; gap: 8px; min-width: 0;
  padding: 4px 12px 4px 5px;
  background: rgba(255, 255, 255, .88);
  border: 1.5px solid rgba(255, 255, 255, .95);
  border-radius: 99px;
  box-shadow: 0 2px 8px rgba(50, 40, 110, .18), inset 0 1px 0 rgba(255, 255, 255, .9);
  backdrop-filter: blur(6px);
}
.hab-plate .hp-ava {
  position: relative; flex: 0 0 auto;
  width: 29px; height: 29px; border-radius: 50%;
  display: grid; place-items: center;
  font-size: 17px; line-height: 1;
  background: linear-gradient(140deg, #a99bff, #5b8def);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .55), 0 1px 3px rgba(60, 50, 130, .35);
}
.hab-plate .hp-ava .hp-lv {
  position: absolute; right: -5px; bottom: -4px;
  font-size: 8.5px; font-weight: 900; font-style: normal;
  color: #7a4b00; line-height: 13px; padding: 0 4px;
  background: linear-gradient(180deg, #ffe9a8, #ffb703);
  border: 1.5px solid #fff; border-radius: 99px;
  box-shadow: 0 1px 3px rgba(120, 80, 0, .3);
}
.hab-plate .hp-col { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.hab-plate .hp-name {
  font-size: 12px; font-weight: 900; color: var(--ink);
  line-height: 1.1; max-width: 92px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.hab-plate .hp-bar {
  display: block; width: 74px; height: 5px; border-radius: 99px;
  background: rgba(120, 105, 200, .18); overflow: hidden;
}
.hab-plate .hp-bar > i {
  display: block; height: 100%; border-radius: 99px;
  background: linear-gradient(90deg, #a78bfa, #6366f1);
  box-shadow: 0 0 6px rgba(139, 123, 247, .75);
}
.hab-coin {
  margin-left: auto;
  display: inline-flex; align-items: center; gap: 3px;
  font-size: 12.5px; font-weight: 900; color: #7a4b00;
  padding: 5px 12px 5px 7px;
  background: linear-gradient(180deg, #ffe9a8, #ffc93c);
  border: 1.5px solid #fff; border-radius: 99px;
  box-shadow: 0 2px 8px rgba(160, 110, 20, .3), inset 0 1px 0 rgba(255, 255, 255, .7);
}
.hab-coin b { font-size: 13px; font-weight: 400; line-height: 1; }
.hab-tag {
  position: absolute; left: 50%; bottom: 9px;
  transform: translateX(-50%);
  display: inline-flex; align-items: center; gap: 5px;
  font-size: 10.5px; font-weight: 900; color: #fff;
  padding: 4px 12px;
  background: linear-gradient(180deg, rgba(58, 48, 105, .40), rgba(36, 28, 72, .52));
  border: 1px solid rgba(255, 255, 255, .26);
  border-radius: 99px;
  backdrop-filter: blur(5px);
  text-shadow: 0 1px 2px rgba(0, 0, 0, .3);
  white-space: nowrap;
}
.hab-tag b { font-weight: 400; font-size: 11.5px; line-height: 1; }

/* ============================================================
 * 我的宠物：整页的游戏化外观
 *
 * 这一页的目标是"看起来像一个可以卖的养宠物游戏"，不是"一个显示
 * 宠物数据的表单"。所以：
 *   · 场景套一圈相框（.pg-hero），像游戏视口而不是页面上的一块钱
 *   · 三个页签一屏只讲一件事，避免 12 只宠物 + 3 个装扮槽一起往下滚
 *   · 图鉴是卡片墙，每张卡用那只宠物**自己那块地**的天空和草色画缩微
 *     风景 —— 一眼就看出"换一只 = 换一个世界"
 *   · 所有面板统一用一层浅渐变 + 极细描边 + 分层阴影，
 *     而不是清一色的纯白圆角块（那是"表单"，不是"游戏"）
 * ============================================================ */
.pg { padding-bottom: 4px; }

/* ---------------- 场景相框 ---------------- */
.pg-hero {
  padding: 5px;
  border-radius: 30px;
  margin-bottom: 13px;
  background: linear-gradient(165deg, #ffffff, #f1ecff 44%, #e2ecff);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, .95),
    inset 0 -1px 0 rgba(120, 105, 200, .10),
    0 14px 30px -14px rgba(78, 66, 160, .55),
    0 3px 8px rgba(90, 80, 170, .10);
}
.pg-hero > .hab {
  margin: 0;
  border-radius: 26px;
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, .45);
}

/* ---------------- 页签 ---------------- */
.pg-tabs {
  display: grid; grid-template-columns: repeat(3, 1fr); gap: 5px;
  padding: 5px; margin-bottom: 14px;
  background: linear-gradient(180deg, #f2efff, #eae6fb);
  border-radius: 19px;
  box-shadow: inset 0 2px 5px rgba(90, 80, 170, .10);
}
.pg-tab {
  display: flex; align-items: center; justify-content: center; gap: 5px;
  font-family: inherit; font-size: 13px; font-weight: 900; color: var(--ink-2);
  padding: 9px 4px; border-radius: 14px; cursor: pointer;
  transition: transform .16s, background .16s, color .16s, box-shadow .16s;
}
.pg-tab i { font-style: normal; font-size: 15px; line-height: 1; }
.pg-tab.active {
  color: #fff;
  background: linear-gradient(180deg, #8f7ff8, #6366f1);
  box-shadow: 0 3px 0 #4c46bd, 0 5px 14px -3px rgba(99, 102, 241, .7);
  transform: translateY(-1px);
}

/* ---------------- 状态胶囊 ---------------- */
.pg-stats { display: grid; gap: 9px; margin-bottom: 12px; }
.pg-stat {
  display: flex; align-items: center; gap: 11px;
  padding: 11px 14px; border-radius: 19px;
  background: linear-gradient(180deg, #fff, #fbfaff);
  border: 1px solid rgba(120, 105, 200, .10);
  box-shadow: 0 1px 2px rgba(90, 80, 170, .05), 0 9px 18px -13px rgba(90, 80, 170, .75);
}
.pg-stat .ps-ico {
  flex: 0 0 auto; width: 37px; height: 37px; border-radius: 13px;
  display: grid; place-items: center; font-size: 19px; line-height: 1;
  background: linear-gradient(150deg, var(--a), var(--b));
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .55), 0 4px 10px -4px var(--b);
}
.pg-stat .ps-col { flex: 1 1 auto; min-width: 0; }
.pg-stat .ps-top {
  display: flex; align-items: baseline; justify-content: space-between;
  margin-bottom: 6px;
}
.pg-stat .ps-top b { font-size: 12.5px; font-weight: 900; color: var(--ink); }
.pg-stat .ps-top i { font-size: 13px; font-weight: 900; font-style: normal; color: var(--a); }
.pg-stat .ps-track {
  display: block; height: 9px; border-radius: 99px; overflow: hidden;
  background: rgba(120, 105, 200, .13);
  box-shadow: inset 0 1px 2px rgba(80, 70, 150, .16);
}
.pg-stat .ps-track > i {
  display: block; height: 100%; border-radius: 99px;
  background: linear-gradient(90deg, var(--a), var(--b));
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .45);
  transition: width .45s cubic-bezier(.34, 1.3, .64, 1);
}
.pg-stat.low .ps-ico { animation: pgPulse 1.5s ease-in-out infinite; }
@keyframes pgPulse {
  0%, 100% { transform: scale(1); }
  50%      { transform: scale(1.12); }
}

/* ---------------- 升级进度 ---------------- */
.pg-next {
  position: relative; display: flex; align-items: center; gap: 8px;
  padding: 12px 14px 17px; margin-bottom: 14px;
  border-radius: 19px;
  background: linear-gradient(150deg, #fff8e6, #ffefd2);
  border: 1px solid rgba(255, 180, 60, .28);
  box-shadow: 0 8px 18px -13px rgba(200, 140, 20, .9);
}
.pg-next .pn-ico { font-size: 16px; line-height: 1; }
.pg-next .pn-txt { font-size: 12px; font-weight: 700; color: #8a5a12; }
.pg-next .pn-txt b { font-weight: 900; color: #b45309; }
.pg-next .pn-bar {
  position: absolute; left: 13px; right: 13px; bottom: 8px;
  height: 5px; border-radius: 99px; overflow: hidden;
  background: rgba(180, 120, 20, .18);
}
.pg-next .pn-bar > i {
  display: block; height: 100%; border-radius: 99px;
  background: linear-gradient(90deg, #ffd166, #ff9f1c);
  transition: width .45s;
}

/* ---------------- 照顾三连 ---------------- */
.pg-acts { display: grid; grid-template-columns: repeat(3, 1fr); gap: 10px; margin-bottom: 13px; }
.pg-act {
  display: flex; flex-direction: column; align-items: center;
  font-family: inherit; padding: 13px 4px 11px;
  border-radius: 21px; cursor: pointer;
  background: linear-gradient(180deg, #fff, #fbfaff);
  border: 1px solid rgba(120, 105, 200, .10);
  box-shadow: 0 4px 0 rgba(90, 80, 170, .14), 0 12px 22px -16px rgba(90, 80, 170, .9);
  transition: transform .1s, box-shadow .1s;
}
.pg-act .pa-ico {
  width: 43px; height: 43px; border-radius: 50%;
  display: grid; place-items: center; font-size: 23px; line-height: 1;
  margin-bottom: 5px;
  background: linear-gradient(150deg, var(--a), var(--b));
  box-shadow: inset 0 2px 0 rgba(255, 255, 255, .5), 0 6px 14px -5px var(--b);
}
.pg-act .pa-label { font-size: 13px; font-weight: 900; color: var(--ink); }
.pg-act .pa-cost {
  margin-top: 4px; font-size: 10.5px; font-weight: 900; color: #8a5a12;
  padding: 1.5px 9px; border-radius: 99px;
  background: linear-gradient(180deg, #ffeeb8, #ffd76a);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .7);
}
.pg-act:active { transform: translateY(4px); box-shadow: 0 0 0 rgba(0, 0, 0, 0); }
.pg-act.poor { opacity: .6; }
.pg-act.poor .pa-cost { color: #b91c1c; background: linear-gradient(180deg, #ffe3e3, #ffc9c9); }

/* ---------------- 底部说明 ---------------- */
.pg-note {
  font-size: 11.5px; line-height: 1.85; color: var(--ink-3);
  text-align: center; padding: 6px 10px 10px;
}

/* ---------------- 分区标题 ---------------- */
.pg-sec { margin-bottom: 16px; }
.pg-sec-h { display: flex; align-items: center; gap: 9px; margin: 0 2px 10px; }
.pg-sec-h .sh-ico {
  flex: 0 0 auto; width: 31px; height: 31px; border-radius: 11px;
  display: grid; place-items: center; font-size: 16px; line-height: 1;
  background: linear-gradient(150deg, #f2edff, #e0e9ff);
  box-shadow: inset 0 1px 0 #fff, 0 3px 8px -3px rgba(99, 102, 241, .55);
}
.pg-sec-h .sh-t { font-size: 14.5px; font-weight: 900; color: var(--ink); }
.pg-sec-h .sh-d { margin-left: auto; font-size: 11.5px; font-weight: 800; color: var(--ink-3); }

/* ---------------- 装扮格子 ---------------- */
.pg-items { display: flex; flex-wrap: wrap; gap: 8px; }
.pg-item {
  position: relative;
  display: flex; flex-direction: column; align-items: center;
  font-family: inherit; width: 71px; padding: 9px 3px 8px;
  border-radius: 17px; cursor: pointer;
  background: linear-gradient(180deg, #fff, #fbfaff);
  border: 1px solid rgba(120, 105, 200, .10);
  box-shadow: 0 3px 0 rgba(90, 80, 170, .10);
  transition: transform .1s;
}
.pg-item .pi-ico {
  display: grid; place-items: center;
  width: 100%; height: 33px;
  font-size: 26px; line-height: 1;
  margin-bottom: 3px;
}
.pg-item .pi-name { font-size: 10.5px; font-weight: 800; color: var(--ink-2); margin-top: 2px; }
.pg-item .pi-foot { font-size: 9.5px; font-weight: 900; color: var(--ink-3); margin-top: 3px; }
.pg-item.on {
  border-color: #8b7bf7;
  background: linear-gradient(180deg, #f7f3ff, #ece5ff);
  box-shadow: 0 0 0 2px rgba(139, 123, 247, .26), 0 3px 0 #b9aefb;
}
.pg-item.on .pi-foot { color: #6d5ef0; }
.pg-item .pi-tick {
  position: absolute; right: -4px; top: -4px;
  width: 19px; height: 19px; border-radius: 50%;
  display: grid; place-items: center;
  font-size: 11px; font-style: normal; font-weight: 900; color: #fff;
  background: linear-gradient(150deg, #8b7bf7, #6366f1);
  border: 2px solid #fff;
}
.pg-item.locked { opacity: .74; }
.pg-item:active { transform: scale(.95); }

/* ---------------- 图鉴 ---------------- */
.pg-prog {
  height: 8px; border-radius: 99px; margin: 0 2px 12px; overflow: hidden;
  background: rgba(120, 105, 200, .13);
  box-shadow: inset 0 1px 2px rgba(80, 70, 150, .16);
}
.pg-prog > i {
  display: block; height: 100%; border-radius: 99px;
  background: linear-gradient(90deg, #8b7bf7, #5b8def);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .4);
  transition: width .5s;
}
.pg-cards { display: grid; grid-template-columns: repeat(2, 1fr); gap: 10px; }
.pg-card {
  display: flex; flex-direction: column; text-align: left;
  font-family: inherit; padding: 0; border-radius: 21px; cursor: pointer;
  background: linear-gradient(180deg, #fff, #fbfaff);
  border: 1px solid rgba(120, 105, 200, .10);
  box-shadow: 0 3px 0 rgba(90, 80, 170, .10), 0 12px 22px -18px rgba(90, 80, 170, 1);
  overflow: hidden;
  transition: transform .12s, box-shadow .12s;
}
.pg-card:active { transform: scale(.97); }
.pg-card.active {
  border-color: #8b7bf7;
  box-shadow: 0 0 0 2px rgba(139, 123, 247, .3), 0 3px 0 #b9aefb,
              0 14px 24px -16px rgba(99, 102, 241, .95);
}

/* 卡片上半：这只宠物自己那块地的缩微风景（天空 + 草坡 + 太阳 + 云） */
.pg-card .pc-art {
  position: relative; display: block; height: 84px; overflow: hidden;
  background: linear-gradient(180deg, var(--s1), var(--s2));
}
.pg-card .pc-art::after {
  content: ''; position: absolute; left: -14%; right: -14%; bottom: 0;
  height: 48%;
  background: linear-gradient(180deg, var(--ga), var(--gb));
  border-radius: 50% 50% 0 0 / 45% 45% 0 0;
  box-shadow: inset 0 2px 0 rgba(255, 255, 255, .38);
}
.pg-card .pc-sun {
  position: absolute; right: 8px; top: 7px;
  font-size: 15px; line-height: 1; font-style: normal;
  filter: drop-shadow(0 0 6px rgba(255, 225, 130, .9));
}
.pg-card .pc-cloud {
  position: absolute; left: 10px; top: 15px;
  width: 23px; height: 8px; border-radius: 99px;
  background: #fff; opacity: .82;
}
.pg-card .pc-cloud.c2 { left: auto; right: 27px; top: 27px; width: 15px; height: 6px; opacity: .62; }
.pg-card .pc-pet {
  position: absolute; left: 50%; bottom: 5px; transform: translateX(-50%);
  font-size: 39px; line-height: 1; z-index: 2;
  filter: drop-shadow(0 3px 3px rgba(30, 24, 8, .32));
}
.pg-card .pc-lock, .pg-card .pc-tick {
  position: absolute; right: 7px; bottom: 7px; z-index: 3;
  width: 23px; height: 23px; border-radius: 50%;
  display: grid; place-items: center;
  font-size: 12px; font-style: normal; font-weight: 900;
  border: 2px solid #fff;
}
.pg-card .pc-lock { background: rgba(56, 46, 104, .62); }
.pg-card .pc-tick { background: linear-gradient(150deg, #34d399, #059669); color: #fff; }

.pg-card .pc-body { display: block; padding: 8px 10px 10px; }
.pg-card .pc-name { display: block; font-size: 13px; font-weight: 900; color: var(--ink); }
.pg-card .pc-where { display: block; font-size: 10px; font-weight: 700; color: var(--ink-3); margin-top: 1px; }
.pg-card .pc-foot { display: block; margin-top: 7px; }
.pg-card .pc-foot i {
  display: inline-block; font-style: normal;
  font-size: 10.5px; font-weight: 900;
  padding: 2.5px 10px; border-radius: 99px;
}
.pg-card .pc-on { color: #fff; background: linear-gradient(150deg, #8b7bf7, #6366f1); }
.pg-card .pc-own { color: #15803d; background: #dcfce7; }
.pg-card .pc-price { color: #8a5a12; background: linear-gradient(180deg, #ffeeb8, #ffd76a); }
.pg-card.locked .pc-art { filter: saturate(.75) brightness(.86); }
/* 上锁的卡再压一层浅灰，比直接去色干净得多 */
.pg-card.locked .pc-art::before {
  content: ''; position: absolute; inset: 0; z-index: 4;
  background: rgba(250, 249, 255, .28);
}

.chip.locked { opacity: .55; }

/* 首页横幅里"全部通关了"那句话：是个提示，不是按钮 */
.gobtn.allclear {
  display: flex; align-items: center; justify-content: center;
  background: rgba(255, 255, 255, .22);
  color: #fff; font-weight: 900; cursor: default;
}

/* ============================================================
 * 看拼音写词语 —— A4 听写纸
 *
 * 这一块的尺寸**全部用 mm**：孩子在纸上写多大的格子，预览里就是多大，
 * 打印出来一分不差。屏幕放不下就用 transform 整体缩小（--zs 由 JS 算），
 * 打印时把缩放关掉、把宽度换成 186mm（= A4 减掉 12mm 白边）。
 *
 * 分页是自己算的（js/core/dictation.js 的 layout），不交给浏览器的
 * 自动分页 —— 自动分页会把一行田字格从中间劈开，还可能多出一张空白页。
 * ============================================================ */
.dict-paper { display: block; }

/* 缩放容器：transform 不改变布局高度，所以容器高度得自己跟着缩放走，
   不然两张纸会叠在一起。--zs 由 R.fitSheets() 按可用宽度算出来；
   打印时下面 @media print 会把这个高度收回成 auto */
.ds-view { overflow: hidden; height: calc(297mm * var(--zs, 1)); }
.ds-view + .ds-view { margin-top: 14px; }

.dsheet {
  box-sizing: border-box;
  width: 210mm; height: 297mm;
  padding: 12mm;
  display: flex; flex-direction: column;
  background: #fff;
  color: #2b3550;
  border-radius: 3px;
  box-shadow: 0 10px 30px rgba(38, 30, 80, .18);
  font-family: "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "Noto Sans SC", sans-serif;
  transform: scale(var(--zs, 1));
  transform-origin: 0 0;
  overflow: hidden;
}

.ds-head { flex: 0 0 auto; height: 22mm; text-align: center; }
.ds-title {
  font-size: 6.4mm; font-weight: 800; letter-spacing: .8mm;
  color: #2b3550; padding-top: .5mm;
}
.ds-meta { font-size: 3.4mm; color: #8b94a8; margin-top: 1.4mm; }
.ds-meta b { color: #46506b; font-weight: 700; }
.ds-dot { margin: 0 2mm; color: #ccd3e0; }

.ds-body { flex: 1 1 auto; min-height: 0; }
.ds-row { display: flex; align-items: flex-start; gap: 6mm; height: var(--rowh); }

/* 一组：拼音在上、田字格连排在下。宽度 = 格子 × 字数 */
.ds-unit { flex: 0 0 auto; width: calc(var(--cell) * var(--n)); }
.ds-py { display: flex; align-items: flex-end; height: var(--pyh); }
.ds-syl {
  flex: 0 0 auto; width: var(--cell);
  text-align: center;
  /* --pyfs 由 dictation.js 按"最长的那个音节"算好（见那里的注释）；
     没有这个值时退回格子宽度的 30% */
  font-size: var(--pyfs, calc(var(--cell) * .30));
  line-height: 1.05;
  color: #3c4763;
  white-space: nowrap;
}
/* 音节数和字数对不上时整串居中，不硬往格子上套 */
.ds-py-wide { display: block; }
.ds-syl-wide { width: 100%; text-align: center; }

.ds-cells { display: flex; height: var(--cell); }
.ds-cell {
  position: relative;
  width: var(--cell); height: var(--cell);
  box-sizing: border-box;
  border: .35mm solid #46506b;
}
/* 相邻格共用一条线，不然中线会变成两倍粗 */
.ds-cell + .ds-cell { border-left-width: 0; }
/* 田字格的十字虚线：用伪元素的 border 画，不用背景渐变 ——
   浏览器打印默认不印背景色，用 background 画的线会整片消失 */
.ds-cell::before, .ds-cell::after { content: ''; position: absolute; }
.ds-cell::before { left: 0; right: 0; top: 50%; border-top: 1px dashed #aab6cc; }
.ds-cell::after { top: 0; bottom: 0; left: 50%; border-left: 1px dashed #aab6cc; }

.ds-foot {
  flex: 0 0 auto; height: 8mm;
  display: flex; align-items: flex-end; justify-content: space-between;
  font-size: 3mm; color: #98a2b6;
  border-top: .2mm solid #e6eaf2; padding-top: 1.4mm;
}
.ds-empty { padding: 24mm 6mm; text-align: center; font-size: 4mm; color: #b3bccd; }

/* 答案页 */
.ds-answers { display: flex; flex-wrap: wrap; gap: 4mm 7mm; padding-top: 2mm; }
.ds-ans { font-size: 6mm; font-weight: 700; color: #2b3550; letter-spacing: 1mm; white-space: nowrap; }
.ds-ans i { font-style: normal; font-size: 3.4mm; color: #9aa4b6; margin-right: 1.4mm; letter-spacing: 0; }

/* ---------------- 页面上的工具条（不打印） ---------------- */
.dict-ta {
  width: 100%; min-height: 76px; resize: vertical;
  font-family: inherit; font-size: 15px; font-weight: 700; line-height: 1.65;
  padding: 12px 14px; border-radius: var(--r-md);
  border: 2.5px solid var(--line); background: #faf9ff;
  color: var(--ink); outline: none;
}
.dict-ta:focus { border-color: var(--p1); background: #fff; }
.dict-ta::placeholder { color: var(--ink-3); font-weight: 600; }

/* 课本课号：紧凑的小方块，一册二十几课也排得下 */
.dict-lessons { gap: 6px; }
.chip.num {
  min-width: 34px; padding: 6px 9px;
  font-size: 13px; font-weight: 800;
  border-radius: 10px;
}
.chip.num[disabled] { opacity: .4; }

.dict-rows { margin-top: 4px; }
.dict-row {
  display: flex; align-items: center; gap: 8px;
  padding: 7px 0; border-bottom: 1px dashed var(--line);
}
.dict-row:last-child { border-bottom: none; }
.dict-w {
  flex: 0 0 auto; font-size: 17px; font-weight: 800; color: var(--ink);
  letter-spacing: 1px;
}
.dict-row.bad .dict-w { color: var(--red); }
.dict-py-in {
  flex: 1 1 auto; min-width: 0;
  font-family: inherit; font-size: 14px; font-weight: 700;
  padding: 8px 11px; border-radius: 10px;
  border: 2px solid var(--line); background: #faf9ff;
  color: var(--ink-2); outline: none;
}
.dict-py-in:focus { border-color: var(--p1); background: #fff; color: var(--ink); }
.dict-x {
  flex: 0 0 auto; width: 30px; height: 30px; border-radius: 50%;
  background: #f4f2fb; color: var(--ink-3);
  font-size: 15px; font-weight: 900; line-height: 1;
  display: grid; place-items: center;
}
.dict-x:active { background: #ffe4ea; color: var(--red); }
.dict-warn {
  font-size: 12px; font-weight: 700; line-height: 1.6;
  color: #b45309; background: #fff7ed;
  border-radius: 12px; padding: 9px 12px; margin-top: 10px;
}
.dict-tip { font-size: 12px; font-weight: 600; color: var(--ink-3); line-height: 1.6; margin-top: 8px; }

/* 打印：把整个应用外壳收起来，只留纸 */
@media print {
  @page { size: A4 portrait; margin: 12mm; }

  html, body {
    height: auto !important; min-height: 0 !important;
    overflow: visible !important; background: #fff !important;
  }
  .blobs, #topbar, #tabbar, #consent-layer, #toast-layer, #modal-layer,
  .dict-ui { display: none !important; }

  #app {
    display: block !important; height: auto !important;
    max-width: none !important; margin: 0 !important; padding: 0 !important;
  }
  #stage {
    display: block !important; height: auto !important;
    overflow: visible !important; max-height: none !important;
    padding: 0 !important; margin: 0 !important; max-width: none !important;
  }

  .dict-paper { display: block !important; }
  .ds-view { height: auto !important; overflow: visible !important; }
  .ds-view + .ds-view { margin-top: 0 !important; }

  /* 白边交给 @page 的 margin，纸自己不再留 padding，宽度换成 186mm */
  .dsheet {
    width: 186mm !important;
    /* 273mm 是 A4 去掉上下各 12mm 白边后的净高度。这里故意少半毫米：
       纸和可用高度完全相等时，浏览器四舍五入就会把最后一像素挤到下一页，
       于是每张纸后面多出一张空白页（实测出来的，见 tools/layout-check.js）。 */
    height: 272.5mm !important;
    padding: 0 !important;
    margin: 0 !important;
    border-radius: 0 !important;
    box-shadow: none !important;
    transform: none !important;
    break-after: page;
    page-break-after: always;
  }
  .ds-view:last-child .dsheet { break-after: auto; page-break-after: auto; }

  /* 线条和颜色按屏幕上的来，别被打印机"省墨"省掉 */
  .dsheet, .dsheet * {
    -webkit-print-color-adjust: exact;
    print-color-adjust: exact;
  }
}
