/* Netbook 课程包样式基座（token 版）
 * 设计规范：.agents/skills/ui-design-system/DESIGN-课包端.md（色板、字阶、圆角、儿童适配基线）。
 * 课程包的 styles.css 由 build_package.py 生成：本文件 + 作者目录 stage.css。
 * 类名是播放器模板的接口，改动前先看 assets/player-template.js。
 *
 * 审计约定：本文件（共享基座部分）只允许在 :root token 区出现裸色值/裸圆角，
 * 其余规则一律引用 var(--lk-*)；逐课 stage.css 不受此约束。
 * 正文/舞台字体 = LXGW WenKai（OFL 开源，构建期按课文子集化为 assets/fonts/wenkai.woff2），
 * 缺字形自动回退系统字体。 */

@font-face {
  font-family: 'LXGW WenKai';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('assets/fonts/wenkai.woff2') format('woff2');
}

:root {
  /* ---------- 字体 ---------- */
  --lk-font-body: 'LXGW WenKai', 'PingFang SC', 'Microsoft YaHei', system-ui, sans-serif;

  /* ---------- 品牌 / 行动 ---------- */
  --lk-accent: #f27a50; /* 主行动：按钮、进度条、当前态 */
  --lk-accent-deep: #d75e38; /* 实体按钮投影 */
  --lk-accent-soft: #fff4ef; /* 当前句底、活动入口激活底 */
  --lk-accent-hl: #ffd9c6; /* 逐词高亮底 */
  --lk-accent-hl-ink: #b8431f; /* 逐词高亮文字 */

  /* ---------- 中性 ---------- */
  --lk-bg: #f6f8fc;
  --lk-surface: #ffffff;
  --lk-border: #e4eaf2;
  --lk-border-soft: #eef0f4;
  --lk-ink: #24324a;
  --lk-ink-strong: #233a68;
  --lk-ink-muted: #5f6d85; /* 次要说明，白底 ≥4.5:1 */
  --lk-ink-faint: #77839b; /* 仅 ≥12px 非关键文字 */

  /* ---------- 反馈 ---------- */
  --lk-ok: #237845;
  --lk-ok-soft: #e7f7ed;
  --lk-ok-border: #61c184;
  --lk-ok-edge: #4aa06a; /* SVG 粗描边用的深一档正确绿 */
  --lk-bad: #b84444;
  --lk-bad-soft: #fff0f0;
  --lk-bad-border: #ef8a8a;
  --lk-bad-ink: #d2664f;
  --lk-bad-text: #c24f38;
  --lk-warn: #9b671a;
  --lk-warn-soft: #fff5e8;

  /* ---------- 信息蓝（非行动引导） ---------- */
  --lk-info: #3f6fa8;
  --lk-info-deep: #2b5273;
  --lk-info-soft: #eef4fb;
  --lk-info-hover: #dfeaf7; /* 信息蓝按钮 hover 底 */

  /* ---------- 教具语义（与 stage-kit / 教具库一一对应，绘制层引用同一套值）
   * 橙 = 原有/第一部分，蓝 = 第二部分，绿 = 当前/补进/正确，红 = 错误，压淡 = 拿走 */
  --lk-part-a: #ffb28f;
  --lk-part-a-edge: #d9552f;
  --lk-part-a-soft: #fffaf3;
  --lk-part-a-edge-soft: #e0a98f;
  --lk-part-b: #9cc3ef;
  --lk-part-b-edge: #3f6fa8;
  --lk-part-b-soft: #f2faf4;
  --lk-part-b-edge-soft: #8fc9a8;
  --lk-hot: #7ec7a2;
  --lk-hot-edge: #3f8d63;
  --lk-hot-soft: #bfe3cc; /* 十位块、bar-ok 的大面积浅绿 */
  --lk-stage-ink: #24404d;
  --lk-stage-line: #c9d6dc; /* 教具盒描边 */
  --lk-stage-edge: #b9cee4; /* 胶囊、信息类描边 */
  --lk-stage-card: #fffdf8; /* 教具卡底 */
  --lk-stage-dim: #f4f6f8; /* 压淡底 */
  --lk-stage-line-dim: #cfd8e0;
  --lk-stage-tick: #a9b6bf;
  --lk-stage-arrow: #5d6b73;
  --lk-stage-arrow-dim: #8c9aa6;
  --lk-actor-ring: #b7c8de;
  --lk-pv-block: #ffd9a8;
  --lk-pv-block-edge: #c98a3c;
  --lk-pv-hundred: #cfe0f6;
  --lk-pv-hundred-edge: #4a73a8;
  --lk-bar-a: #ffe1cc;
  --lk-bar-b: #d6e6f8;
  --lk-bar-brace: #6f8fb5;
  --lk-step-bg: #f7fbff;
  --lk-step-edge: #bcd4ef;
  --lk-step-ink: #4a6f9b;
  --lk-step-arrow: #9db8d6;
  --lk-chip-edge: #cfd9e6;
  --lk-chip-hot-ink: #4c8a66;
  --lk-pv-grid: rgba(0, 0, 0, 0.18); /* 位值块内部网格线 */

  /* ---------- 地点底色（教具画布外的情境渐变，配合 data-location） ---------- */
  --lk-loc-huaguo-smart-orchard: linear-gradient(180deg, #e9f6ff 0%, #f1faf0 52%, #e6f4de 100%);
  --lk-loc-gaolao-bakery-hub: linear-gradient(180deg, #fff6ea 0%, #fff9f1 55%, #f8ead8 100%);
  --lk-loc-drift-sand-lab: linear-gradient(180deg, #eef6fb 0%, #f7f5ee 55%, #efe6d2 100%);
  --lk-loc-bailong-express-transit: linear-gradient(180deg, #e8f1ff 0%, #f3f7fd 55%, #e4ebf5 100%);
  --lk-loc-dayan-math-archive: linear-gradient(180deg, #f7f1e6 0%, #fbf8f1 55%, #efe5d3 100%);
  --lk-loc-flame-mountain-energy: linear-gradient(180deg, #fff1e8 0%, #fff8f2 55%, #f9e4d6 100%);
  --lk-loc-water-curtain-maker-lab: linear-gradient(180deg, #e8f7f6 0%, #f3fbfa 55%, #dff0ee 100%);

  /* ---------- 投影（完整 shadow 值作 token，共享区不出现裸色） ---------- */
  --lk-shadow-card: 0 8px 25px #2947790c;
  --lk-shadow-float: 0 6px 26px #2947792e;
  --lk-shadow-toggle: 0 2px 10px #29477926;
  --lk-theater-plate: #fffefbf2; /* 剧场字幕底板（半透明白） */

  /* ---------- 圆角 5 档 ---------- */
  --lk-r-xs: 8px; /* 字幕句底、小标签 */
  --lk-r-sm: 12px; /* 按钮、反馈条、选项 */
  --lk-r-md: 16px; /* 舞台、字幕内件、插图、活动入口 */
  --lk-r-lg: 20px; /* 大卡片 */
  --lk-r-full: 999px; /* 胶囊 */

  /* ---------- 间距（4px 基数） ---------- */
  --lk-s1: 4px;
  --lk-s2: 8px;
  --lk-s3: 12px;
  --lk-s4: 16px;
  --lk-s5: 24px;
  --lk-s6: 32px;

  /* ---------- 字阶（儿童基线） ---------- */
  --lk-f-xs: 12px; /* 辅助标签，仅非关键信息 */
  --lk-f-sm: 14px; /* 解析、说明 */
  --lk-f-md: 18px; /* 正文与字幕基准 */
  --lk-f-lg: 22px; /* 面板标题、答案数字 */
  --lk-f-xl: 28px;

  /* ---------- 触控 ---------- */
  --lk-hit: 48px; /* 一级触控目标最小高 */
}

* {
  box-sizing: border-box;
}
body {
  margin: 0;
  font-family: var(--lk-font-body);
  color: var(--lk-ink);
  background: var(--lk-bg);
  line-height: 1.6;
  letter-spacing: 0.01em;
  -webkit-font-smoothing: antialiased;
}

button,
input {
  font-family: inherit;
  letter-spacing: inherit;
}

.lesson-app {
  max-width: 1180px;
  margin: auto;
  padding: var(--lk-s5) 18px 50px;
}

/* ---------- 顶栏 ---------- */
.lesson-header {
  display: flex;
  align-items: center;
  gap: var(--lk-s3);
  margin-bottom: 22px;
}
/* 品牌徽章：本课第一个出场角色的立绘（构建期由 build_package.py 写进 index.html 的 .brand-sprite）。
 * 立绘是 640×480 的胸像，整幅缩进小方块只看得到衣服，所以用 object-fit 裁到中间再放大取头部；
 * 拿不到立绘时回退成标题首字（.brand-fallback）。 */
.brand-mark {
  width: 52px;
  height: 52px;
  flex: none;
  overflow: hidden;
  display: grid;
  place-items: center;
  background: var(--lk-info-soft);
  border-radius: var(--lk-r-sm);
}
.brand-mark .brand-sprite {
  width: 100%;
  height: 100%;
  display: block;
  object-fit: cover;
  transform: scale(1.5);
  transform-origin: 50% 22%;
}
.brand-mark .brand-fallback {
  font-size: 26px;
  font-weight: 800;
  color: var(--lk-info);
}
.kicker,
.section-label {
  margin: 0;
  color: var(--lk-ink-faint);
  font-size: var(--lk-f-xs);
  font-weight: 800;
  letter-spacing: 0.04em;
}
.lesson-header h1 {
  margin: 0;
  color: var(--lk-ink-strong);
  font-size: clamp(24px, 4vw, 34px);
  line-height: 1.2;
}
.offline-pill {
  margin-left: auto;
  background: var(--lk-ok-soft);
  color: var(--lk-ok);
  padding: 7px 12px;
  border-radius: var(--lk-r-full);
  font-size: var(--lk-f-xs);
  font-weight: 700;
}
.offline-pill span {
  display: inline-block;
  width: 7px;
  height: 7px;
  background: var(--lk-ok-border);
  border-radius: 50%;
  margin-right: 6px;
}

/* ---------- 左舞台右字幕 ---------- */
/* 两张卡同一行，行高由内容多的那张决定：舞台与字幕列表都能纵向伸缩，不把空白留在卡片底部。
 * 所以卡片是 flex 列，舞台（.stage）与字幕列表（.captions）各自 flex:1 吸收多出来的高度。 */
.lesson-grid {
  display: grid;
  grid-template-columns: minmax(0, 1.45fr) minmax(290px, 0.75fr);
  gap: 18px;
}
.stage-card,
.caption-card,
.panel {
  background: var(--lk-surface);
  border: 1px solid var(--lk-border);
  border-radius: var(--lk-r-lg);
  box-shadow: var(--lk-shadow-card);
  padding: 18px;
}
.stage-card,
.caption-card {
  display: flex;
  flex-direction: column;
}
.section-head,
.panel-title {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--lk-s3);
}
.section-head h2,
.panel h2 {
  margin: 1px 0 0;
  color: var(--lk-ink-strong);
  font-size: var(--lk-f-lg);
}

/* ---------- 舞台 ----------
 * 舞台卡不再有自己的标题行（知识点标题在页头，不重复）；画面是卡片第一块内容。 */
.stage {
  flex: 1 1 auto;
  min-height: 355px;
  border-radius: var(--lk-r-md);
  position: relative;
  overflow: hidden;
  background: var(--lk-info-soft);
}
#stage-svg {
  width: 100%;
  height: 100%;
  display: block;
}

/* 全屏按钮浮在舞台右下角：只有图标，说明靠 title/aria-label；
 * 画面内容区（760×320 画布内 24–736 / 16–304）比舞台框略小，所以按钮落在画面外的下白边上。
 * 剧场层里已有“退出全屏”，这里不重复出现。 */
.stage-fullscreen {
  position: absolute;
  right: 8px;
  bottom: 8px;
  z-index: 2;
  width: 40px;
  height: 40px;
  padding: 0;
  display: grid;
  place-items: center;
  cursor: pointer;
  border: 1px solid var(--lk-stage-edge);
  border-radius: var(--lk-r-sm);
  background: var(--lk-surface);
  color: var(--lk-info-deep);
  opacity: 0.82;
}
.stage-fullscreen:hover {
  opacity: 1;
  background: var(--lk-info-soft);
}
.stage-fullscreen .ico {
  width: 20px;
  height: 20px;
}
body.theater .stage-fullscreen {
  display: none;
}

/* ---------- 播放控制条 ----------
 * 两个图标按钮（播放/暂停、从头重播）+ 进度条。进度条跟着按钮走，不再挂在字幕卡底部。 */
.stage-footer {
  display: flex;
  align-items: center;
  gap: var(--lk-s3);
  padding-top: 15px;
}
.ico {
  display: block;
  width: 24px;
  height: 24px;
}
.stage-footer .icon-play,
.stage-footer .icon-btn {
  width: var(--lk-hit);
  min-height: var(--lk-hit);
  padding: 0;
  display: grid;
  place-items: center;
}
.stage-footer .icon-play .ico {
  width: 26px;
  height: 26px;
}
.stage-footer .icon-btn {
  background: var(--lk-info-soft);
  color: var(--lk-info-deep);
}
.stage-footer .icon-btn:hover {
  background: var(--lk-info-hover);
}
/* 播放/暂停是同一个按钮：状态写在 aria-pressed 上，图标由 CSS 换，文字只在 title 里 */
#play .ico-pause {
  display: none;
}
#play[aria-pressed='true'] .ico-play {
  display: none;
}
#play[aria-pressed='true'] .ico-pause {
  display: block;
}
.progress {
  flex: 1 1 auto;
  min-width: 96px;
  height: 8px;
  border-radius: var(--lk-r-full);
  background: var(--lk-border-soft);
  overflow: hidden;
}
.progress i {
  display: block;
  height: 100%;
  width: 0;
  background: var(--lk-accent);
  border-radius: var(--lk-r-full);
  transition: 0.3s;
}
/* 播放状态：平时只给屏幕阅读器（不占版面，也不重复字幕与画面已经说明的事）。
 * 出错时才加上 .error 露出来——按钮点下去没反应必须有个说法，不能一声不响。
 * .voice-status.error 的特异性（0,2,0）高于 .visually-hidden（0,1,0），所以不必写 !important。 */
.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}
.voice-status.error {
  position: static;
  width: auto;
  height: auto;
  margin: var(--lk-s3) 0 0;
  padding: 10px 14px;
  overflow: visible;
  clip-path: none;
  white-space: normal;
  border-radius: var(--lk-r-sm);
  background: var(--lk-bad-soft);
  color: var(--lk-bad);
  font-size: var(--lk-f-sm);
}

/* ---------- 剧场模式：舞台铺满视口，字幕默认关掉 ----------
 * 进入方式：#theater 按钮给 body 加 .theater（player.js 的 toggleTheater）。
 * 字幕默认不显示（画面整幅铺满），#theater-caption 按钮再加 .caption-on 才让出底部条带。
 * 只放大不改色：舞台保留本课 stage.css 的背景（沙地、天空…），换幕布会把舞台画风拖掉。
 * 这里只用 CSS 覆盖层，不依赖原生 Fullscreen API——iPhone Safari 不支持元素级
 * requestFullscreen，而 iframe 嵌入时全屏权限还受父页 allow 属性约束。
 * 用 body.theater 提高特异性：逐课 stage.css 里的 .stage 规则和窄屏媒体查询
 * 都盖不住它，不需要 !important。 */
.stage-caption,
.theater-controls {
  display: none;
}
body.theater {
  overflow: hidden;
}
body.theater .stage {
  position: fixed;
  inset: 0;
  height: 100%;
  margin: 0;
  border-radius: 0;
  z-index: 60;
  /* 背景沿用本课舞台样式，不覆盖。默认不留字幕条带，画面整幅铺满 */
  padding: 0;
}
/* 开了字幕才在底部让出条带，画面不被字幕压住 */
body.theater.caption-on .stage {
  padding: 0 0 clamp(84px, 18vh, 190px);
}
body.theater.caption-on .stage-caption {
  display: flex;
  justify-content: center;
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  padding: var(--lk-s3) clamp(14px, 3vw, 48px) clamp(16px, 3vh, 40px);
}
/* 字幕做成自适应底板：舞台背景是浅底卡片色系，白底深字在任何课上都能读 */
body.theater.caption-on .stage-caption > .sent {
  max-width: min(1100px, 100%);
  padding: 10px clamp(14px, 2.5vw, 30px);
  background: var(--lk-theater-plate);
  color: var(--lk-ink-strong);
  border-radius: var(--lk-r-md);
  font-size: clamp(17px, 3.2vh, 38px);
  line-height: 1.8;
  text-align: center;
  cursor: default;
  box-shadow: var(--lk-shadow-float);
}
body.theater.caption-on .stage-caption .grp.hl {
  background: var(--lk-accent-hl);
  color: var(--lk-accent-hl-ink);
}
/* 深色底上才需要投影的按钮，浅色底同样看得到 */
body.theater .theater-controls {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: var(--lk-s2);
  position: absolute;
  top: 0;
  right: 0;
  z-index: 2;
  padding: 14px;
}
/* 默认只留触发按钮（右上角一小块），点开才铺开全部按钮；面板闲置后自动收回 */
body.theater .theater-controls-panel {
  display: none;
  flex-wrap: wrap;
  justify-content: flex-end;
  gap: var(--lk-s2);
  max-width: min(74vw, 560px);
}
body.theater.controls-open .theater-controls-panel {
  display: flex;
}
body.theater .theater-controls .toggle {
  box-shadow: var(--lk-shadow-toggle);
}
body.theater #theater-controls-toggle {
  opacity: 0.86;
}
body.theater.controls-open #theater-controls-toggle {
  opacity: 1;
  background: var(--lk-info-soft);
  border-color: var(--lk-info-soft);
}
/* 字幕关着时拼音开关无处可切，置灰 */
body.theater .theater-controls .toggle:disabled {
  opacity: 0.45;
  cursor: not-allowed;
}
/* 竖屏手机：画面是横向画布，底部给字幕留更多空间，控制条也要收紧 */
@media (max-aspect-ratio: 1/1) {
  body.theater.caption-on .stage {
    padding-bottom: clamp(120px, 22vh, 200px);
  }
}
@media (max-width: 480px) {
  body.theater .theater-controls {
    gap: 6px;
    padding: 10px;
  }
  body.theater .theater-controls .toggle {
    padding: 6px 9px;
    font-size: var(--lk-f-xs);
  }
  body.theater .theater-controls-panel {
    max-width: 88vw;
  }
}
/* 横屏手机（高 375 左右）：收起态只剩图标，尽量不压到画面标题 */
@media (max-height: 520px) {
  body.theater .theater-controls {
    padding: 10px;
  }
  body.theater #theater-controls-toggle .lbl {
    display: none;
  }
}

