/* ============================================================================
   le.css —— 朗文家 AI 阅读视觉层（v6）
   依据：MasterGo「朗文家 APP UI/UE / AI阅读」设计稿反解出的真实数值
   基准画板：812 × 375（横屏），与真机 837 × 388 基本 1:1
   加载顺序：style.css（结构·动效）→ brand.css（色令牌）→ look.css → 本文件
   本文件只做「视觉覆盖」，不改 DOM 结构与交互；出问题删除本 link 即可回退
   ========================================================================== */

:root {
  /* 1 设计像素 —— 812 宽画板下的 1px，换算成 rem 以便随视口缩放 */
  --u: 0.0847rem;

  /* 取色自设计稿的背景色使用频次统计 */
  --le-bg: #f7f7f7;
  --le-card: #ffffff;
  --le-ink: #333333;
  --le-ink-2: #666666;
  --le-ink-3: #999999;
  --le-line: #ededed;
  --le-primary: #64afff;
  --le-primary-d: #4d9bf0;
  --le-green: #1bbc40;
  --le-green-l: #dfffe7;
  --le-cyan: #d4ffff;
  --le-warn: #ff9900;
  --le-accent: #ff5836;
  --le-accent-l: #ffefec;
  --le-yellow: #ffe923;
  --le-navy: #18123f;
  --le-purple: #6f61ff;

  /* 圆角：白卡 20，按钮 12，药丸全圆角 */
  --le-r-card: calc(20 * var(--u));
  --le-r-btn: calc(12 * var(--u));
  --le-r-pill: 999px;

  /* 阴影：设计稿几乎不用投影，只给浮起元素一层极淡的 */
  --le-shadow: 0 calc(2 * var(--u)) calc(12 * var(--u)) rgba(24, 18, 63, 0.06);
  --le-shadow-lift: 0 calc(6 * var(--u)) calc(20 * var(--u)) rgba(24, 18, 63, 0.1);

  /* 字号阶梯（设计稿实测：10/12/14/16/18/20/23/24）
     真机 837×388 下 --u 折合 0.908px，设计稿字号打九折后偏小（中文副标只有 10.9px），
     所以整条阶梯在原值上抬约 25%，让 1u 字号≈设计稿物理字号再略大一点。
     儿童用户 + 横屏观看距离，宁可大一号。
     第二轮再整体 +11%（≈31/27/25/21/19/17/14），实测仍不折行。 */
  --le-fs-title: calc(31 * var(--u));
  --le-fs-h2: calc(27 * var(--u));
  --le-fs-body: calc(27 * var(--u));
  --le-fs-line: calc(25 * var(--u));
  --le-fs-q: calc(21 * var(--u));
  --le-fs-btn: calc(19 * var(--u));
  --le-fs-sm: calc(17 * var(--u));
  --le-fs-xs: calc(14 * var(--u));

  /* 版式栅格：左右留白 31，左栏 424，右栏 334，栏距 23 */
  --le-pad-x: calc(31 * var(--u));
  --le-gutter: calc(23 * var(--u));
  --le-col-left: 52.2%;
  --le-col-right: 41.1%;
}

/* ------------------------------------------------------------------ 基础 */
.app,
.screen {
  background: var(--le-bg) !important;
  color: var(--le-ink) !important;
  font-family: "Source Han Sans SC", "Source Han Sans", "Alibaba PuHuiTi 2.0",
    "PingFang SC", "Noto Sans SC", "Microsoft YaHei", system-ui, sans-serif !important;
}

.screen {
  padding: 0 !important;
}

/* 全局：把深色时代的发光/描边/斜切都收掉，朗文是干净的平面 */
.screen * {
  text-shadow: none !important;
}

/* ------------------------------------------------------------------ 顶栏 */
.hud {
  position: static !important;
  grid-column: 1 / -1 !important;
  grid-row: 1 !important;
  height: calc(30 * var(--u)) !important;
  display: flex !important;
  align-items: center !important;
  gap: calc(8 * var(--u)) !important;
  margin: 0 0 calc(6 * var(--u)) !important;
  padding: 0 !important;
  background: transparent !important;
  border: none !important;
  box-shadow: none !important;
  backdrop-filter: none !important;
  z-index: 30 !important;
}

.screen:not(.screen-cover) > .hud {
  position: static !important;
}

.hud-title {
  display: inline-flex;
  align-items: center;
  gap: calc(6 * var(--u));
  height: calc(30 * var(--u));
  padding: 0 calc(10 * var(--u)) 0 calc(4 * var(--u));
  font-size: var(--le-fs-btn) !important;
  font-weight: 600 !important;
  letter-spacing: 0 !important;
  color: var(--le-ink) !important;
  background: var(--le-card);
  border-radius: var(--le-r-pill);
  box-shadow: none;
}

.guide-avatar {
  width: calc(22 * var(--u)) !important;
  height: calc(22 * var(--u)) !important;
  border-radius: 50% !important;
  background: var(--le-cyan) !important;
  color: var(--le-ink) !important;
  display: inline-flex !important;
  align-items: center !important;
  justify-content: center !important;
  font-size: var(--le-fs-sm) !important;
  border: none !important;
  box-shadow: none !important;
}

.hud-progress {
  margin-left: auto;
  padding: 0 calc(10 * var(--u));
  height: calc(24 * var(--u));
  display: inline-flex;
  align-items: center;
  font-size: var(--le-fs-sm) !important;
  font-weight: 500 !important;
  letter-spacing: 0 !important;
  color: var(--le-ink-2) !important;
  background: var(--le-card);
  border-radius: var(--le-r-pill);
  font-variant-numeric: tabular-nums;
}

.hud-close {
  width: calc(30 * var(--u)) !important;
  height: calc(30 * var(--u)) !important;
  border-radius: 50% !important;
  background: var(--le-card) !important;
  color: var(--le-ink-2) !important;
  border: none !important;
  font-size: var(--le-fs-btn) !important;
  box-shadow: none !important;
}

/* ------------------------------------------------------------------ 按钮 */
.btn {
  height: calc(40 * var(--u)) !important;
  padding: 0 calc(18 * var(--u)) !important;
  border-radius: var(--le-r-pill) !important;
  font-size: var(--le-fs-btn) !important;
  font-weight: 600 !important;
  letter-spacing: 0 !important;
  border: none !important;
  box-shadow: none !important;
  display: inline-flex !important;
  align-items: center !important;
  justify-content: center !important;
  gap: calc(6 * var(--u)) !important;
  transition: transform 0.15s ease, background 0.15s ease !important;
}

.btn:active {
  transform: scale(0.97);
}

.btn-primary {
  background: var(--le-primary) !important;
  color: #ffffff !important;
}

.btn-lg {
  height: calc(48 * var(--u)) !important;
  padding: 0 calc(30 * var(--u)) !important;
  font-size: calc(21 * var(--u)) !important;
}

.btn-ghost {
  background: var(--le-card) !important;
  color: var(--le-ink-2) !important;
  border: 1px solid var(--le-line) !important;
  font-weight: 500 !important;
}

/* 主操作：按住说 —— 设计稿里唯一的实心蓝 */
.btn-talk {
  background: var(--le-primary) !important;
  color: #ffffff !important;
  min-width: calc(120 * var(--u)) !important;
}

.btn-talk.is-recording {
  background: var(--le-accent) !important;
}

