/* 练习页版面（Steven 的设计稿：docs/backup/assets/ui-references/design-phone.png、design-desktop.png）。
   颜色、字号、间距、圆角来自 css/tokens.css；按钮组件在 css/base.css。

   骨架：所有级别、所有状态都是同一个结构——页面底色 + 顶栏 + 一张白色底板。底板里从上到下固定五行：
     ① 图片区（正方形）  ② 文字区（固定高度：两行英文 + 一行中文）  ③ 图标行（3 个 52px 圆）
     ④ 反馈行（固定 44px，一行）  ⑤ 按钮行（← → 等宽，高 52）
   任何按钮都不出现、不消失、不移动，只在「可用」和「灰色」之间切换；元素全在文档流里（flex），不用绝对定位。

   尺寸由 CSS 实时算（不用 JS 量尺寸）：先算图片区边长 --media，底板宽 --board-w 由它推出。
   手机（默认）：五行上下摞；电脑与横屏（宽 ≥ 768 且宽 > 高）：左右两栏，左栏图片区，右栏其余四行垂直居中。
   一屏放下、不滚动；教学用图一律不裁切（contain）。 */

:root {
  --page-x: var(--pad-x);          /* 底板到屏幕左右边的距离（≤ 360 宽收到 8px，见 tokens.css） */
  --page-y: 16px;                  /* 顶栏与底板、底板与屏幕下沿的距离 */
  --top-h: 56px;                   /* 顶栏高度 */
  --board-pad: 16px;               /* 底板内边距 */
  --row-gap: clamp(10px, 2dvh, 18px); /* 五行之间的间距：窗口越矮越紧（844 高时约 17px，568 高时约 11px） */
  --tile-gap: 12px;                /* 2×2 选项之间的间距 */

  --icon: 52px;                    /* 图标行：圆形按钮直径 */
  --icon-gap: 20px;                /* 图标之间的间距 */
  --fb-h: 44px;                    /* 反馈行高度 */
  --act-h: 52px;                   /* 按钮行高度 */
  --act-gap: 12px;                 /* ← → 之间的间距 */
  /* 文字区高度 = 两行英文（行高 1.35）+ 4px + 一行中文（行高 1.4）；始终固定，英文只有一行时中文紧跟其后，剩余留在下面 */
  --text-h: calc(2 * 1.35 * var(--fs-sentence) + 4px + 1.4 * var(--fs-gloss));

  /* 手机：图片区边长 = 底板内宽、剩余高度能给的、源图清晰度上限（512），三者取最小。
     高度：视口高 − 顶栏 − 上下留白 − 底板上下内边距 − 文字区 − 图标行 − 反馈行 − 按钮行 − 4 处行间距。
     上限 512：源图 1024×1024，2 倍屏每个 CSS 像素要 2 个源像素，再大就是放大后模糊（docs/05_ai_config/media-assets.md）。
     底板宽 ≤ 544（= 512 + 2 × 16），平板竖屏上不会拉得太宽。 */
  --board-w: min(100vw - 2 * var(--page-x), 544px);
  --media: max(64px, min(var(--board-w) - 2 * var(--board-pad),
    100dvh - var(--top-h) - 2 * var(--page-y) - 2 * var(--board-pad) - var(--text-h) - var(--icon) - var(--fb-h) - var(--act-h) - 4 * var(--row-gap), 512px));
}

/* 电脑与横屏：宽大于高、且宽度 ≥ 768。左右两栏，顺序不变。
   1280×600 时：图片区 464（= 600 − 56 − 2×16 − 2×24），底板 944×512（= 464 + 400 + 32 + 2×24）。 */
@media (min-width: 768px) and (orientation: landscape) {
  :root {
    --board-pad: 24px;
    --row-gap: 20px;
    --tile-gap: 16px;
    --col-gap: 32px;               /* 左栏与右栏之间 */
    --side-max: 400px;             /* 右栏最宽 */
    --side-min: 320px;             /* 右栏最窄（装得下一行反馈与两个按钮） */
    --media: max(64px, min(100dvh - var(--top-h) - 2 * var(--page-y) - 2 * var(--board-pad),
      100vw - 2 * var(--page-x) - 2 * var(--board-pad) - var(--col-gap) - var(--side-min), 512px));
    --side-w: min(var(--side-max), 100vw - 2 * var(--page-x) - 2 * var(--board-pad) - var(--col-gap) - var(--media));
    --board-w: calc(var(--media) + var(--side-w) + var(--col-gap) + 2 * var(--board-pad));
  }
}