/* ---------- 按钮（一级触控目标 ≥48px） ---------- */
.primary,
.secondary,
.toggle {
  border: 0;
  border-radius: var(--lk-r-sm);
  min-height: var(--lk-hit);
  padding: 10px 16px;
  font: inherit;
  font-weight: 700;
  cursor: pointer;
}
.primary {
  background: var(--lk-accent);
  color: var(--lk-surface);
  box-shadow: 0 4px 0 var(--lk-accent-deep);
}
.primary:disabled {
  opacity: 0.45;
  cursor: not-allowed;
}
.secondary {
  background: var(--lk-info-soft);
  color: var(--lk-info-deep);
}
.toggle {
  min-height: 40px;
  padding: 7px 10px;
  background: var(--lk-bg);
  color: var(--lk-info-deep);
  border: 1px solid var(--lk-border);
  font-size: var(--lk-f-xs);
}
:is(
  .primary,
  .secondary,
  .toggle,
  .activity,
  .answers button,
  .question-options button
):focus-visible {
  outline: 2px solid var(--lk-accent);
  outline-offset: 2px;
}

/* ---------- 字幕：连续文本 + 逐词高亮，字号固定 ----------
 * 字号与行高写死：内容多少都不缩字，注音开关也不跳行。正文 18px（儿童基线）。
 * 容器高度跟着卡片：内容少就长到内容高，内容多则封顶 400px 后自己滚（不撑高整页）。 */