.talk-dot {
  width: calc(8 * var(--u)) !important;
  height: calc(8 * var(--u)) !important;
  background: currentColor !important;
  box-shadow: none !important;
}

/* 「跳过 / 继续」：设计稿右上角的 79×30 蓝色小胶囊 */
.skip {
  position: absolute !important;
  top: calc(-41 * var(--u)) !important;
  right: 0 !important;
  left: auto !important;
  bottom: auto !important;
  width: auto !important;
  height: calc(30 * var(--u)) !important;
  padding: 0 calc(14 * var(--u)) !important;
  display: inline-flex !important;
  align-items: center !important;
  justify-content: center !important;
  background: var(--le-primary) !important;
  color: #ffffff !important;
  border: none !important;
  border-radius: var(--le-r-btn) !important;
  font-size: var(--le-fs-btn) !important;
  font-weight: 600 !important;
  letter-spacing: 0 !important;
  box-shadow: none !important;
  z-index: 40 !important;
}

/* ------------------------------------------------------------------ 封面 */
/* 顶部单独一条 bar 放返回键。原来把返回键做成绝对定位浮在左上角，
   字号抬上来之后正好压在「用英语讲中国故事」这个眉标上。
   给它一行自己的高度，文案就不需要为了避让而挤成一团。 */
.screen-cover {
  display: grid !important;
  /* 左栏宽度直接算出来，不用 auto 轨道：方形插画的「内在宽度」要先知道高度，
     而 auto 轨道又在等内在宽度 —— Chromium 114（真机 WebView）会把这个环解成 0 宽，
     插画整块消失。这里按「视口高 - 上下留白 - 返回栏 - 行距」算出与正文行等高的一格，
     宽度就变成确定值，不再依赖内在尺寸。 */
  grid-template-columns: calc(100dvh - 68 * var(--u)) minmax(0, 1fr) !important;
  grid-template-rows: auto minmax(0, 1fr) !important;
  align-items: center !important;
  gap: calc(2 * var(--u)) var(--le-gutter) !important;
  padding: calc(14 * var(--u)) var(--le-pad-x) calc(18 * var(--u)) !important;
}

.cover-bar {
  grid-column: 1 / -1 !important;
  grid-row: 1 !important;
  display: flex !important;
  align-items: center !important;
  min-height: calc(34 * var(--u));
}

.screen-cover .stage {
  position: relative !important;
  inset: auto !important;
  grid-column: 1 !important;
  grid-row: 2 !important;
  /* 正方形：横图（16:9）比右边文字矮一截，两栏底部对不齐，看着像插画被压扁了。
     1:1 之后边长 = 左栏宽 = 正文行高，插画和文案块等高 */
  width: 100% !important;
  height: auto !important;
  aspect-ratio: 1 / 1 !important;
  align-self: center !important;
  justify-self: stretch !important;
  border-radius: var(--le-r-card) !important;
  overflow: hidden !important;
  background: var(--le-navy) !important;
  box-shadow: var(--le-shadow) !important;
  order: 0;
}

.cover-scroll {
  grid-column: 2 !important;
  grid-row: 2 !important;
  position: static !important;
  inset: auto !important;
  width: auto !important;
  max-width: none !important;
  height: auto !important;
  max-height: 100% !important;
  margin: 0 !important;
  padding: 0 !important;
  display: flex !important;
  flex-direction: column !important;
  align-items: flex-start !important;
  /* 字号抬上来之后，统一的 6u gap 会让「眉标—中文名—英文名」挤成一块，
     改成各自用 margin 控制，标题组内部贴紧、组与组之间拉开 */
  gap: 0 !important;
  overflow: visible !important;
  background: transparent !important;
  text-align: left !important;
}

.cover-eyebrow {
  display: inline-flex;
  align-items: center;
  height: calc(24 * var(--u));
  padding: 0 calc(10 * var(--u));
  margin: 0 !important;
  font-size: var(--le-fs-sm) !important;
  font-weight: 500 !important;
  letter-spacing: 0 !important;
  color: var(--le-ink) !important;
  background: var(--le-cyan) !important;
  border-radius: calc(6 * var(--u)) !important;
  text-transform: none !important;
  margin: 0 0 calc(11 * var(--u)) !important;
}

.cover-title {
  margin: calc(5 * var(--u)) 0 0 !important;
  font-size: calc(37 * var(--u)) !important;
  line-height: 1.15 !important;
  font-weight: 700 !important;
  letter-spacing: 0 !important;
  color: var(--le-navy) !important;
  display: block !important;
}

.cover-title span {
  display: block !important;
}

.cover-title-zh {
  margin: 0 !important;
  font-size: var(--le-fs-title) !important;
  font-weight: 600 !important;
  line-height: 1.3 !important;
  color: var(--le-ink) !important;
}

.cover-pitch {
  margin: 0 !important;
  /* 17u 时「雾起时，你的一句话，就是一千支箭。」刚好折成孤字行，
     压到 16u 就能一行放下，同时仍比原稿大 */
  font-size: calc(16 * var(--u)) !important;
  line-height: 1.5 !important;
  color: var(--le-ink-2) !important;
  max-width: 100%;
  margin: calc(9 * var(--u)) 0 0 !important;
}

.cover-scroll .btn-lg {
  margin-top: calc(15 * var(--u)) !important;
  width: auto !important;
  min-width: calc(96 * var(--u));
  /* 字号在 look.css 的 `.screen-cover .cover-scroll > .btn` 里定
     （那条 specificity 更高，这里写 font-size 也压不住，别在这儿重复写）。 */
}

.cover-note {
  margin: 0 !important;
  font-size: var(--le-fs-sm) !important;
  line-height: 1.5 !important;
  /* 设计稿小字用 #999，但这一行是「请横屏 / 要麦克风」的必要提示，
     在真机 12px 下 #999 对白底只有 2.8:1，读不出来，压深一档到 #666 */
  color: var(--le-ink-2) !important;
  margin: calc(11 * var(--u)) 0 0 !important;
}

/* ------------------------------------------------------------------ 故事页 */
.screen-story {
  display: grid !important;
  grid-template-columns: var(--le-col-left) var(--le-col-right) !important;
  grid-template-rows: auto 1fr !important;
  gap: calc(4 * var(--u)) var(--le-gutter) !important;
  padding: calc(12 * var(--u)) var(--le-pad-x) calc(14 * var(--u)) !important;
  align-items: start !important;
}

.screen-story .stage {
  position: relative !important;
  inset: auto !important;
  grid-column: 1 !important;
  grid-row: 2 !important;
  width: 100% !important;
  height: auto !important;
  aspect-ratio: auto !important;
  height: 100% !important;
  min-height: 0 !important;
  align-self: stretch !important;
  border-radius: var(--le-r-card) !important;
  overflow: hidden !important;
  background: var(--le-navy) !important;
  box-shadow: var(--le-shadow) !important;
}

.side {
  grid-column: 2 !important;
  grid-row: 2 !important;
  min-height: 0 !important;
  height: 100% !important;
  display: flex !important;
  flex-direction: column !important;
  align-items: stretch !important;
  justify-content: center !important;
  gap: calc(8 * var(--u)) !important;
  position: relative !important;
  /* 底部预留手指气泡的高度，否则卡片会一路顶到屏幕下沿，气泡贴边 */
  padding-bottom: calc(42 * var(--u)) !important;
  box-sizing: border-box !important;
}