body { overflow: hidden; }
.app { height: 100dvh; display: flex; flex-direction: column; }

/* 顶栏与底板同宽、同一条中轴 */
.top { flex: none; }
.top-in { display: flex; align-items: center; gap: var(--sp-3); width: var(--board-w); height: var(--top-h); margin-inline: auto; }
.scene { flex: none; font-size: var(--fs-small); color: var(--c-text-2); }

/* 内容区：占满剩余高度，底板在里面垂直、水平居中 */
.content { flex: 1; min-height: 0; display: grid; place-items: center; padding: var(--page-y) var(--page-x); }

/* 底板：白色、圆角 20、极淡阴影。手机上五行摞起来 */
.board { width: var(--board-w); padding: var(--board-pad); border-radius: var(--r-card); background: var(--c-card); box-shadow: var(--shadow-0);
  display: flex; flex-direction: column; gap: var(--row-gap); }
.media { align-self: center; flex: none; width: var(--media); height: var(--media); }
.side { display: flex; flex-direction: column; gap: var(--row-gap); min-width: 0; }

/* ① 图片区：第 1 级一张大图，第 2、3 级 2×2；两者占同样大小 */
.hero { display: block; width: 100%; height: 100%; object-fit: contain; border-radius: var(--r-img); }
.options { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); grid-template-rows: repeat(2, minmax(0, 1fr)); gap: var(--tile-gap); width: 100%; height: 100%; }
.opt { position: relative; min-width: 0; min-height: 0; padding: 4px; border: 2px solid var(--c-line); border-radius: var(--r-img); background: var(--c-card); cursor: pointer; transition: border-color .15s; }
.opt:hover:not(:disabled) { border-color: var(--c-line-strong); }
.opt img { display: block; width: 100%; height: 100%; object-fit: contain; border-radius: 8px; transition: opacity .2s; }
.opt:disabled { cursor: default; }
/* 对错：3px 彩色边（2px 边框 + 1px 内描边，尺寸不跳）；选错的图变淡、不可再点；右上角小圆标 */
.opt.right { border-color: var(--c-ok); box-shadow: inset 0 0 0 1px var(--c-ok); }
.opt.wrong { border-color: var(--c-bad); box-shadow: inset 0 0 0 1px var(--c-bad); animation: shake .3s; }
.opt.wrong img { opacity: .45; }
.badge { position: absolute; top: 6px; right: 6px; display: grid; place-items: center; width: 22px; height: 22px; border-radius: var(--r-pill); background: var(--c-card); }
.badge .ico { width: 14px; height: 14px; }
.opt.right .badge { color: var(--c-ok); border: 2px solid var(--c-ok); }
.opt.wrong .badge { color: var(--c-bad); border: 2px solid var(--c-bad); }
@keyframes shake { 0%, 100% { transform: translateX(0); } 25% { transform: translateX(-6px); } 75% { transform: translateX(6px); } }

/* ② 文字区：固定高度，从顶部排起；英文居中、常规粗细、#4D4D4D，变化词块加粗 + 浅蓝底（base.css 的 mark.chunk）；中文紧贴英文下方居中 */
.text { height: var(--text-h); text-align: center; overflow: hidden; }
.sentence { margin: 0; font-size: var(--fs-sentence); font-weight: var(--fw-regular); color: var(--c-text-2); line-height: 1.35; overflow-wrap: anywhere; }
.gloss-line { margin: 4px 0 0; font-size: var(--fs-gloss); line-height: 1.4; color: var(--c-text-2); visibility: hidden; } /* 始终占位，只切换可见性 */
.gloss-line.on { visibility: visible; }

/* ③ 图标行：3 个 52px 圆，间距 20，整组居中 */
.icons { display: flex; justify-content: center; gap: var(--icon-gap); height: var(--icon); }