.captions {
  flex: 1 1 auto;
  margin-top: var(--lk-s3);
  max-height: 400px;
  overflow-y: auto;
  padding: 2px 2px 6px;
  font-size: var(--lk-f-md);
  line-height: 2.6;
}
.cap-para {
  margin: 0 0 10px;
}
.cap-para:last-child {
  margin-bottom: 0;
}
/* 左侧留出当前句指示条的位置（inset 阴影，不引起回流） */
.sent {
  border-radius: var(--lk-r-xs);
  padding: 2px 3px 2px 6px;
  color: var(--lk-ink-muted);
  cursor: pointer;
  overflow-wrap: anywhere;
}
.sent:hover {
  background: var(--lk-bg);
}
/* 当前句双通道：橙色底 + 左侧橙条（不只靠颜色，色弱可辨位置） */
.sent.active {
  background: var(--lk-accent-soft);
  color: var(--lk-ink-strong);
  box-shadow: inset 3px 0 0 var(--lk-accent);
}
.sent:focus-visible {
  outline: 2px solid var(--lk-accent);
  outline-offset: 1px;
}
.grp {
  border-radius: var(--lk-r-xs);
  transition: background 0.12s;
}
.grp.hl {
  background: var(--lk-accent-hl);
  color: var(--lk-accent-hl-ink);
}
.grp.hl rt {
  color: var(--lk-accent-hl-ink);
}