/* 旁白：设计稿里的「问题1」标签 + 题干 */
.narrator {
  position: static !important;
  inset: auto !important;
  width: auto !important;
  max-width: none !important;
  margin: 0 !important;
  padding: 0 calc(6 * var(--u)) 0 0 !important;
  background: transparent !important;
  border: none !important;
  border-radius: 0 !important;
  box-shadow: none !important;
  display: block !important;
  position: relative !important;
  flex: 0 0 auto !important;
}

.narrator-text {
  margin: 0 !important;
  /* 右侧留出喇叭的位置：喇叭从 26u 抬到 36u 后，这里也要跟着加宽，
     否则第一行文字会钻到圆按钮底下 */
  padding-right: calc(46 * var(--u));
  /* 旁白是"大人念给我听"的背景信息，台词才是我要说的那一句。
     整体字号抬上来之后旁白如果跟台词同级，四行就装不下一段话了 ——
     所以旁白固定比台词低一档，优先级靠字号差表达，而不是靠截断。
     行数上限给 5 行：最长的一页（第 8 页，26 词）正好要 5 行，
     卡在 4 行会把最后一句 "Zhuge Liang smiles at the river." 整句吃掉。
     万一还有更长的页（换故事以后），app.js 的 fitNarrator 会再降一档字号兜底。 */
  font-size: var(--le-fs-sm) !important;
  font-weight: 500 !important;
  line-height: 1.45 !important;
  color: var(--le-ink-2) !important;
  max-height: calc(130 * var(--u));
  overflow: hidden;
  display: -webkit-box;
  -webkit-line-clamp: 5;
  -webkit-box-orient: vertical;
}

/* 装不下时先降一档字号，再降一档。宁可小 1–2u，也不能少一句 */
.narrator-text.is-tight {
  font-size: calc(16 * var(--u)) !important;
}

.narrator-text.is-tighter {
  font-size: calc(15 * var(--u)) !important;
  line-height: 1.38 !important;
}

/* 重听小按钮：右上角，与设计稿「继续」同量级 */
.narrator-replay {
  position: absolute !important;
  top: 0 !important;
  right: 0 !important;
  width: calc(36 * var(--u)) !important;
  height: calc(36 * var(--u)) !important;
  display: inline-flex !important;
  align-items: center !important;
  justify-content: center !important;
  background: var(--le-card) !important;
  border: 1px solid var(--le-line) !important;
  border-radius: 50% !important;
  padding: 0 !important;
  font-size: calc(13 * var(--u)) !important;
  color: var(--le-ink-2) !important;
  box-shadow: none !important;
}

/* 台词卡：白卡 r20，装「跟读」内容 */
.linebar {
  position: relative !important;
  inset: auto !important;
  flex: 0 0 auto !important;
  min-height: 0 !important;
  display: flex !important;
  flex-direction: column !important;
  align-items: flex-start !important;
  justify-content: flex-start !important;
  gap: calc(4 * var(--u)) !important;
  padding: calc(14 * var(--u)) calc(16 * var(--u)) !important;
  background: var(--le-card) !important;
  border: none !important;
  border-radius: var(--le-r-card) !important;
  box-shadow: var(--le-shadow) !important;
  overflow: hidden !important;
}

/* 空卡里那圈声波环去掉——朗文的卡片里不放装饰 */
.linebar::after {
  display: none !important;
}

.linebar-task {
  font-size: var(--le-fs-sm) !important;
  font-weight: 500 !important;
  letter-spacing: 0 !important;
  color: var(--le-ink-3) !important;
  background: transparent !important;
  /* 右上角留给「跳过」。
     原来这里写的是「跳过这一页」，字号抬到 17u 后光按钮就吃掉 111u，
     任务行被挤到折行、还钻到按钮底下（"谢谢你，曹操。"会断成"操。"）。
     换成两个字既够明确，也把任务行还给整行宽度。 */
  padding: 0 calc(62 * var(--u)) 0 0 !important;
  border-radius: 0 !important;
}

.linebar-line {
  font-size: var(--le-fs-line) !important;
  font-weight: 500 !important;
  line-height: 1.34 !important;
  color: var(--le-ink) !important;
  margin: 0 !important;
}

.linebar-zh {
  font-size: var(--le-fs-sm) !important;
  line-height: 1.4 !important;
  color: var(--le-ink-3) !important;
  margin: 0 !important;
}

.linebar-actions {
  margin-top: calc(10 * var(--u)) !important;
  width: 100% !important;
  display: flex !important;
  align-items: center !important;
  gap: calc(8 * var(--u)) !important;
}

.linebar-actions .btn-ghost {
  flex: 0 1 auto !important;
  height: calc(34 * var(--u)) !important;
  font-size: var(--le-fs-sm) !important;
  padding: 0 calc(12 * var(--u)) !important;
}

.linebar-actions .btn-talk {
  margin-left: auto !important;
  height: calc(40 * var(--u)) !important;
}

/* 跟读示范时的绿色高亮：设计稿用 #1BBC40 平铺当前句 */
.linebar.is-demoing .linebar-line {
  background: linear-gradient(transparent 62%, var(--le-green-l) 62%) !important;
  border-radius: calc(3 * var(--u));
}

.skip {
  top: auto !important;
}

/* 「跳过这一页」原来是卡片最底下的一行，正好卡在「按住说」和手指气泡中间，
   把气泡顶到离按钮很远的位置。挪到卡片右上角，与任务行同一水平，
   卡片底部就只剩按钮，气泡能直接贴在按钮下面。 */
.screen-story .skip {
  position: absolute !important;
  top: calc(9 * var(--u)) !important;
  right: calc(14 * var(--u)) !important;
  margin: 0 !important;
  align-self: auto !important;
  height: calc(26 * var(--u)) !important;
  padding: 0 calc(6 * var(--u)) !important;
  background: transparent !important;
  color: var(--le-ink-3) !important;
  border: none !important;
  font-weight: 500 !important;
  font-size: var(--le-fs-sm) !important;
  white-space: nowrap !important;
  z-index: 2 !important;
}

/* 手指引导：贴住「按住说」按钮的正下方，右边缘与按钮对齐，箭头朝上指回去。
   tip 现在挂在 .linebar 内部（DOM 里跟着按钮走），所以定位基准是台词卡。 */
.linebar:has(.js-finger) {
  overflow: visible !important;
}

.finger-tip {
  position: absolute !important;
  left: auto !important;
  right: calc(16 * var(--u)) !important;
  top: calc(100% - calc(6 * var(--u))) !important;
  bottom: auto !important;
  max-width: calc(300 * var(--u));
  padding: calc(6 * var(--u)) calc(12 * var(--u)) !important;
  background: var(--le-navy) !important;
  color: #ffffff !important;
  border: none !important;
  border-radius: calc(10 * var(--u)) !important;
  font-size: var(--le-fs-sm) !important;
  font-weight: 500 !important;
  white-space: nowrap !important;
  box-shadow: var(--le-shadow-lift) !important;
}

/* style.css 的箭头是一个朝下的旋转方块，在原位置（按钮上方）够用；
   挪到卡片下方后它朝错方向，且 5px 的露出量在白底上根本看不见。
   换成 border 画的实心朝上三角：16×9 设计像素，压在白卡上，一眼能读到方向。 */