/* ④ 反馈行：固定 44px，只能一行，居中；状态图标与标签不被挤压、不折行，反馈句放不下时由 test-ui/feedback-fit.spec.js 报警 */
.feedback { display: flex; align-items: center; justify-content: center; gap: var(--sp-2); height: var(--fb-h); margin: 0; font-size: var(--fs-small); white-space: nowrap; overflow: hidden; }
.fb-label { flex: none; font-weight: var(--fw-bold); }
.fb-text { min-width: 0; color: var(--c-text-2); }
.fb-ico { flex: none; display: inline-flex; }
.feedback.ok .fb-ico, .feedback.ok .fb-label { color: var(--c-ok-text); }
.feedback.bad .fb-ico, .feedback.bad .fb-label { color: var(--c-bad); }
.fb-ico .ico { width: 16px; height: 16px; }

/* ⑤ 按钮行：← 和 → 等宽，各占一半，间距 12，高 52，胶囊形（样式在 base.css 的 .nav-btn） */
.actions { display: flex; gap: var(--act-gap); height: var(--act-h); }

/* 完成页：同一张底板，图片区放大 ✓，文字区写小结，按钮行是 ↻ 与 → */
.done-mark { display: grid; place-items: center; width: 100%; height: 100%; border-radius: var(--r-img); background: var(--c-ok-tint); color: var(--c-ok); }
.done-mark .ico { width: 40%; height: 40%; }
.done-title { margin: 0; font-size: var(--fs-title); font-weight: var(--fw-bold); line-height: 1.2; }
.done-summary { margin: 4px 0 0; font-size: var(--fs-gloss); color: var(--c-text-2); }
.error-text { margin: 0; color: var(--c-text); }

/* 电脑与横屏：左栏图片区（正方形），右栏四行垂直居中 */
@media (min-width: 768px) and (orientation: landscape) {
  .board { flex-direction: row; align-items: center; gap: var(--col-gap); }
  .media { align-self: center; }
  .side { flex: none; width: var(--side-w); }
}

/* ===== 第 9 级「你想到了吗」（设计稿 docs/backup/assets/ui-references/level9-design.html）=====
   图片区（正方形）里竖着放：缩略图、中文场景句、输入框（含麦克风）。缩略图是可压缩的那一块：
   图片区高度不到 280px（如 320×568 的手机、横过来的手机）时，缩略图整个不显示（容器查询；不认识容器查询的旧浏览器里它会被压成一小点，不影响其余部分）：
   场景句最多 4 行（约 87px）+ 输入框至少 96px + 缩略图 64px + 间距，需要约 270px。 */
.board.write .media { container-type: size; }
@container (max-height: 280px) { .l9-thumb { display: none; } }
.l9 { display: flex; flex-direction: column; align-items: center; gap: var(--sp-3); width: 100%; height: 100%; min-height: 0; }
.l9-thumb { flex: 0 1 calc(var(--media) * .34); min-height: 0; aspect-ratio: 1; max-width: 100%; padding: 4px; border: 2px solid var(--c-line); border-radius: var(--r-card); background: var(--c-card); }
.l9-thumb img { display: block; width: 100%; height: 100%; object-fit: contain; border-radius: 8px; }
.l9-scene { flex: none; width: 100%; margin: 0; font-size: var(--fs-gloss); line-height: 1.45; color: var(--c-text-2); text-align: center; overflow-wrap: anywhere; }

/* 输入框：作答时白底、聚焦时主色边；出结果后变成浅灰底（done），里面显示学习者的回答（带改正标记） */
.l9-box { flex: 1 0 96px; width: 100%; min-height: 0; padding: var(--sp-3) var(--sp-3) var(--sp-2); border: 2px solid var(--c-line); border-radius: 14px; background: var(--c-card);
  display: flex; flex-direction: column; align-items: center; justify-content: space-between; gap: var(--sp-2); }
.l9-box:focus-within { border-color: var(--c-primary); }
.l9-box.done { background: var(--c-bg); border-color: var(--c-bg); }
.l9-input, .l9-ans { flex: 1; width: 100%; min-height: 0; margin: 0; padding: 0; border: 0; background: transparent; color: var(--c-text); font: inherit;
  font-size: var(--fs-sentence); line-height: 1.45; text-align: center; overflow-y: auto; overflow-wrap: anywhere; }