ruby {
  ruby-position: over;
}
rt {
  font-size: 0.58em;
  font-weight: 600;
  color: var(--lk-ink-faint);
  letter-spacing: 0.02em;
}
.no-pinyin rt {
  display: none;
}

/* ---------- 活动入口 ---------- */
.activity-nav {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--lk-s3);
  margin: 20px 0;
}
.activity {
  display: flex;
  align-items: center;
  gap: var(--lk-s3);
  min-height: 64px;
  padding: 14px 16px;
  text-align: left;
  border: 1px solid var(--lk-border);
  background: var(--lk-surface);
  border-radius: var(--lk-r-md);
  cursor: pointer;
  color: var(--lk-ink-strong);
}
.activity svg {
  width: 30px;
  height: 30px;
  flex: none;
}
.activity .activity-text {
  flex: 1;
}
.activity b,
.activity small {
  display: block;
}
.activity small {
  color: var(--lk-ink-faint);
  font-size: var(--lk-f-xs);
  margin-top: 2px;
}
.activity.active {
  border-color: var(--lk-accent);
  box-shadow: 0 0 0 3px var(--lk-accent-soft);
  background: var(--lk-accent-soft);
}
.activity.active svg {
  color: var(--lk-accent-deep);
}

/* ---------- 活动面板 ---------- */
.panel {
  margin-top: 0;
}
.panel-title {
  padding-bottom: 16px;
  border-bottom: 1px solid var(--lk-border-soft);
}
.tag {
  padding: 6px 10px;
  border-radius: var(--lk-r-full);
  background: var(--lk-accent-soft);
  color: var(--lk-accent-deep);
  font-size: var(--lk-f-xs);
  white-space: nowrap;
}
.hidden {
  display: none !important;
}

/* 练习：提交后立即解析。对错状态 = 颜色 + ✓/✗ 图标双通道 */
.practice-visual {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 18px;
  padding: var(--lk-s5);
  font-size: 34px;
}
.practice-visual em {
  opacity: 0.2;
  font-style: normal;
}
.practice-visual strong {
  color: var(--lk-accent-deep);
  font-size: var(--lk-f-lg);
}
.answers {
  display: flex;
  justify-content: center;
  gap: var(--lk-s3);
}
.answers button {
  min-width: 74px;
  min-height: var(--lk-hit);
  padding: 10px;
  border: 1px solid var(--lk-border);
  border-radius: var(--lk-r-sm);
  background: var(--lk-surface);
  color: var(--lk-ink-strong);
  font-size: var(--lk-f-lg);
  cursor: pointer;
}
.answers button.chosen {
  border-color: var(--lk-accent);
}
.answers button.correct,
.question-options button.correct {
  background: var(--lk-ok-soft);
  border-color: var(--lk-ok-border);
  color: var(--lk-ok);
}
.answers button.wrong,
.question-options button.wrong {
  background: var(--lk-bad-soft);
  border-color: var(--lk-bad-border);
  color: var(--lk-bad);
}
.answers button.correct::before,
.question-options button.correct::before {
  content: '✓ ';
}
.answers button.wrong::before,
.question-options button.wrong::before {
  content: '✗ ';
}
.feedback {
  margin-top: 18px;
  padding: 13px 16px;
  border-radius: var(--lk-r-sm);
  font-size: var(--lk-f-sm);
}
.feedback.success {
  background: var(--lk-ok-soft);
  color: var(--lk-ok);
}
.feedback.retry {
  background: var(--lk-warn-soft);
  color: var(--lk-warn);
}
.feedback.success::before {
  content: '✓ ';
  font-weight: 800;
}
.feedback.retry::before {
  content: '↻ ';
  font-weight: 800;
}

/* 答案反馈动效：≤300ms，尊重系统减动效设置 */
@keyframes lk-pop {
  0% {
    transform: scale(1);
  }
  45% {
    transform: scale(1.08);
  }
  100% {
    transform: scale(1);
  }
}
@keyframes lk-shake {
  0%,
  100% {
    transform: translateX(0);
  }
  25% {
    transform: translateX(-4px);
  }
  60% {
    transform: translateX(4px);
  }
}
.answers button.correct,
.question-options button.correct {
  animation: lk-pop 0.3s ease-out;
}
.answers button.wrong,
.question-options button.wrong {
  animation: lk-shake 0.3s ease-out;
}
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation: none !important;
    transition: none !important;
  }
}

/* 通关测试：提交前不显示解析 */
.question {
  padding: 16px 0;
  border-bottom: 1px solid var(--lk-border-soft);
}
.question-title {
  display: flex;
  gap: 10px;
  align-items: center;
  font-size: var(--lk-f-md);
}
.question-title i {
  font-style: normal;
  width: 27px;
  height: 27px;
  display: grid;
  place-items: center;
  border-radius: 50%;
  background: var(--lk-accent-soft);
  color: var(--lk-accent-deep);
  font-size: 13px;
}
.question-options {
  display: flex;
  gap: 9px;
  margin: 11px 0 0 37px;
  flex-wrap: wrap;
}
.question-options button {
  min-width: 60px;
  min-height: var(--lk-hit);
  padding: 8px 18px;
  border: 1px solid var(--lk-border);
  border-radius: var(--lk-r-sm);
  background: var(--lk-surface);
  color: var(--lk-ink-strong);
  font-size: var(--lk-f-md);
  cursor: pointer;
}
.question-options button.selected {
  border-color: var(--lk-accent);
}
.explain {
  margin: 9px 0 0 37px;
  color: var(--lk-ink-muted);
  font-size: var(--lk-f-sm);
}
.gate-footer {
  display: flex;
  align-items: center;
  gap: 13px;
  margin-top: 18px;
  flex-wrap: wrap;
}
.gate-result {
  padding: 10px 14px;
  border-radius: var(--lk-r-sm);
  font-size: var(--lk-f-sm);
}
.gate-result.success {
  background: var(--lk-ok-soft);
  color: var(--lk-ok);
}
.gate-result.retry {
  background: var(--lk-warn-soft);
  color: var(--lk-warn);
}