.finger-tip::after {
  content: "" !important;
  /* 气泡与「按住说」按钮同宽同位，箭头居中即指向按钮中心 */
  left: 50% !important;
  right: auto !important;
  top: calc(-8 * var(--u)) !important;
  bottom: auto !important;
  width: 0 !important;
  height: 0 !important;
  margin: 0 0 0 calc(-8 * var(--u)) !important;
  background: transparent !important;
  border: none !important;
  border-left: calc(8 * var(--u)) solid transparent !important;
  border-right: calc(8 * var(--u)) solid transparent !important;
  border-bottom: calc(9 * var(--u)) solid var(--le-navy) !important;
  transform: none !important;
}

/* ------------------------------------------------------------------ 反馈 */
/* 反馈卡要和右侧内容栏对齐（左插画栏不能被压住）。
   look.css 用 50% 定位是靠「两栏近似等宽」，这里两栏是 52.2% / 41.1%，
   直接把定位算成「内容栏左边界」：pad + 0.522×(100% − 2·pad) + gutter
   = 52.2% + gutter − 0.044·pad                                        */
.feedback {
  position: absolute !important;
  left: calc(52.2% + var(--le-gutter) - 0.044 * var(--le-pad-x)) !important;
  right: var(--le-pad-x) !important;
  bottom: calc(14 * var(--u)) !important;
  top: auto !important;
  max-width: none !important;
  transform: none !important;
  padding: calc(12 * var(--u)) calc(16 * var(--u)) !important;
  background: var(--le-card) !important;
  border-radius: var(--le-r-card) !important;
  box-shadow: var(--le-shadow-lift) !important;
  border: none !important;
  color: var(--le-ink) !important;
  z-index: 35 !important;
}

.feedback.is-in {
  opacity: 1 !important;
  transform: none !important;
}

/* 反馈卡是「替换」台词卡，不是叠上去：出结果时把台词卡和手指标记藏掉，
   否则按钮会从卡片边上露出来，两层白卡互相压着看得很脏 */
.screen-story:has(.feedback:not([hidden])) .linebar,
.screen-story:has(.feedback:not([hidden])) .finger-tip {
  opacity: 0 !important;
  visibility: hidden !important;
  pointer-events: none !important;
}

.feedback .btn {
  margin-top: calc(6 * var(--u)) !important;
  height: calc(30 * var(--u)) !important;
  border-radius: var(--le-r-btn) !important;
  font-size: var(--le-fs-btn) !important;
}

.feedback-stars {
  color: var(--le-warn) !important;
  font-size: calc(20 * var(--u)) !important;
  letter-spacing: calc(1 * var(--u)) !important;
  text-shadow: none !important;
}

.feedback-echo {
  font-size: var(--le-fs-btn) !important;
  color: var(--le-ink-2) !important;
}

.feedback-plot {
  font-size: var(--le-fs-sm) !important;
  line-height: 1.5 !important;
  color: var(--le-ink-2) !important;
}

.feedback.band--great {
  border-left: calc(3 * var(--u)) solid var(--le-green) !important;
}

.feedback.band--ok {
  border-left: calc(3 * var(--u)) solid var(--le-warn) !important;
}

.feedback.band--retry {
  border-left: calc(3 * var(--u)) solid var(--le-accent) !important;
}

/* ------------------------------------------------------------------ 答题 */
.screen-quiz {
  display: grid !important;
  grid-template-columns: var(--le-col-left) var(--le-col-right) !important;
  grid-template-rows: auto 1fr !important;
  gap: calc(4 * var(--u)) var(--le-gutter) !important;
  padding: calc(12 * var(--u)) var(--le-pad-x) calc(16 * var(--u)) !important;
  align-items: start !important;
}

.screen-quiz .stage--dim {
  position: relative !important;
  inset: auto !important;
  grid-column: 1 !important;
  grid-row: 2 !important;
  width: 100% !important;
  height: auto !important;
  aspect-ratio: auto !important;
  height: 100% !important;
  min-height: 0 !important;
  align-self: stretch !important;
  border-radius: var(--le-r-card) !important;
  overflow: hidden !important;
  opacity: 1 !important;
  filter: none !important;
  box-shadow: var(--le-shadow) !important;
}

.quiz-scrim {
  display: none !important;
}

.screen-quiz .stage--dim,
.screen-story .stage,
.screen-cover .stage,
.screen-dubbing .stage {
  display: block !important;
}

.quiz-body {
  position: relative !important;
  inset: auto !important;
  grid-column: 2 !important;
  grid-row: 2 !important;
  width: 100% !important;
  max-width: none !important;
  max-height: 100% !important;
  margin: 0 !important;
  padding: 0 !important;
  background: transparent !important;
  border: none !important;
  border-radius: 0 !important;
  box-shadow: none !important;
  display: flex !important;
  flex-direction: column !important;
  align-items: stretch !important;
  justify-content: flex-start !important;
  gap: calc(8 * var(--u)) !important;
  overflow-y: auto !important;
  -webkit-overflow-scrolling: touch;
}

.quiz-prompt {
  margin: 0 !important;
  font-size: var(--le-fs-q) !important;
  font-weight: 600 !important;
  line-height: 1.34 !important;
  color: var(--le-ink) !important;
  flex: 0 0 auto;
}

.quiz-prompt-zh {
  margin: 0 !important;
  font-size: var(--le-fs-sm) !important;
  line-height: 1.4 !important;
  color: var(--le-ink-3) !important;
  flex: 0 0 auto;
}

.quiz-options {
  display: flex !important;
  flex-direction: column !important;
  gap: calc(8 * var(--u)) !important;
  margin-top: calc(2 * var(--u)) !important;
  width: 100% !important;
}

/* 选项 = 28×28 字母徽章 + 药丸选项条
   数值来自设计稿 41:6678 / 41:6639：
   药丸 280×40 r245，白底 + 白描边，靠「内下浅蓝 + 外发光」托起来，不用灰线；
   徽章 28×28 r9.87，绿底白字、白色 1px 描边、带一点倾斜。 */
.quiz-opt {
  position: relative !important;
  width: 100% !important;
  min-height: calc(38 * var(--u)) !important;
  padding: calc(5 * var(--u)) calc(12 * var(--u)) calc(5 * var(--u)) calc(42 * var(--u)) !important;
  display: flex !important;
  flex-wrap: wrap !important;
  align-items: center !important;
  column-gap: calc(8 * var(--u)) !important;
  background: var(--le-card) !important;
  border: 1px solid #ffffff !important;
  border-radius: var(--le-r-pill) !important;
  box-shadow: inset 0 calc(-4 * var(--u)) calc(6 * var(--u)) #d0f5fe,
    0 calc(4 * var(--u)) calc(10 * var(--u)) rgba(133, 204, 235, 0.5) !important;
  text-align: left !important;
  color: var(--le-ink) !important;
  transition: background 0.15s ease, box-shadow 0.15s ease !important;
}

.quiz-opt .qicon {
  position: absolute !important;
  left: calc(6 * var(--u)) !important;
  top: 50% !important;
  transform: translateY(-50%) rotate(-8deg) !important;
  width: calc(28 * var(--u)) !important;
  height: calc(28 * var(--u)) !important;
  border-radius: calc(10 * var(--u)) !important;
  background: var(--le-green) !important;
  color: #ffffff !important;
  font-size: var(--le-fs-h2) !important;
  font-weight: 700 !important;
  display: flex !important;
  align-items: center !important;
  justify-content: center !important;
  border: 1px solid #ffffff !important;
  box-shadow: 0 calc(3 * var(--u)) calc(8 * var(--u)) rgba(126, 184, 209, 0.5) !important;
  line-height: 1 !important;
}