.l9-input { resize: none; outline: none; }
.l9-input::placeholder { color: var(--c-disabled); }
.l9-mic { flex: none; width: 44px; height: 44px; background: var(--c-bg); color: var(--c-primary); }
.l9-box:focus-within .l9-mic { background: var(--c-tint); }
.l9-mic:disabled, .l9-box.done .l9-mic { background: var(--c-card); color: var(--c-disabled); }
.l9-mic.on { background: var(--c-primary); color: #FFFFFF; }
.l9-mic.on:hover:not(:disabled) { background: var(--c-primary-deep); color: #FFFFFF; }

/* 改正标记：删去的词红色加删除线，补上的词绿色加粗 */
.del { color: var(--c-bad); text-decoration: line-through; }
.ins { color: var(--c-ok-deep); font-weight: var(--fw-bold); } /* 输入框结果态是浅灰底，#00892F 在上面只有 4.25:1，用加深的 --c-ok-deep（4.64:1） */

/* 文字区：作答前是隐私提示（灰色小字，一行）；出结果后是「参考」小标签 + 参考答案（词块高亮）+ 译文行 */
.l9-privacy { margin: 0; font-size: var(--fs-small); line-height: 1.4; color: var(--c-text-2); text-align: center; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.ref { font-size: 12px; line-height: 1.5; color: var(--c-text-2); background: var(--c-bg); border-radius: var(--r-pill); padding: 1px 8px; margin-right: 6px; vertical-align: 2px; }

/* 反馈行：标签 + 短评，必须一行（短评不超过 12 个字，在 320 宽上放得下；依据见设计文档「反馈两层」），万一超出用省略号，完整文字在 title 里；
   完整讲解不放在这一行，放在作答框里（.l9-explain） */
.feedback.fb9 .fb-text { overflow: hidden; text-overflow: ellipsis; }
.feedback.warn .fb-ico, .feedback.warn .fb-label { color: var(--c-warn-text); }
.feedback.busy .fb-ico { color: var(--c-primary); }
.feedback.hint .fb-ico { color: var(--c-text-2); }
.feedback.fb9 .fb-ico .ico { width: 18px; height: 18px; }

/* 批改后作答框里：学习者的句子 + 完整讲解（灰色小字）。原来麦克风的位置不再显示麦克风；内容多时在框内滚动（.l9-ans 的 overflow-y），不撑开版面 */
.l9-sent { font-size: var(--fs-sentence); line-height: 1.45; color: var(--c-text); }
.l9-explain { margin: var(--sp-2) 0 0; font-size: var(--fs-small); line-height: 1.45; color: var(--c-text-2); }

/* ===== 打字模式（html.typing，由 level9.js 在输入时加上）=====
   原因：安卓微信等浏览器弹出键盘后会压缩网页高度，而图片区的正方形边长是按高度算的，高度一小它就缩成一窄条，下面各行互相重叠。
   做法：输入时不再用「按高度算的正方形」，改成自然流式、可滚动的布局——隐藏缩略图和图标行，场景句占满卡片内容宽度，
   下面是输入框、隐私提示 / 反馈行、提交按钮；内容放不下就页面滚动，不压缩任何元素。
   提交按钮「贴在键盘上方」靠文档流做到：页面至少一屏高（键盘弹出后一屏就是键盘上方那一截），按钮行用 margin-top:auto 推到最底；
   内容比一屏长时按钮在内容末尾，滚到底就能点。不用固定 / 粘性定位（style.spec.js 禁止：按钮全在文档流里，从结构上不会重叠）。
   这是对「按钮不出现、不消失、不移动」的明确例外：只在输入的这一小段时间里，左边的灰色 ← 隐藏，提交占满宽。 */
html.typing, html.typing body { height: auto; overflow-y: auto; }
html.typing .app { height: auto; min-height: 100dvh; }
html.typing .content { display: flex; flex-direction: column; align-items: center; justify-content: flex-start; }
html.typing .board { flex: 1 0 auto; flex-direction: column; align-items: stretch; gap: var(--row-gap); }
html.typing .board.write .media { width: 100%; height: auto; container-type: normal; align-self: stretch; }
html.typing .l9 { height: auto; }
html.typing .l9-thumb, html.typing .icons { display: none; }
html.typing .side { flex: 1 0 auto; width: auto; }
html.typing .text { height: auto; }
html.typing .l9-box { flex: none; min-height: 128px; }
html.typing .l9-input { flex: 1 0 auto; min-height: 72px; }
html.typing .actions { margin-top: auto; }
html.typing .actions > [data-act="prev"] { display: none; }

/* ===== 句型引擎外壳（public/js/engine/）：第 4 级对立对的示范、第 5 级示范类推 =====
   设计稿：docs/backup/assets/ui-references/level4-contrast-design.html（v3）、level5-analogy-design.html（v2）。
   骨架还是练习页同一个（图片区 / 文字区 / 图标行 / 反馈行 / 按钮行）；窄屏的页面外边距和卡片内边距由 JS 按 drill-config.js 设到 --page-x、--board-pad。 */
.opt.playing { border-color: var(--c-primary); }
.opt.dim { opacity: .45; }
.l4-demo .opt { display: flex; flex-direction: column; overflow: hidden; }
.l4-demo .opt img { flex: 1; min-height: 0; height: auto; }
.cap2 { flex: none; padding: 4px 2px 0; font-size: 12px; line-height: 16px; color: var(--c-text); text-align: center; }
/* 窄屏收紧卡片内边距，把宽度让给词块。页面外边距 ≤360 宽时已经是 8px（tokens.css 的 --pad-x）。数值与 drill-config.js 的 CHIP.narrowMaxPx、narrowMainPadPx、narrowCardPadPx 必须一致，test-ui/style.spec.js 核对 */
@media (max-width: 360px) { html.engine { --board-pad: 10px; } }

.l5-cell { position: relative; min-width: 0; min-height: 0; display: flex; flex-direction: column; padding: 0; overflow: hidden; border: 2px solid var(--c-line); border-radius: var(--r-img); background: var(--c-bg); color: var(--c-text); font: inherit; cursor: pointer; transition: border-color .2s; }
.l5-cell.target { border-style: dashed; border-color: var(--c-primary); background: var(--c-card); cursor: default; }
.l5-cell.target.ok { border-style: solid; border-color: var(--c-ok); }
.l5-cell.playing { border-color: var(--c-primary); }
.l5-cell.dim { opacity: .45; }
.l5-cell .pic { flex: 1; min-height: 0; display: flex; align-items: center; justify-content: center; padding: 4px; }
.l5-cell .pic img { display: block; max-width: 100%; max-height: 100%; object-fit: contain; }
.l5-cell .sc { display: flex; align-items: center; justify-content: center; min-height: 34px; padding: 4px 6px 6px; font-size: 13px; line-height: 17px; text-align: center; }
.blank { display: inline-block; width: 56px; height: 15px; border-bottom: 2px dashed var(--c-primary); vertical-align: baseline; }
.filled { font-weight: var(--fw-bold); white-space: nowrap; color: var(--c-ok-text); background: var(--c-ok-tint); border-radius: 4px; padding: 0 3px; }
.l5-pool { display: grid; grid-template-columns: 1fr 1fr; grid-template-rows: 1fr 1fr; gap: 4px; min-width: 0; min-height: 0; }
/* 词块：宽度、边框、内边距的数字和 drill-config.js 的 CHIP 一致（chipBorderPx、chipPadPx），字号由 JS 按 fitChips 在 15 和 12 之间选，4 块一致 */
.chip { min-width: 0; padding: 3px; border: 2px solid var(--c-line); border-radius: 10px; background: var(--c-card); color: var(--c-text); font: inherit; font-size: 15px; line-height: 18px; font-weight: var(--fw-bold);
  display: flex; align-items: center; justify-content: center; text-align: center; word-break: keep-all; overflow-wrap: normal; hyphens: none; cursor: pointer; }
.chip.sm { font-size: 12px; line-height: 15px; }
.chip.wait { opacity: .4; cursor: default; }
.chip.used { color: var(--c-disabled); background: var(--c-bg); border-color: var(--c-bg); cursor: default; }
.chip.bad { border-color: var(--c-bad); color: var(--c-bad); animation: shake .3s; cursor: default; } /* 抖完由 JS（rejectChip）换成 .used */
.chip.ok { border-color: var(--c-ok); background: var(--c-ok-tint); color: var(--c-ok-text); cursor: default; }

/* 带图的词块题（第 6、7 级）共用，类名 fixpic / fix-pic：图高固定，不随下面的答案区、词块区变化，更不会被挤没。
   原先图是「可压缩的那一块」，答案区一排满、词块池一折行，图就缩成一条（360×640 上只剩 42px）。
   现在：图高 --pic = 图片区边长 − 图下面要留的 168px（答题线 52 + 词块 2 行 96 + 2 处间距 20，是典型句子的高度），最小 140px；
   图下面放不下时，图片区变高、整页上下滚动（html.engine 的 .content 可滚），不压缩图。
   手机上图片区改成占满底板内宽（不再是正方形），多出的宽度让给词块；电脑与横屏（左右两栏）里仍是左栏的正方形，只是高度可以长。
   滚动区和居中：html.engine .content 可滚，底板用 margin: auto 居中，放得下时位置不变，放不下时从顶部排起（grid 的 place-items: center 在内容超高时会把上沿切掉）。 */
html.engine .content { place-items: initial; overflow-y: auto; }
html.engine .board { margin: auto; }
.board.fixpic { --pic: max(140px, calc(var(--media) - 168px)); }
.board.fixpic .media { width: 100%; height: auto; min-height: var(--media); }
.fix-pic { flex: none; width: 100%; height: var(--pic); display: flex; align-items: center; justify-content: center; border-radius: var(--r-img); background: var(--c-bg); }
.fix-pic img { display: block; max-width: 100%; max-height: 100%; object-fit: contain; }
@media (min-width: 768px) and (orientation: landscape) { .board.fixpic .media { width: var(--media); } }

/* 第 6 级多槽填空（设计稿 level6-multislot-design.html v1）：图片区里一列——图（高度固定，见上）、句子、一行 4 个正方形词块 */
.l6-col { width: 100%; display: flex; flex-direction: column; align-items: center; gap: 12px; }
.l6-sent { flex: none; margin: 0; min-height: 52px; display: block; font-size: 17px; line-height: 26px; text-align: center; color: var(--c-text); }
.l6 .blank { width: 72px; height: 18px; }
.l6-row { flex: none; width: 100%; display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 4px; }
.l6-row .chip { aspect-ratio: 1 / 1; }

/* 第 7 级点词组句（设计稿 level7-chunk-assembly-design.html v1）：图片区里一列——图（高度固定，见上）、答题线、词块池。词块是圆角长条，高 44，不换行，一行放不下整块折到下一行 */
.l7-col { width: 100%; display: flex; flex-direction: column; align-items: center; gap: 10px; }
.l7-ans { flex: none; width: 100%; min-height: 52px; display: flex; flex-wrap: wrap; align-content: flex-start; gap: 6px; padding: 4px 0 6px; border-bottom: 2px solid var(--c-line); transition: border-color .2s; }
.l7-ans.ok { border-bottom-color: var(--c-ok); }
.l7-pool { flex: none; width: 100%; display: flex; flex-wrap: wrap; justify-content: center; align-content: flex-start; gap: 8px; }
.pill { flex: none; height: 44px; padding: 0 14px; border: 2px solid var(--c-line); border-radius: 22px; background: var(--c-card); color: var(--c-text); font: inherit; font-size: 16px; font-weight: var(--fw-bold);
  display: inline-flex; align-items: center; white-space: nowrap; cursor: pointer; transition: border-color .2s, background .2s; }
.pill:hover:not(:disabled) { border-color: var(--c-line-strong); }
.pill.ghost { border-style: dashed; border-color: var(--c-bg); background: var(--c-bg); color: transparent; cursor: default; }
.pill.ok { border-color: var(--c-ok); background: var(--c-ok-tint); color: var(--c-ok-text); cursor: default; }
.pill.bad { border-color: var(--c-bad); color: var(--c-bad); animation: shake .3s; }

/* 结构变换选择（设计稿 transform-choice-design.html v1）：上面两格（原句、变换图标），下面 4 条通栏句子 */
.tf-col { width: 100%; height: 100%; display: flex; flex-direction: column; gap: 10px; min-height: 0; }
.tf-top { flex: 1 1 0; min-height: 0; display: grid; grid-template-columns: 1fr 1fr; gap: 10px; }
.tf-cell { position: relative; min-width: 0; min-height: 0; display: flex; flex-direction: column; padding: 0; overflow: hidden; border: 2px solid var(--c-line); border-radius: var(--r-img); background: var(--c-bg); color: var(--c-text); font: inherit; cursor: pointer; }
.tf-cell .pic { flex: 1; min-height: 0; display: flex; align-items: center; justify-content: center; padding: 4px; }
.tf-cell .pic img { display: block; max-width: 100%; max-height: 100%; object-fit: contain; }
.tf-cell .sc { display: flex; align-items: center; justify-content: center; padding: 2px 6px 6px; font-size: 13px; line-height: 17px; text-align: center; }
.tf-icon { align-items: center; justify-content: center; cursor: default; border-color: var(--c-primary); background: var(--c-tint); color: var(--c-primary); }
.tf-icon[data-type="negative"] { border-color: var(--c-bad); background: var(--c-bad-tint); color: var(--c-bad); }
.tf-icon .ico { width: min(64px, 70%); height: min(64px, 70%); }
.tf-bars { flex: none; display: flex; flex-direction: column; gap: 6px; }
.tf-bar { min-height: 46px; padding: 4px 12px; border: 2px solid var(--c-line); border-radius: 12px; background: var(--c-card); color: var(--c-text); font: inherit; font-size: 15px; line-height: 19px; font-weight: var(--fw-bold); text-align: left; cursor: pointer; transition: border-color .2s, background .2s; }
.tf-bar:hover:not(:disabled) { border-color: var(--c-line-strong); }
.tf-bar.used { color: var(--c-disabled); background: var(--c-bg); border-color: var(--c-bg); cursor: default; }
.tf-bar.bad { border-color: var(--c-bad); color: var(--c-bad); animation: shake .3s; cursor: default; }
.tf-bar.ok { border-color: var(--c-ok); background: var(--c-ok-tint); color: var(--c-ok-text); cursor: default; }

/* 第 8 级对话补全（设计稿 level8-dialogue-design.html v1）：图片区里一列——对话气泡（对方在左、学习者在右）、4 条通栏选项（和结构变换同一套 .tf-bar）。
   正在播的气泡蓝框；空格是虚线框；空格后面的台词答对前只显示「· · ·」；答对后点「文A」，每个气泡下面出现中文 */
/* 版面：对话 3–5 句加 4 条通栏比正方形图片区高，和第 6、7 级一样让图片区按内容长高（最少仍是正方形），放不下时整页滚动（html.engine .content），不压缩、不重叠 */
.board.dlgf .media { width: 100%; height: auto; min-height: var(--media); }
@media (min-width: 768px) and (orientation: landscape) { .board.dlgf .media { width: var(--media); } }
.dlg-col { width: 100%; display: flex; flex-direction: column; gap: 14px; }
.dlg { display: flex; flex-direction: column; gap: 8px; }
.dlg-line { display: flex; gap: 8px; align-items: flex-start; }
.dlg-line.me { flex-direction: row-reverse; }
.dlg-av { flex: none; width: 34px; height: 34px; border-radius: 999px; background: var(--c-yellow); color: #131313; display: flex; align-items: center; justify-content: center; font-size: 11px; font-weight: var(--fw-bold); }
.dlg-line.me .dlg-av { background: var(--c-highlight); }
.dlg-bw { display: flex; flex-direction: column; max-width: calc(100% - 42px); min-width: 0; }
.dlg-line.me .dlg-bw { align-items: flex-end; }
.dlg-bub { padding: 8px 12px; border-radius: 14px; border-top-left-radius: 4px; background: var(--c-bg); color: var(--c-text); font-size: 15px; line-height: 21px; transition: box-shadow .2s, background .2s; overflow-wrap: anywhere; }
.dlg-line.me .dlg-bub { background: var(--c-tint); color: #131313; border-top-left-radius: 14px; border-top-right-radius: 4px; }
.dlg-bub.playing { box-shadow: 0 0 0 2px var(--c-primary); }
.dlg-bub.gap { min-width: 110px; background: var(--c-card); border: 2px dashed var(--c-primary); color: var(--c-primary); text-align: center; font-weight: var(--fw-bold); }
.dlg-bub.okb { background: var(--c-ok-tint); color: var(--c-ok-text); font-weight: var(--fw-bold); box-shadow: 0 0 0 2px var(--c-ok); }
.dlg-line.hid .dlg-bub { color: var(--c-disabled); letter-spacing: 3px; }
.dlg-line.hid .dlg-av { opacity: .4; }
.dlg-zh { display: none; padding: 2px 4px 0; font-size: 12px; line-height: 17px; color: var(--c-text-2); }
.dlg.zh-on .dlg-zh { display: block; }

/* d / e 层自由表达（设计稿 free-expression-de-design.html v1）：沿用第 9 级的作答框和打字模式（.write、.l9、.l9-box、html.typing），
   题面（标题、中文意思或角色提问）、e2 的追问串、作答框底部的词数和「即将开放」的麦克风、批改结果（你写的、母语者说法、提示、结构打勾） */
/* 版面：题面 + e2 的追问串 + 批改结果可能比正方形图片区高：图片区按内容长高（最少仍是正方形），放不下时整页滚动，结果不在框内被裁掉。
   container-type 要关掉：尺寸容器的高度不随内容变（.board.write 给第 9 级开的） */
.board.fxb .media { width: 100%; height: auto; min-height: var(--media); container-type: normal; }
@media (min-width: 768px) and (orientation: landscape) { .board.fxb .media { width: var(--media); } }
.board.fxb .l9 { height: auto; min-height: 100%; }
.board.fxb .l9-box { flex: 1 0 auto; min-height: 96px; } /* 第 9 级的 flex-basis 96px 在高度随内容的列里会压住结果，这里按内容算 */
.l9.fx { gap: var(--sp-2); justify-content: flex-start; }
.fx-title { flex: none; margin: 0; font-size: var(--fs-small); color: var(--c-text-2); text-align: center; }
.fx-intent { flex: none; margin: 0; font-size: 20px; line-height: 1.4; font-weight: var(--fw-bold); color: var(--c-text); text-align: center; overflow-wrap: anywhere; }
.fx-hint { flex: none; margin: 0; font-size: var(--fs-small); color: var(--c-text-2); text-align: center; }
.fx-thread { flex: none; width: 100%; display: flex; flex-direction: column; gap: 6px; }
.fx-thread:empty { display: none; }
.fx-q { flex: none; width: 100%; display: flex; flex-direction: column; gap: 2px; padding: 8px 12px; border-radius: 14px; background: var(--c-bg); }
.fx-who { font-size: 12px; font-weight: var(--fw-bold); color: var(--c-text-2); display: flex; gap: 6px; align-items: center; }
.fx-tag { padding: 0 6px; border-radius: 999px; background: var(--c-tint); color: var(--c-primary-deep); font-size: 11px; }
.fx-qt { font-size: 16px; line-height: 1.4; color: var(--c-text); overflow-wrap: anywhere; }
.fx-box { flex-direction: column; }
.fx-foot { flex: none; width: 100%; display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.fx-foot[hidden] { display: none; }
.fx-count { font-size: var(--fs-small); color: var(--c-text-2); }
.fx-count.over { color: var(--c-bad); font-weight: var(--fw-bold); }
.fx-micw { display: flex; align-items: center; gap: 6px; }
.fx-soon { font-size: 12px; color: var(--c-text-2); }
.fx-res { flex: none; width: 100%; display: flex; flex-direction: column; gap: 8px; }
.fx-res[hidden] { display: none; }
.fx-row { display: flex; flex-direction: column; gap: 2px; }
.fx-lab { font-size: 12px; color: var(--c-text-2); }
.fx-val { font-size: 15px; line-height: 1.45; color: var(--c-text); overflow-wrap: anywhere; }
.fx-tip, .fx-prog { margin: 0; font-size: var(--fs-small); line-height: 1.45; color: var(--c-text-2); }
.fx-struct { display: flex; flex-wrap: wrap; gap: 6px; }
.fx-mark { display: inline-flex; align-items: center; gap: 4px; padding: 2px 8px; border-radius: 999px; font-size: 13px; background: var(--c-bg); color: var(--c-text-2); }
.fx-mark .ico { width: 14px; height: 14px; }
.fx-mark.yes { background: var(--c-ok-tint); color: var(--c-ok-text); }
.fx-mark.partly { background: var(--c-warn-tint); color: #131313; }
html.typing .fx-hint { display: none; }