/* 拓展阅读 */
.reading-hero {
  margin: 18px 0;
  padding: 23px;
  text-align: center;
  background: var(--lk-accent-soft);
  border-radius: var(--lk-r-md);
  font-size: 36px;
}
.reading-hero b {
  color: var(--lk-accent-deep);
  font-size: var(--lk-f-xl);
}
.panel > p {
  color: var(--lk-ink-muted);
  line-height: 2;
}
.panel figure {
  margin: 0 0 18px;
}
.panel figure img {
  max-width: 100%;
  border-radius: var(--lk-r-md);
}
.panel figcaption {
  margin-top: 6px;
  color: var(--lk-ink-faint);
  font-size: var(--lk-f-xs);
}

/* ---------- 数学排版（MathML 真分数） ----------
 * 题库与解析里的 `\frac{分子}{分母}` 由 player.js 的 renderMath 转成 <math><mfrac>，
 * 分子在上、分母在下、分数线由浏览器画；带分数写成 `1\frac{1}{2}`。
 * 字号：MathML 默认会把分子分母再缩一档（实测约 0.71 倍），缩完只有周围文字的六成，看着很小；
 * 这里把两次缩小都抵掉（mfrac 0.95em、mfrac 子项 1em），让分数与周围文字几乎同号。 */
math {
  font-family: inherit;
  font-size: 1em;
  vertical-align: -0.3em;
  line-height: 1;
}
math mfrac {
  font-size: 0.95em;
  padding: 0 0.14em;
}
math mfrac > * {
  font-size: 1em;
}
.question-options math,
.answers math {
  vertical-align: -0.32em;
}
.reading-hero math {
  font-size: 1.05em;
}
.reading-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: var(--lk-s3);
}
.reading-grid article {
  display: flex;
  flex-direction: column;
  gap: 5px;
  padding: 14px;
  border-radius: var(--lk-r-sm);
  background: var(--lk-bg);
}
.reading-grid b {
  color: var(--lk-accent-deep);
}
.reading-grid span {
  font-size: var(--lk-f-sm);
  color: var(--lk-ink-muted);
}

/* ---------- 舞台图元默认样式（共享运行时 stage-kit.js 的类） ----------
 * 这些是跨课复用的图元（角色牌、气泡、箭头、分与合、算式条、胶囊横幅、文字），
 * 所以默认值写在基座里；某课要换配色就在自己的 stage.css 里覆盖同名类（本课样式在后）。
 * 字号随画布等比缩放，所以写类而不是逐元素写 font-size。
 * 居中审计（2026-09-27，g1-059）：元素用 x=cx 起排的图元（equation 文字、bond 盒标签、
 * card 标签）必须在这里补 text-anchor: middle，否则文字从盒心向右溢出（被相邻元素盖住）；
 * 十格框/数轴标签已经走 KIT.text(anchor) 或已有锚点。新增图元时照这条自检。 */
#stage-svg {
  font-family: inherit;
}
.kit-text {
  font-size: 22px;
  fill: var(--lk-stage-ink);
}
.kit-rect {
  fill: var(--lk-surface);
  stroke: var(--lk-stage-line);
  stroke-width: 3;
}
.kit-card {
  fill: var(--lk-stage-card);
  stroke: var(--lk-stage-line);
  stroke-width: 3;
}
.kit-card-label {
  font-size: 30px;
  font-weight: 700;
  fill: var(--lk-stage-ink);
  text-anchor: middle;
}
.kit-image {
  border-radius: var(--lk-r-sm);
}

/* 胶囊横幅 */
.pill-box {
  fill: var(--lk-info-soft);
  stroke: var(--lk-stage-edge);
  stroke-width: 2;
}
.pill-text {
  font-size: 22px;
  font-weight: 700;
  fill: var(--lk-info-deep);
}

/* 角色牌：圆形头像 + 名字 + 对话气泡（形象来自共享立绘库）
 * 盘底色必须等于立绘自带的背景色（实测 #b7c8de），否则换情绪时会在两种盘底之间跳色：
 * 立绘带不透明底时铺满圆盘看不到盘底，立绘是透明背景时露出的就是这一层。 */
.actor-ring {
  fill: var(--lk-actor-ring);
  stroke: var(--lk-stage-line);
  stroke-width: 3;
}
.actor-image {
}
.actor-name {
  font-size: 20px;
  font-weight: 700;
  fill: var(--lk-stage-ink);
}
.bubble-box {
  fill: var(--lk-surface);
  stroke: var(--lk-part-a);
  stroke-width: 3;
}
.bubble-tail {
  fill: var(--lk-surface);
  stroke: var(--lk-part-a);
  stroke-width: 3;
}
.bubble-text {
  font-size: 20px;
  font-weight: 700;
  fill: var(--lk-part-a-edge);
}

/* 箭头连线（数量、配对、移动方向） */
.arrow-line {
  stroke: var(--lk-stage-arrow);
  stroke-width: 3;
  stroke-linecap: round;
}
.arrow-head {
  fill: var(--lk-stage-arrow);
}

/* 分与合：整体在上，两半在下；bond-change = 这一半是当前要说的一口（change 角色） */
.bond-line {
  stroke: var(--lk-stage-arrow);
  stroke-width: 3;
  stroke-linecap: round;
}
.bond-line.dim {
  stroke: var(--lk-stage-line-dim);
}
.bond-box {
  fill: var(--lk-stage-card);
  stroke: var(--lk-stage-line);
  stroke-width: 3;
}
.bond-box.bond-change {
  fill: var(--lk-ok-soft);
  stroke: var(--lk-ok-edge);
  stroke-width: 4;
}
.bond-box.bond-dim {
  fill: var(--lk-stage-dim);
  stroke: var(--lk-stage-line-dim);
}
.bond-label {
  font-size: 30px;
  font-weight: 700;
  fill: var(--lk-stage-ink);
  text-anchor: middle;
}

/* 算式条：一道算式一块，tone 写角色词 change（算对/结论）/ error（算错） */
.equation-box {
  fill: var(--lk-surface);
  stroke: var(--lk-stage-line);
  stroke-width: 2.5;
}
.equation-change {
  fill: var(--lk-ok-soft);
  stroke: var(--lk-ok-edge);
}
.equation-error {
  fill: var(--lk-bad-soft);
  stroke: var(--lk-bad-ink);
}
/* 算式条：文字从 cx 起排会右溢出盒子（盒子以 cx 居中），必须居中 */
.equation-text {
  font-size: 24px;
  font-weight: 700;
  fill: var(--lk-stage-ink);
  text-anchor: middle;
}
.equation-label {
  font-size: 16px;
  fill: var(--lk-ink-muted);
}