.quiz-opt-label {
  font-size: var(--le-fs-btn) !important;
  font-weight: 500 !important;
  line-height: 1.34 !important;
  color: var(--le-ink) !important;
}

.quiz-opt-zh {
  font-size: var(--le-fs-sm) !important;
  line-height: 1.34 !important;
  color: var(--le-ink-3) !important;
  flex-basis: 100% !important;
}

.quiz-opt.is-right {
  background: var(--le-green-l) !important;
  border: calc(2 * var(--u)) solid var(--le-green) !important;
  box-shadow: 0 calc(4 * var(--u)) calc(12 * var(--u)) rgba(96, 178, 122, 0.34) !important;
}

/* 判断对错只靠形状 + 颜色，不靠声音。
   只换底色不够：小孩分辨"这题我答了没有、对不对"需要两个强信号 ——
   勾/叉（形状）和绿/红（颜色），任一个看不清还有另一个兜着。 */
.quiz-mark {
  position: absolute !important;
  right: calc(10 * var(--u)) !important;
  top: 50% !important;
  transform: translateY(-50%) !important;
  width: calc(24 * var(--u)) !important;
  height: calc(24 * var(--u)) !important;
  border-radius: 50% !important;
  display: none !important;
  align-items: center !important;
  justify-content: center !important;
  font-size: calc(15 * var(--u)) !important;
  font-weight: 700 !important;
  line-height: 1 !important;
  color: #ffffff !important;
}

.quiz-opt.is-right .quiz-mark,
.quiz-opt.is-wrong .quiz-mark {
  display: flex !important;
}

.quiz-opt.is-right .quiz-mark {
  background: var(--le-green) !important;
}

.quiz-opt.is-wrong .quiz-mark {
  background: var(--le-accent) !important;
}

.quiz-opt.is-right .qicon {
  background: var(--le-green) !important;
  color: #ffffff !important;
}

.quiz-opt.is-wrong {
  background: var(--le-accent-l) !important;
  border: calc(2 * var(--u)) solid var(--le-accent) !important;
  box-shadow: 0 calc(4 * var(--u)) calc(12 * var(--u)) rgba(214, 108, 96, 0.3) !important;
}

.quiz-opt.is-wrong .qicon {
  background: var(--le-accent) !important;
  color: #ffffff !important;
}

/* 答题后的结论行和「跳过」共用一行：答题前是跳过，答完就地变成结论，
   布局不跳、也不会多挤出一行把选项顶出可视区。 */
.quiz-foot {
  position: relative !important;
  display: flex !important;
  align-items: center !important;
  justify-content: flex-end !important;
  min-height: calc(26 * var(--u)) !important;
  margin-top: calc(2 * var(--u)) !important;
  width: 100% !important;
}

/* 答题后「跳过」让位给结论行。
   .skip 本身带 display:inline-flex !important，单靠 hidden 属性盖不住。 */
.quiz-foot .skip[hidden] {
  display: none !important;
}

.quiz-verdict {
  margin: 0 !important;
  padding: 0 calc(10 * var(--u)) !important;
  height: calc(26 * var(--u)) !important;
  display: flex !important;
  align-items: center !important;
  border-radius: var(--le-r-pill) !important;
  font-size: var(--le-fs-sm) !important;
  font-weight: 600 !important;
  line-height: 1 !important;
  white-space: nowrap !important;
}

.quiz-verdict[hidden] {
  display: none !important;
}

.quiz-verdict.is-right {
  color: #1f6b3b !important;
  background: var(--le-green-l) !important;
}

.quiz-verdict.is-wrong {
  color: #9c3527 !important;
  background: var(--le-accent-l) !important;
}

.screen-quiz .skip {
  position: static !important;
  margin-top: calc(2 * var(--u)) !important;
  align-self: flex-end !important;
  height: calc(26 * var(--u)) !important;
  padding: 0 calc(8 * var(--u)) !important;
  background: transparent !important;
  color: var(--le-ink-3) !important;
  border: none !important;
  font-weight: 500 !important;
  font-size: var(--le-fs-sm) !important;
  flex: 0 0 auto !important;
}

/* ------------------------------------------------------------------ 配音 */
.screen-dubbing {
  display: grid !important;
  grid-template-columns: var(--le-col-left) var(--le-col-right) !important;
  grid-template-rows: auto auto 1fr !important;
  gap: calc(4 * var(--u)) var(--le-gutter) !important;
  padding: calc(12 * var(--u)) var(--le-pad-x) calc(16 * var(--u)) !important;
  align-items: start !important;
}

.screen-dubbing .stage {
  position: relative !important;
  inset: auto !important;
  grid-column: 1 !important;
  grid-row: 2 / span 2 !important;
  width: 100% !important;
  height: auto !important;
  aspect-ratio: auto !important;
  height: 100% !important;
  min-height: 0 !important;
  align-self: stretch !important;
  border-radius: var(--le-r-card) !important;
  overflow: hidden !important;
  box-shadow: var(--le-shadow) !important;
}

.dub-lead {
  grid-column: 2 !important;
  grid-row: 2 !important;
  margin: 0 !important;
  /* 首字「现」的左边旁压到栅格起点被裁掉。字号从 16u 抬到 19u 后
     2u 的出血位又不够了，加到 7u（真机约 6px），左旁才能完整露出。 */
  padding-left: calc(7 * var(--u)) !important;
  font-size: var(--le-fs-q) !important;
  font-weight: 600 !important;
  line-height: 1.34 !important;
  color: var(--le-ink) !important;
}

.dub-panel {
  position: relative !important;
  inset: auto !important;
  grid-column: 2 !important;
  grid-row: 3 !important;
  width: 100% !important;
  min-height: 0 !important;
  display: flex !important;
  flex-direction: column !important;
  gap: calc(6 * var(--u)) !important;
  /* 和第 2 行「现在，你来配音」共用一个出血位：中文首字（现 / 前 / 请…）
     的字形左边界会略微超出 em 框，贴齐栅格起点会被裁掉半个偏旁。
     放在容器上而不是逐个元素补，规则只需要理解一次。 */
  padding: 0 0 0 calc(7 * var(--u)) !important;
  background: transparent !important;
  border: none !important;
  box-shadow: none !important;
  overflow-y: auto !important;
  -webkit-overflow-scrolling: touch;
}

.dub-lines {
  display: flex !important;
  flex-direction: column !important;
  gap: calc(6 * var(--u)) !important;
}

.dub-line {
  background: var(--le-card) !important;
  border: 1px solid var(--le-line) !important;
  border-radius: var(--le-r-pill) !important;
  padding: calc(6 * var(--u)) calc(12 * var(--u)) !important;
  min-height: calc(34 * var(--u)) !important;
  display: flex !important;
  align-items: center !important;
  gap: calc(8 * var(--u)) !important;
  box-shadow: none !important;
  animation: none !important;
}

.dub-line.is-active {
  border-color: var(--le-primary) !important;
  background: var(--le-card) !important;
  box-shadow: 0 0 0 calc(2 * var(--u)) rgba(100, 175, 255, 0.16) !important;
}

.dub-line.is-done {
  background: var(--le-green-l) !important;
  border-color: transparent !important;
}

/* 沿用前文录音的状态：用主色 + 虚线下划线，跟"待录"的灰字区分开，
   同时暗示这一项可以点 */
.dub-state.is-reuse {
  color: var(--le-primary) !important;
  font-weight: 600 !important;
  text-decoration: underline dotted;
  text-underline-offset: calc(2 * var(--u));
  cursor: pointer;
}

.dub-text {
  font-size: var(--le-fs-btn) !important;
  line-height: 1.34 !important;
  color: var(--le-ink) !important;
  flex: 1 1 auto !important;
  min-width: 0 !important;
}

.dub-hear,
.dub-no {
  /* 26u ≈ 23.6px 真机，既是喇叭图标也是点击热区，偏小；两次抬到 34u
     图标连带放大，同时把热区做到 31px，孩子手指点得中 */
  width: calc(34 * var(--u)) !important;
  height: calc(34 * var(--u)) !important;
  border-radius: 50% !important;
  background: var(--le-bg) !important;
  border: none !important;
  color: var(--le-ink-2) !important;
  font-size: calc(14 * var(--u)) !important;
  display: inline-flex !important;
  align-items: center !important;
  justify-content: center !important;
  box-shadow: none !important;
}

.dub-state {
  font-size: var(--le-fs-sm) !important;
  color: var(--le-ink-3) !important;
  min-width: calc(30 * var(--u));
  flex: 0 0 auto !important;
  white-space: nowrap !important;
  text-align: right;
}

.dub-note {
  font-size: var(--le-fs-xs) !important;
  line-height: 1.4 !important;
  color: var(--le-ink-3) !important;
  margin: 0 !important;
  max-width: 100% !important;
  white-space: normal !important;
  overflow-wrap: anywhere !important;
}

.dub-actions {
  margin-top: auto !important;
  display: flex !important;
  flex-wrap: wrap !important;
  align-items: center !important;
  gap: calc(8 * var(--u)) !important;
}

/* 右栏垂直空间是这一屏最紧的地方（要装 2–3 句 + 三个按钮 + 一句提示），
   按钮统一压到 38u，比正文页的 40u 略矮，视觉上看不出来，但省出十几像素 */
.dub-actions .btn {
  height: calc(38 * var(--u)) !important;
  padding: 0 calc(14 * var(--u)) !important;
}

.dub-actions > .btn:first-child {
  flex: 1 1 100% !important;
}

.dub-actions > .btn:not(:first-child) {
  flex: 1 1 0 !important;
  background: var(--le-card) !important;
  border: 1px solid var(--le-line) !important;
  color: var(--le-ink-2) !important;
  font-weight: 500 !important;
}

.dub-actions > .btn[disabled],
.dub-actions > .btn:disabled {
  background: var(--le-bg) !important;
  border-color: transparent !important;
  color: var(--le-ink-3) !important;
}

.dub-actions .btn-ghost {
  background: var(--le-card) !important;
  border: 1px solid var(--le-line) !important;
  color: var(--le-ink-2) !important;
}

.dub-note {
  max-width: 100% !important;
}

/* ------------------------------------------------------------------ 成就 */
.screen-achieve {
  display: flex !important;
  align-items: center !important;
  justify-content: center !important;
  padding: calc(16 * var(--u)) var(--le-pad-x) !important;
  overflow-y: auto !important;
}

.achieve-card {
  width: 100% !important;
  max-width: calc(720 * var(--u)) !important;
  max-height: 100% !important;
  padding: calc(18 * var(--u)) calc(24 * var(--u)) !important;
  background: var(--le-card) !important;
  border-radius: calc(24 * var(--u)) !important;
  box-shadow: var(--le-shadow) !important;
  display: grid !important;
  grid-template-columns: auto 1fr !important;
  grid-template-rows: auto auto auto 1fr auto !important;
  align-items: center !important;
  justify-items: start !important;
  column-gap: calc(20 * var(--u)) !important;
  row-gap: calc(4 * var(--u)) !important;
  text-align: left !important;
  overflow: hidden !important;
}

.achieve-art {
  grid-area: 1 / 1 / 3 / 2 !important;
  width: calc(150 * var(--u)) !important;
  height: auto !important;
  margin: 0 !important;
}

.achieve-eyebrow {
  grid-area: 1 / 2 / 2 / 3 !important;
  justify-self: start !important;
  height: calc(22 * var(--u));
  padding: 0 calc(10 * var(--u));
  display: inline-flex;
  align-items: center;
  font-size: var(--le-fs-sm) !important;
  font-weight: 500 !important;
  letter-spacing: 0 !important;
  color: var(--le-ink) !important;
  background: var(--le-cyan) !important;
  border-radius: calc(6 * var(--u)) !important;
}

.achieve-title {
  grid-area: 2 / 2 / 3 / 3 !important;
  margin: 0 !important;
  font-size: calc(35 * var(--u)) !important;
  font-weight: 700 !important;
  line-height: 1.2 !important;
  color: var(--le-navy) !important;
  letter-spacing: calc(1 * var(--u)) !important;
}

.achieve-sub {
  grid-area: 3 / 1 / 4 / 3 !important;
  margin: calc(2 * var(--u)) 0 0 !important;
  font-size: var(--le-fs-sm) !important;
  line-height: 1.5 !important;
  color: var(--le-ink-3) !important;
}

.achieve-stats {
  grid-area: 4 / 1 / 5 / 3 !important;
  align-self: start !important;
  width: 100% !important;
  display: flex !important;
  gap: calc(10 * var(--u)) !important;
  margin-top: calc(10 * var(--u)) !important;
}

.achieve-stats > * {
  flex: 1 1 0 !important;
  min-width: 0 !important;
  padding: calc(8 * var(--u)) calc(10 * var(--u)) !important;
  background: var(--le-bg) !important;
  border-radius: calc(12 * var(--u)) !important;
  border: none !important;
  box-shadow: none !important;
}

.achieve-actions {
  grid-area: 5 / 2 / 6 / 3 !important;
  justify-self: end !important;
  display: flex !important;
  gap: calc(8 * var(--u)) !important;
  margin-top: calc(8 * var(--u)) !important;
}

.report-entry {
  grid-area: 5 / 1 / 6 / 2 !important;
  justify-self: start !important;
  align-self: center !important;
  margin-top: calc(8 * var(--u)) !important;
  height: calc(30 * var(--u)) !important;
  padding: 0 calc(12 * var(--u)) !important;
  background: var(--le-bg) !important;
  color: var(--le-ink-2) !important;
  border: none !important;
  border-radius: var(--le-r-pill) !important;
  font-size: var(--le-fs-sm) !important;
  font-weight: 500 !important;
  box-shadow: none !important;
}

/* ------------------------------------------------------------------ 报告 */
/* 家长报告是这块体验唯一的"成年人页面"：孩子看到的是雾、船、箭，
   家长看到的必须是一份能读懂、能带走的判断。
   所以这一屏不用表格（表格像后台报表），改成
   左栏「一眼看懂 + 三个维度」、右栏「逐句表现」的两段式。 */

.screen-report {
  display: flex !important;
  flex-direction: column !important;
  padding: calc(12 * var(--u)) var(--le-pad-x) calc(14 * var(--u)) !important;
  gap: calc(6 * var(--u)) !important;
}