/* 十格框 / 数轴 / 对错标记：只给默认配色，尺寸与数量由 stage.js 的数据算 */
/* 空格是“待填位”，凑十语义的一半：描边要比普通盒线深一档，但仍弱于实点的彩描边 */
.tenframe-cell {
  fill: var(--lk-surface);
  stroke: var(--lk-stage-tick);
  stroke-width: 2;
}
.tenframe-dot {
  fill: var(--lk-part-a);
  stroke: var(--lk-part-a-edge);
  stroke-width: 2;
}
.tenframe-dot.tenframe-change {
  fill: var(--lk-hot);
  stroke: var(--lk-hot-edge);
}
.tenframe-label {
  font-size: 17px;
  font-weight: 700;
  fill: var(--lk-stage-ink);
}
.tenframe-sub {
  font-size: 16px;
  fill: var(--lk-ink-muted);
}

.line-axis {
  stroke: var(--lk-stage-arrow);
  stroke-width: 3;
  stroke-linecap: round;
}
.line-tick {
  stroke: var(--lk-stage-arrow);
  stroke-width: 2;
}
.line-tick.line-tick-small {
  stroke: var(--lk-stage-tick);
  stroke-width: 1.5;
}
.line-tick-label {
  font-size: 15px;
  fill: var(--lk-ink-muted);
  text-anchor: middle;
}
/* 数轴标记与跳步：类名 = 角色名（缺省 change = 当前正在做的这一步，whole = 跳的是已有的量） */
.line-mark {
  fill: var(--lk-surface);
  stroke: var(--lk-stage-arrow);
  stroke-width: 2;
}
.line-mark-change {
  fill: var(--lk-ok-soft);
  stroke: var(--lk-hot-edge);
}
.line-mark-whole {
  fill: var(--lk-accent-soft);
  stroke: var(--lk-part-a-edge);
}
.line-note {
  font-size: 15px;
  font-weight: 700;
  fill: var(--lk-stage-ink);
}
.line-note-change {
  fill: var(--lk-hot-edge);
}
.line-note-whole {
  fill: var(--lk-part-a-edge);
}
.line-jump {
  fill: none;
  stroke-width: 3;
  stroke-linecap: round;
}
.line-jump-change {
  stroke: var(--lk-hot-edge);
}
.line-jump-whole {
  stroke: var(--lk-part-a-edge);
}
.line-jump-head-change {
  fill: var(--lk-hot-edge);
}
.line-jump-head-whole {
  fill: var(--lk-part-a-edge);
}
.line-jump-label {
  font-size: 17px;
  font-weight: 700;
}
.line-jump-label-change {
  fill: var(--lk-hot-edge);
}
.line-jump-label-whole {
  fill: var(--lk-part-a-edge);
}

/* 对错角标：right = 对（change 绿）、wrong = 错（error 红） */