.report-date {
  margin-left: calc(10 * var(--u));
  padding: 0 calc(10 * var(--u));
  height: calc(24 * var(--u));
  display: inline-flex;
  align-items: center;
  font-size: var(--le-fs-sm) !important;
  font-weight: 500 !important;
  color: var(--le-ink-3) !important;
  background: var(--le-card);
  border-radius: var(--le-r-pill);
  white-space: nowrap;
}

.report-date + .hud-close {
  margin-left: auto;
}

.report-grid {
  flex: 1 1 auto;
  min-height: 0;
  display: grid !important;
  grid-template-columns: 36% minmax(0, 1fr) !important;
  gap: calc(16 * var(--u)) !important;
  align-items: stretch !important;
}

.report-col {
  min-width: 0;
  min-height: 0;
  display: flex;
  flex-direction: column;
  gap: calc(9 * var(--u));
}

.report-col--right {
  gap: calc(6 * var(--u));
}

/* ---- 左栏：这一趟的总账 ---- */
.report-hero {
  padding: calc(13 * var(--u)) calc(15 * var(--u)) calc(12 * var(--u));
  background: var(--le-card);
  border-radius: var(--le-r-card);
  box-shadow: var(--le-shadow);
  flex: 0 0 auto;
}

.report-hero-top {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: calc(8 * var(--u));
}

.report-hero-label {
  margin: 0 0 calc(2 * var(--u));
  font-size: var(--le-fs-sm);
  font-weight: 500;
  color: var(--le-ink-3);
}

.report-hero-num {
  margin: 0;
  font-size: calc(34 * var(--u));
  font-weight: 700;
  line-height: 1;
  color: var(--le-navy);
  font-variant-numeric: tabular-nums;
}

.report-hero-num span {
  margin-left: calc(3 * var(--u));
  font-size: var(--le-fs-sm);
  font-weight: 500;
  color: var(--le-ink-3);
}

/* 箭数用绿色，和成就页的主色呼应：这一趟"兑现"了什么
   竖排 + 右对齐：中文数字一长（"十一万五千"）横排会把右边界顶穿，
   而左栏是定宽 36%，一顶穿就把下面那句评语挤掉一行。 */
.report-arrow {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: calc(2 * var(--u));
  line-height: 1.1;
  white-space: nowrap;
  flex: 0 0 auto;
  min-width: 0;
}

.report-arrow b {
  font-size: calc(19 * var(--u));
  font-weight: 700;
  color: var(--le-green);
}

.report-arrow span {
  font-size: var(--le-fs-xs);
  color: var(--le-ink-3);
}

.report-bar {
  margin: calc(10 * var(--u)) 0 calc(7 * var(--u));
  height: calc(7 * var(--u));
  border-radius: 999px;
  background: var(--le-bg);
  overflow: hidden;
}

.report-bar i {
  display: block;
  height: 100%;
  border-radius: 999px;
  background: linear-gradient(90deg, #8ecbff, var(--le-primary));
}

.report-hero-foot {
  margin: 0;
  font-size: var(--le-fs-xs);
  color: var(--le-ink-3);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.report-hero-foot em {
  font-style: normal;
  margin: 0 calc(3 * var(--u));
  color: var(--le-line);
}

/* ---- 三个维度：条形而不是环形。横屏高度只有 340px，
        环形放三个必然压到 60px 以下，读数比看形状重要 ---- */
.report-dims {
  padding: calc(10 * var(--u)) calc(15 * var(--u));
  background: var(--le-card);
  border-radius: var(--le-r-card);
  box-shadow: var(--le-shadow);
  display: flex;
  flex-direction: column;
  gap: calc(7 * var(--u));
  flex: 0 0 auto;
}

.report-dim {
  display: flex;
  align-items: center;
  gap: calc(8 * var(--u));
}

.report-dim-label {
  flex: 0 0 calc(72 * var(--u));
  font-size: var(--le-fs-xs);
  font-weight: 500;
  color: var(--le-ink-2);
  white-space: nowrap;
}

.report-dim-track {
  flex: 1 1 auto;
  min-width: 0;
  height: calc(6 * var(--u));
  border-radius: 999px;
  background: var(--le-bg);
  overflow: hidden;
}

.report-dim-track i {
  display: block;
  height: 100%;
  border-radius: 999px;
  background: var(--le-primary);
}

.report-dim:nth-child(2) .report-dim-track i {
  background: #5fc98a;
}

.report-dim:nth-child(3) .report-dim-track i {
  background: #ffb454;
}

.report-dim-val {
  flex: 0 0 calc(26 * var(--u));
  text-align: right;
  font-size: var(--le-fs-sm);
  font-weight: 700;
  color: var(--le-ink);
  font-variant-numeric: tabular-nums;
}

/* ---- 一句话结论：家长真正会读的那一行 ---- */
.report-verdict {
  margin: 0 !important;
  padding: calc(10 * var(--u)) calc(14 * var(--u));
  flex: 1 1 auto;
  /* 以前这块高度完全由"左栏剩下的空隙"决定，而它又是 overflow-y:auto：
     上方箭数一折行、高度一被吃掉，最后一行就被无声裁掉，连滚动条都没有 ——
     家长看到的就是"评语显示不完整"。给它一个三行起跳的地板，宁可它多占几像素。 */
  min-height: calc(62 * var(--u));
  overflow: hidden;
  /* 字数少的时候这块会撑满左栏剩余高度，文字贴着顶部会显得空。
     竖排居中之后，它读起来像一条"结论横幅"而不是一张没写完的卡片。 */
  display: flex;
  align-items: center;
  font-size: var(--le-fs-sm);
  line-height: 1.5;
  font-weight: 500;
  color: #1f4a78;
  background: #eaf4ff;
  border-radius: var(--le-r-card);
  border-left: calc(3 * var(--u)) solid var(--le-primary);
}

/* ---- 右栏：逐句表现 ---- */
.report-lines-title {
  margin: 0;
  font-size: var(--le-fs-sm);
  font-weight: 600;
  color: var(--le-ink-2);
  flex: 0 0 auto;
}

.report-lines {
  margin: 0;
  padding: 0;
  list-style: none;
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  display: flex;
  flex-direction: column;
  gap: calc(4 * var(--u));
}

.report-line {
  display: flex;
  align-items: center;
  gap: calc(9 * var(--u));
  padding: calc(4 * var(--u)) calc(12 * var(--u)) calc(4 * var(--u)) calc(4 * var(--u));
  min-height: calc(29 * var(--u));
  background: var(--le-card);
  border-radius: var(--le-r-pill);
  box-shadow: none;
  font-size: var(--le-fs-sm);
}

.report-line-no {
  flex: 0 0 calc(24 * var(--u));
  width: calc(24 * var(--u));
  height: calc(24 * var(--u));
  border-radius: 50%;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: var(--le-fs-xs);
  font-weight: 700;
  color: #ffffff;
  background: var(--le-ink-3);
}

.report-line-text {
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  color: var(--le-ink);
}

.report-line-band {
  flex: 0 0 auto;
  font-size: var(--le-fs-xs);
  font-weight: 600;
  color: var(--le-ink-3);
  white-space: nowrap;
}

.report-line-stars {
  flex: 0 0 auto;
  font-size: var(--le-fs-xs);
  letter-spacing: calc(0.6 * var(--u));
  color: var(--le-warn);
}

.report-line.band--great .report-line-no {
  background: var(--le-green);
}

.report-line.band--great .report-line-band {
  color: var(--le-green);
}

.report-line.band--ok .report-line-no {
  background: var(--le-warn);
}

.report-line.band--ok .report-line-band {
  color: var(--le-warn);
}

.report-line.band--retry .report-line-no {
  background: var(--le-accent);
}

.report-line.band--retry .report-line-band {
  color: var(--le-accent);
}

.report-line--empty {
  justify-content: center;
  color: var(--le-ink-3);
  font-weight: 500;
}

.report-note {
  margin: 0 !important;
  flex: 0 0 auto;
  font-size: var(--le-fs-xs);
  line-height: 1.5;
  color: var(--le-ink-3);
}

/* ------------------------------------------------------------------ 退出确认 */
/* 原生 confirm() 在 WebView 里是系统弹窗：直角、Android 蓝、按钮写着 Ok / Cancel，
   和整个水墨故事完全两个世界，孩子会以为 App 崩了。这里做一块自己的浮层。 */
.qmask {
  position: fixed;
  inset: 0;
  z-index: 900;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: calc(24 * var(--u));
  background: rgba(24, 18, 63, 0.42);
  opacity: 0;
  transition: opacity 0.18s ease;
  box-sizing: border-box;
}

.qmask.is-in {
  opacity: 1;
}

.qcard {
  width: calc(460 * var(--u));
  max-width: 100%;
  padding: calc(20 * var(--u)) calc(24 * var(--u)) calc(18 * var(--u));
  background: var(--le-card);
  border-radius: calc(24 * var(--u));
  box-shadow: 0 calc(12 * var(--u)) calc(40 * var(--u)) rgba(24, 18, 63, 0.22);
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  transform: scale(0.94);
  transition: transform 0.18s cubic-bezier(0.34, 1.4, 0.64, 1);
  box-sizing: border-box;
}

.qmask.is-in .qcard {
  transform: scale(1);
}

.qcard-art {
  width: calc(66 * var(--u));
  height: calc(66 * var(--u));
  margin-bottom: calc(10 * var(--u));
}

.qcard-art svg {
  width: 100%;
  height: 100%;
  display: block;
}

.qcard-title {
  margin: 0;
  font-size: var(--le-fs-h2);
  font-weight: 700;
  color: var(--le-navy);
  line-height: 1.25;
}

.qcard-text {
  margin: calc(7 * var(--u)) 0 0;
  font-size: var(--le-fs-sm);
  line-height: 1.5;
  color: var(--le-ink-2);
  max-width: 100%;
}

.qcard-actions {
  margin-top: calc(16 * var(--u));
  width: 100%;
  display: flex;
  gap: calc(10 * var(--u));
}

.qcard-actions .btn {
  flex: 1 1 0;
  height: calc(42 * var(--u)) !important;
  font-size: var(--le-fs-btn) !important;
}

/* ------------------------------------------------------------------ 封面返回 */
/* 封面是整段体验的第一屏。系统栏已隐藏、又没给退出口子，
   孩子在真机上只能靠手势 —— 很多人根本不知道有这个手势。 */
.cover-back {
  flex: 0 0 auto;
  width: calc(34 * var(--u));
  height: calc(34 * var(--u));
  padding: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: var(--le-card);
  color: var(--le-ink-2);
  border: none;
  border-radius: 50%;
  box-shadow: var(--le-shadow);
  cursor: pointer;
}

.cover-back svg {
  width: 58%;
  height: 58%;
}

.cover-back:active {
  transform: scale(0.94);
}

/* ------------------------------------------------------------------ 兜底 */
@media (max-height: 470px) {
  .achieve-art {
    width: calc(120 * var(--u)) !important;
  }
  .screen-achieve .achieve-card {
    padding: calc(12 * var(--u)) calc(18 * var(--u)) !important;
  }
}

@media (min-width: 900px) {
  :root {
    --u: 0.088rem;
  }
}

/* ================================================================ 播放态 */
/* 1. 喇叭跟着声音呼吸：播放期间外圈持续扩散，停止立刻收回 —— 让孩子知道
      "现在是它在我说话"，而不是以为页面卡住了。
   2. 正文逐词点亮（卡拉OK）：时间轴来自 assets/audio/timings/*.json，
      由 WordBoundary 落盘，已经按人名替换做过平移。 */

/* 喇叭是 emoji 字形，`color` 对它不起作用 —— 之前只改描边，真机上几乎看不出
   在播。改成三重叠加：浅蓝底（不动 emoji 本体）+ 外圈扩散 + 轻微呼吸缩放，
   三个频率同步（0.95s），一眼能读到"这个喇叭正在响"。 */
/* 喇叭改成内联 SVG（原来是 🔈 emoji）。emoji 是彩色字形，`color`/`fill`
   对它无效，只能靠描边和底色暗示"在响"，真机上几乎看不出。
   换成矢量后：喇叭体吃 currentColor，两道音波弧线可以单独闪烁。 */
.spk {
  display: block;
  width: 84% !important;
  height: 84% !important;
  overflow: visible;
}

.spk-body {
  fill: currentColor;
}

.spk-wave {
  fill: none;
  stroke: currentColor;
  stroke-width: 2.3;
  stroke-linecap: round;
  opacity: 0.85;
}

.narrator-replay.is-speaking,
.dub-hear.is-speaking {
  background: #E1F0FF !important;
  border-color: var(--le-primary) !important;
  /* 主色 #64AFFF 压在 #E1F0FF 上只有 1.9:1，喇叭会糊成一个小点，
     播放态改用深一档的蓝，保证在浅底上清楚可辨 */
  color: #2A6FD0 !important;
  animation: hornPulse 0.95s ease-in-out infinite;
}

/* 播放期间两道音波依次向外扩散，像真的在出声 */
.narrator-replay.is-speaking .spk-wave,
.dub-hear.is-speaking .spk-wave {
  animation: spkWave 1s linear infinite;
}

.narrator-replay.is-speaking .spk-wave:last-of-type,
.dub-hear.is-speaking .spk-wave:last-of-type {
  animation-delay: 0.24s;
}

@keyframes spkWave {
  0% {
    opacity: 0;
  }
  22% {
    opacity: 1;
  }
  100% {
    opacity: 0;
  }
}

@keyframes hornPulse {
  0%,
  100% {
    box-shadow: 0 0 0 0 rgba(100, 175, 255, 0.55);
    transform: scale(1);
  }
  60% {
    box-shadow: 0 0 0 calc(10 * var(--u)) rgba(100, 175, 255, 0);
    transform: scale(1.06);
  }
}

/* 逐词高亮。
   之前是「实心浅蓝块 + 同色外扩」，看上去像整段文字被选中，读起来很吵。
   改成荧光笔式的下半行渐变：只压住字的下半截，既像字幕跑马灯，
   又不会盖掉单词本身的字形。 */
.narrator-text .nw,
.dub-text .nw {
  border-radius: calc(3 * var(--u));
  transition: color 0.1s linear, background 0.12s linear;
}

.narrator-text .nw.is-spoken,
.dub-text .nw.is-spoken {
  color: var(--le-navy) !important;
  background: linear-gradient(180deg, transparent 56%, rgba(100, 175, 255, 0.46) 56%);
  box-shadow: none;
}