.mark-ring {
  fill: var(--lk-surface);
  stroke-width: 2.5;
}
.mark-ring.mark-wrong {
  stroke: var(--lk-bad-ink);
}
.mark-ring.mark-right {
  stroke: var(--lk-hot-edge);
}
.mark-stroke {
  fill: none;
  stroke-width: 3;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.mark-stroke.mark-wrong {
  stroke: var(--lk-bad-ink);
}
.mark-stroke.mark-right {
  stroke: var(--lk-hot-edge);
}

/* ---------- 教具库（声明式场景） ----------
 * 字号与 stage-kit.js 的 FONT 一一对应：排版器靠它估宽，改一边必须改另一边。
 * 颜色语义全课统一，**唯一定义在 scripts/color_roles.py**：类名 = 角色名。
 * whole = 橙（整体/原有/第一部分）、part = 蓝（第二部分）、change = 绿（变化量/补进/结论/正确）、
 * unknown = 压淡虚线（未知/待求/已拿走）、error = 红（错误）。 */
.part-label {
  font-size: 17px;
  font-weight: 700;
  fill: var(--lk-stage-ink);
}
.part-sub {
  font-size: 16px;
  fill: var(--lk-ink-muted);
}
.scene-text {
  font-size: 20px;
  font-weight: 700;
  fill: var(--lk-stage-ink);
}
.scene-text-change {
  fill: var(--lk-ok);
}
.scene-text-error {
  fill: var(--lk-bad-text);
}

.obj {
  fill: var(--lk-part-a);
  stroke: var(--lk-part-a-edge);
  stroke-width: 1.5;
}
.obj.obj-part {
  fill: var(--lk-part-b);
  stroke: var(--lk-part-b-edge);
}
.obj.obj-change {
  fill: var(--lk-hot);
  stroke: var(--lk-hot-edge);
}
.obj.obj-away {
  opacity: 0.35;
  stroke-dasharray: 3 2;
}
.obj-group {
  fill: var(--lk-part-a-soft);
  stroke: var(--lk-part-a-edge-soft);
  stroke-width: 2.5;
}
.obj-group.obj-away {
  opacity: 0.45;
  stroke-dasharray: 6 4;
}
.obj-cross {
  stroke: var(--lk-bad-text);
  stroke-width: 2.5;
  stroke-linecap: round;
  fill: none;
}

.pv-block {
  fill: var(--lk-pv-block);
  stroke: var(--lk-pv-block-edge);
  stroke-width: 1.5;
}
.pv-tens .pv-block {
  fill: var(--lk-hot-soft);
  stroke: var(--lk-hot-edge);
}
.pv-hundreds .pv-block {
  fill: var(--lk-pv-hundred);
  stroke: var(--lk-pv-hundred-edge);
}
.pv-grid {
  stroke: var(--lk-pv-grid);
  stroke-width: 1;
}
.pv-away {
  opacity: 0.35;
}
.pv-caption {
  font-size: 16px;
  font-weight: 700;
  fill: var(--lk-info-deep);
}

.bar-seg {
  stroke: var(--lk-stage-arrow);
  stroke-width: 2;
}
.bar-seg-whole {
  fill: var(--lk-bar-a);
}
.bar-seg-part {
  fill: var(--lk-bar-b);
}
.bar-seg-change {
  fill: var(--lk-hot-soft);
}
.bar-seg-unknown {
  fill: var(--lk-surface);
  stroke-dasharray: 6 4;
}
.bar-text {
  font-size: 18px;
  font-weight: 700;
  fill: var(--lk-stage-ink);
}
.bar-text-sm {
  font-size: 14px;
}
.bar-name {
  font-size: 17px;
  font-weight: 700;
  fill: var(--lk-stage-ink);
}
.bar-total {
  font-size: 17px;
  font-weight: 700;
  fill: var(--lk-info-deep);
  text-anchor: middle;
}
.bar-brace {
  fill: none;
  stroke: var(--lk-bar-brace);
  stroke-width: 2;
}

.chip-box {
  fill: var(--lk-surface);
  stroke: var(--lk-chip-edge);
  stroke-width: 2.5;
}
.chip-box.chip-change {
  fill: var(--lk-ok-soft);
  stroke: var(--lk-ok-edge);
  stroke-width: 3;
}
.chip-label {
  font-size: 12px;
  fill: var(--lk-ink-faint);
}
.chip-label.chip-change {
  fill: var(--lk-chip-hot-ink);
}
.chip-value {
  font-size: 22px;
  font-weight: 700;
  fill: var(--lk-stage-ink);
}
.chip-value.chip-change {
  fill: var(--lk-ok);
}

.step-card {
  fill: var(--lk-step-bg);
  stroke: var(--lk-step-edge);
  stroke-width: 3;
}
.step-title {
  font-size: 17px;
  font-weight: 700;
  fill: var(--lk-step-ink);
}
.step-text {
  font-size: 22px;
  font-weight: 700;
  fill: var(--lk-stage-ink);
}
.step-arrow .arrow-line {
  stroke: var(--lk-step-arrow);
  stroke-width: 4;
}
.step-arrow .arrow-head {
  fill: var(--lk-step-arrow);
}

.kit-card.card-change {
  fill: var(--lk-ok-soft);
  stroke: var(--lk-ok-edge);
  stroke-width: 4;
}

/* cardRow 卡片排：白卡 + 分数（分子/分母）/ 数字 / 空白；配对成功绿描边、错卡红描边；
 * 卡间运算符与判定徽标用信息蓝（非行动引导）。 */
.crd-card {
  fill: var(--lk-stage-card);
  stroke: var(--lk-stage-line);
  stroke-width: 3;
}
.crd-card.crd-card-good {
  stroke: var(--lk-ok-edge);
  stroke-width: 4;
}
.crd-card.crd-card-error {
  fill: var(--lk-bad-soft);
  stroke: var(--lk-bad-ink);
  stroke-width: 4;
}
.crd-card.crd-card-blank {
  fill: var(--lk-info-soft);
  stroke: var(--lk-stage-edge);
  stroke-dasharray: 9 7;
}
.crd-num {
  font-size: 40px;
  font-weight: 700;
  fill: var(--lk-stage-ink);
  paint-order: stroke;
  stroke: var(--lk-surface);
  stroke-width: 4;
}
.crd-num-small {
  font-size: 26px;
}
.crd-value {
  font-size: 34px;
  font-weight: 700;
  fill: var(--lk-stage-ink);
}
.crd-blank-mark {
  font-size: 44px;
  font-weight: 700;
  fill: var(--lk-stage-tick);
}
.crd-bar {
  stroke: var(--lk-stage-arrow);
  stroke-width: 3;
  stroke-linecap: round;
}
.crd-tag {
  font-size: 17px;
  fill: var(--lk-ink-muted);
  paint-order: stroke;
  stroke: var(--lk-surface);
  stroke-width: 4;
}
.crd-op {
  font-size: 34px;
  font-weight: 700;
  fill: var(--lk-info-deep);
}
.crd-op-note {
  font-size: 15px;
  fill: var(--lk-ink-faint);
}
.crd-eq {
  font-size: 32px;
  font-weight: 700;
  fill: var(--lk-info-deep);
}
.crd-verdict {
  fill: var(--lk-ok-soft);
  stroke: var(--lk-ok-edge);
  stroke-width: 3;
}
.crd-verdict.crd-verdict-error {
  fill: var(--lk-bad-soft);
  stroke: var(--lk-bad-ink);
}
.crd-verdict-text {
  font-size: 19px;
  font-weight: 700;
  fill: var(--lk-ok);
}
.crd-verdict-error + .crd-verdict-text {
  fill: var(--lk-bad);
}

/* transfer 搬运：左区还没搬（whole 橙）、右区已搬（change 绿，复用 .obj-change），中间留飞行弧的空当 */
.transfer-zone {
  fill: var(--lk-part-a-soft);
  stroke: var(--lk-part-a-edge-soft);
  stroke-width: 2.5;
}
.transfer-zone-change {
  fill: var(--lk-ok-soft);
  stroke: var(--lk-ok-edge);
  stroke-width: 2.5;
}
.transfer-label {
  font-size: 17px;
  font-weight: 700;
  fill: var(--lk-info-deep);
}

/* fractionBar 分数条：白底盒 + 涂色段（缺省 whole，角色类覆盖）+ 等分线 + 描边（描边后画，盖住涂色段圆角） */
.frac-box {
  fill: var(--lk-surface);
  stroke: none;
}
.frac-fill {
  fill: var(--lk-part-a);
}
.frac-fill.frac-change {
  fill: var(--lk-hot);
}
.frac-fill.frac-part {
  fill: var(--lk-part-b);
}
.frac-line {
  stroke: var(--lk-pv-grid);
  stroke-width: 1.5;
}
.frac-edge {
  fill: none;
  stroke: var(--lk-stage-line);
  stroke-width: 3;
}
.frac-label {
  font-size: 16px;
  font-weight: 700;
  fill: var(--lk-stage-ink);
}

/* areaGrid 面积格：白底 + 涂色格 + 淡网格线 + 外框（后画，盖住格子边缘） */
.grid-box {
  fill: var(--lk-surface);
  stroke: none;
}
.grid-cell {
  fill: var(--lk-part-a);
  stroke: var(--lk-part-a-edge);
  stroke-width: 1;
}
.grid-cell.grid-part {
  fill: var(--lk-part-b);
  stroke: var(--lk-part-b-edge);
}
.grid-line {
  stroke: var(--lk-pv-grid);
  stroke-width: 1;
}
.grid-edge {
  fill: none;
  stroke: var(--lk-stage-line);
  stroke-width: 3;
}
.axis-label {
  font-size: 16px;
  font-weight: 700;
  fill: var(--lk-info-deep);
}

/* polygon 平面图形：固定样子，边长写在标签里，不按数值缩放 */
.poly-shape {
  fill: var(--lk-part-a);
  fill-opacity: 0.18;
  stroke: var(--lk-stage-line);
  stroke-width: 3;
  stroke-linejoin: round;
}
.poly-label {
  font-size: 16px;
  font-weight: 700;
  fill: var(--lk-stage-ink);
}

/* angleMark 角：右边一条水平边，另一条按度数张开；90° 用直角标记 */
.angle-ray {
  stroke: var(--lk-stage-line);
  stroke-width: 3;
  stroke-linecap: round;
}
.angle-arc,
.angle-square {
  fill: none;
  stroke: var(--lk-hot);
  stroke-width: 2.5;
}
.angle-vertex {
  fill: var(--lk-stage-ink);
}
.angle-label {
  font-size: 16px;
  font-weight: 700;
  fill: var(--lk-stage-ink);
}

/* solid 立体：斜二测，只画看得见的面和棱，尺寸写在标签里 */
.solid-face {
  fill: var(--lk-part-a);
  fill-opacity: 0.18;
  stroke: none;
}
.solid-edge {
  fill: none;
  stroke: var(--lk-stage-line);
  stroke-width: 2.5;
}
.solid-label {
  font-size: 16px;
  font-weight: 700;
  fill: var(--lk-stage-ink);
}

/* net 展开图：实面是有的面，虚框是缺的面 */
.net-face {
  fill: var(--lk-part-a);
  fill-opacity: 0.18;
  stroke: var(--lk-stage-line);
  stroke-width: 2.5;
}
.net-blank {
  fill: none;
  stroke: var(--lk-stage-line);
  stroke-width: 2;
  stroke-dasharray: 5 4;
}
.net-label {
  font-size: 15px;
  font-weight: 700;
  fill: var(--lk-stage-ink);
}

/* orthographic 三视图：一格一块，只画一个方向 */
.view-cell {
  fill: var(--lk-part-a);
  fill-opacity: 0.18;
  stroke: var(--lk-stage-line);
  stroke-width: 2.5;
}
.view-label {
  font-size: 15px;
  font-weight: 700;
  fill: var(--lk-stage-ink);
}

/* gridPose 俯视层数：有块的格写层数，0 是空位 */
.pose-cell {
  fill: var(--lk-part-a);
  fill-opacity: 0.18;
  stroke: var(--lk-stage-line);
  stroke-width: 2.5;
}
.pose-empty {
  fill: none;
  stroke: var(--lk-stage-line);
  stroke-width: 2;
  stroke-dasharray: 5 4;
}
.pose-count {
  font-size: 16px;
  font-weight: 700;
  fill: var(--lk-stage-ink);
}

/* compass 八方位：环和刻度是方向标，线段是走出的路 */
.compass-ring {
  fill: none;
  stroke: var(--lk-stage-line);
  stroke-width: 2;
}
.compass-tick {
  stroke: var(--lk-stage-arrow);
  stroke-width: 2.5;
}
.compass-name {
  font-size: 15px;
  font-weight: 700;
  fill: var(--lk-stage-ink);
}
.compass-leg {
  stroke: var(--lk-part-a-edge);
  stroke-width: 3;
  stroke-linecap: round;
}
.compass-leg-label {
  font-size: 14px;
  font-weight: 700;
  fill: var(--lk-stage-ink);
}
.compass-center {
  fill: var(--lk-stage-ink);
}

/* lineChart / pie：和条形图同一套角色色 */
.chart-line {
  fill: none;
  stroke-width: 3;
  stroke-linejoin: round;
  stroke-linecap: round;
}
.chart-line-whole {
  stroke: var(--lk-part-a-edge);
}
.chart-line-part {
  stroke: var(--lk-part-b-edge);
  stroke-dasharray: 7 4;
}
.chart-dot-whole {
  fill: var(--lk-part-a-edge);
}
.chart-dot-part {
  fill: var(--lk-part-b-edge);
}
.pie-slice-0 {
  fill: var(--lk-part-a);
  fill-opacity: 0.55;
  stroke: var(--lk-surface);
  stroke-width: 2;
}
.pie-slice-1 {
  fill: var(--lk-part-b);
  fill-opacity: 0.55;
  stroke: var(--lk-surface);
  stroke-width: 2;
}
.pie-slice-2 {
  fill: var(--lk-hot);
  fill-opacity: 0.45;
  stroke: var(--lk-surface);
  stroke-width: 2;
}
.pie-empty {
  fill: none;
  stroke: var(--lk-stage-line);
  stroke-width: 2;
}
.pie-name {
  font-size: 13px;
  font-weight: 700;
  fill: var(--lk-stage-ink);
}
.pie-value {
  font-size: 13px;
  fill: var(--lk-stage-ink);
}

/* barChart 条形统计图：柱子用教具语义色，数值在柱顶、类名在轴下 */
.chart-bar {
  fill: var(--lk-part-a);
  stroke: var(--lk-part-a-edge);
  stroke-width: 2;
}
.chart-bar.chart-change {
  fill: var(--lk-hot);
  stroke: var(--lk-hot-edge);
}
.chart-bar.chart-part {
  fill: var(--lk-part-b);
  stroke: var(--lk-part-b-edge);
}
.chart-value {
  font-size: 17px;
  font-weight: 700;
  fill: var(--lk-stage-ink);
}
.chart-name {
  font-size: 16px;
  font-weight: 700;
  fill: var(--lk-stage-ink);
}
.chart-axis {
  stroke: var(--lk-stage-arrow);
  stroke-width: 3;
  stroke-linecap: round;
}
.chart-unit {
  font-size: 14px;
  fill: var(--lk-ink-muted);
}

/* clockFace 钟面：白盘、刻度两档、数字一圈；时针短粗橙、分针细长蓝（语义同教具库） */
.clock-face {
  fill: var(--lk-surface);
  stroke: var(--lk-stage-line);
  stroke-width: 3;
}
.clock-tick {
  stroke: var(--lk-stage-tick);
  stroke-width: 1.5;
}
.clock-tick-major {
  stroke: var(--lk-stage-arrow);
  stroke-width: 2.5;
}
.clock-num {
  font-size: 14px;
  font-weight: 700;
  fill: var(--lk-stage-ink);
}
.clock-hour {
  stroke: var(--lk-part-a-edge);
  stroke-width: 7;
  stroke-linecap: round;
}
.clock-minute {
  stroke: var(--lk-part-b-edge);
  stroke-width: 4.5;
  stroke-linecap: round;
}
.clock-center {
  fill: var(--lk-stage-ink);
}

/* ---------- 地点背景（演员表地点库 7 个 Token；由 index.html 的 data-location 选择） ----------
 * 写成任意高度都成立的渐变：剧场模式会铺满视口。逐课 stage.css 可以覆盖。
 * 品牌徽章（.brand-mark）同步用同款渐变，缩略画面与舞台同属一个地点。 */
.stage[data-location='huaguo-smart-orchard'],
.brand-mark[data-location='huaguo-smart-orchard'] {
  background-image: var(--lk-loc-huaguo-smart-orchard);
}
.stage[data-location='gaolao-bakery-hub'],
.brand-mark[data-location='gaolao-bakery-hub'] {
  background-image: var(--lk-loc-gaolao-bakery-hub);
}
.stage[data-location='drift-sand-lab'],
.brand-mark[data-location='drift-sand-lab'] {
  background-image: var(--lk-loc-drift-sand-lab);
}
.stage[data-location='bailong-express-transit'],
.brand-mark[data-location='bailong-express-transit'] {
  background-image: var(--lk-loc-bailong-express-transit);
}
.stage[data-location='dayan-math-archive'],
.brand-mark[data-location='dayan-math-archive'] {
  background-image: var(--lk-loc-dayan-math-archive);
}
.stage[data-location='flame-mountain-energy'],
.brand-mark[data-location='flame-mountain-energy'] {
  background-image: var(--lk-loc-flame-mountain-energy);
}
.stage[data-location='water-curtain-maker-lab'],
.brand-mark[data-location='water-curtain-maker-lab'] {
  background-image: var(--lk-loc-water-curtain-maker-lab);
}

/* ---------- 窄屏 ---------- */
@media (max-width: 760px) {
  .lesson-grid {
    grid-template-columns: 1fr;
  }
  .activity-nav {
    grid-template-columns: 1fr;
  }
  .stage {
    min-height: 300px;
  }
  .lesson-header {
    flex-wrap: wrap;
  }
  .offline-pill {
    margin-left: auto;
  }
  .lesson-header > div:nth-child(2) {
    order: 3;
    flex-basis: 100%;
  }
  .reading-grid {
    grid-template-columns: 1fr;
  }
  .captions {
    max-height: 280px;
  }
}
