/* Minecraft 博士考核 —— 样式
 * 硬约束（对应 Toy 协议）：
 *   1. 不引用任何外部字体 / 图片 / CDN，全部资源本地化；
 *   2. 不使用他人素材，视觉完全由 CSS 绘制；
 *   3. 移动端优先（作品主要在 B 站 App 内的 iframe 中打开）。
 */

:root {
  --bg: #0d1015;
  --card: #171c24;
  --card-soft: #1e242e;
  --line: #2c343f;
  --line-soft: #232a34;
  --text: #e8eef4;
  --text-dim: #9aa7b4;
  --accent: #5ec46f;
  --accent-ink: #0d1015;
  --good: #5ec46f;
  --bad: #e2695f;
  --warn: #e0a54a;
  --radius: 12px;
  --radius-sm: 8px;
  --shadow: 0 12px 32px rgba(0, 0, 0, .38);
}

*,
*::before,
*::after { box-sizing: border-box; }

html, body { margin: 0; padding: 0; }

body {
  background: var(--bg);
  background-image:
    radial-gradient(900px 420px at 50% -160px, rgba(94, 196, 111, .16), transparent 70%),
    linear-gradient(180deg, #12161d 0%, #0d1015 42%);
  background-repeat: no-repeat;
  color: var(--text);
  font-family: system-ui, -apple-system, "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", sans-serif;
  font-size: 16px;
  line-height: 1.65;
  -webkit-text-size-adjust: 100%;
  -webkit-tap-highlight-color: transparent;
  min-height: 100%;
}

.app {
  max-width: 720px;
  margin: 0 auto;
  padding: 22px 16px calc(56px + env(safe-area-inset-bottom, 0px));
}

.app__noscript { padding: 24px; text-align: center; color: var(--text-dim); }

/* ---------- 页头 ---------- */

.hd { padding: 6px 2px 20px; }

.hd__title {
  margin: 0;
  font-size: 27px;
  line-height: 1.25;
  letter-spacing: .5px;
}

.hd__sub {
  margin: 8px 0 0;
  color: var(--text-dim);
  font-size: 14px;
}

/* ---------- 卡片 ---------- */

.card {
  background: var(--card);
  border: 1px solid var(--line-soft);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  padding: 18px 16px;
  margin-bottom: 14px;
}

.card--plain { box-shadow: none; background: var(--card-soft); }

.card__title {
  margin: 0 0 10px;
  font-size: 17px;
  display: flex;
  align-items: center;
  gap: 8px;
}

.card__desc { margin: 0 0 14px; color: var(--text-dim); font-size: 14px; }

.note-list { margin: 0; padding-left: 20px; color: var(--text-dim); font-size: 14px; }
.note-list li { margin: 6px 0; }
.note-list b { color: var(--text); font-weight: 600; }

/* ---------- 按钮 ---------- */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  padding: 11px 18px;
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  background: var(--card-soft);
  color: var(--text);
  font: inherit;
  font-size: 15px;
  cursor: pointer;
  transition: transform .06s ease, background-color .15s ease, border-color .15s ease;
  user-select: none;
}

.btn:hover { background: #262e39; }
.btn:active { transform: translateY(1px); }
.btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

.btn--primary {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--accent-ink);
  font-weight: 700;
}

.btn--primary:hover { background: #6ed37f; }

.btn--big { width: 100%; padding: 15px 18px; font-size: 17px; }

.btn--ghost { background: transparent; color: var(--text-dim); }
.btn--ghost:hover { background: var(--card-soft); color: var(--text); }

.btn[disabled] { opacity: .45; cursor: not-allowed; }

.btn-row { display: flex; flex-wrap: wrap; gap: 10px; }
.btn-row > .btn { flex: 1 1 auto; }

/* ---------- 答题页 ---------- */

.bar {
  height: 6px;
  border-radius: 999px;
  background: #222a34;
  overflow: hidden;
  margin-bottom: 12px;
}

.bar__fill {
  height: 100%;
  width: 0;
  border-radius: 999px;
  background: linear-gradient(90deg, #3f9a52, var(--accent));
  transition: width .25s ease;
}

.qmeta {
  display: flex;
  flex-wrap: wrap;
  gap: 6px 12px;
  justify-content: space-between;
  color: var(--text-dim);
  font-size: 13px;
  margin-bottom: 12px;
}

/* 反馈渠道要求“注明题号”，所以题号得给玩家看：答题页右上角 + 解析底部 */
.qmeta__id {
  letter-spacing: .06em;
  opacity: .78;
  font-variant-numeric: tabular-nums;
}

/* 题型提示（答题页题目开头）：让玩家一眼知道这题怎么作答。
   名字来自题型接口 name()，与题型实现解耦 */
.qmeta__type {
  display: inline-block;
  margin-left: 8px;
  padding: 0 8px;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: var(--line-soft);
  color: var(--accent);
  font-size: 12px;
  letter-spacing: .04em;
}

/* 作答方式提示（题干下方、作答区上方）—— 由题型的 howTo 钩子给，非空才出现。
   排序 / 合成这类“得先知道怎么点”的题型才需要；单选多选不写这个钩子。
   底部那行只留“已排 3 / 6”这类随时会变的状态。 */
.howto {
  margin: -2px 0 14px;
  padding: 8px 12px;
  border-left: 3px solid var(--accent);
  border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
  background: rgba(255, 255, 255, .035);
  color: var(--text-dim);
  font-size: 13.5px;
  line-height: 1.6;
}

.explain__meta {
  margin: 10px 0 0;
  padding-top: 10px;
  border-top: 1px dashed var(--line);
  color: var(--text-dim);
  font-size: 12.5px;
}

/* 每题限时 */

.timer {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-bottom: 10px;
}

.timer__track {
  flex: 1 1 auto;
  height: 4px;
  border-radius: 999px;
  background: #222a34;
  overflow: hidden;
}

.timer__fill {
  height: 100%;
  width: 100%;
  border-radius: 999px;
  background: #7b8794;
  transition: width .1s linear, background-color .2s ease;
}

.timer__fill.is-urgent { background: var(--bad); }

.timer__label {
  flex: 0 0 auto;
  min-width: 44px;
  text-align: right;
  color: var(--text-dim);
  font-size: 12.5px;
  font-variant-numeric: tabular-nums;
}

.stem {
  margin: 0 0 16px;
  font-size: 19px;
  line-height: 1.55;
  font-weight: 600;
}

.opts { list-style: none; margin: 0; padding: 0; }
.opts li { margin-bottom: 10px; }

.opt {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  width: 100%;
  padding: 13px 14px;
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  background: var(--card-soft);
  color: var(--text);
  font: inherit;
  font-size: 15.5px;
  text-align: left;
  cursor: pointer;
  transition: background-color .12s ease, border-color .12s ease;
}

.opt:hover { background: #262e39; border-color: #3a4452; }
.opt:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

.opt[disabled] { cursor: default; }
.opt[disabled]:hover { background: var(--card-soft); }

.opt__key {
  flex: 0 0 auto;
  width: 26px;
  height: 26px;
  border-radius: 6px;
  background: #2b333f;
  color: var(--text-dim);
  font-size: 13px;
  font-weight: 700;
  display: flex;
  align-items: center;
  justify-content: center;
}

.opt__text { flex: 1 1 auto; }

.opt.is-correct { border-color: var(--good); background: rgba(94, 196, 111, .14); }
.opt.is-correct .opt__key { background: var(--good); color: var(--accent-ink); }

.opt.is-wrong { border-color: var(--bad); background: rgba(226, 105, 95, .13); }
.opt.is-wrong .opt__key { background: var(--bad); color: #fff; }

.opt.is-dim { opacity: .52; }

/* 已选、但**还没确认**。标记长什么样由题型决定（见 .opts--dot / .opts--none） */
.opt.is-picked { border-color: var(--accent); background: rgba(255, 255, 255, .06); }
.opt.is-picked .opt__key { background: var(--accent); color: var(--accent-ink); }
/* 默认：打勾（多选） */
/* 两种标记都 align-self: center —— .opt 是 flex-start，不写就会贴着顶边 */
.opt.is-picked::after {
  content: '✓';
  align-self: center;
  margin-left: 10px;
  color: var(--accent);
  font-weight: 700;
}
/* 单选：圆点 */
.opts--dot .opt.is-picked::after {
  content: '';
  flex: none;
  align-self: center;
  width: 10px;
  height: 10px;
  margin-left: 10px;
  border-radius: 50%;
  background: var(--accent);
}
/* 排序：右边已经有“第 N 位”，不再叠一个勾 */
.opts--none .opt.is-picked::after { content: none; }

/* 排序题：选项右侧的位次标签（选项本身位置不动，否则玩家会丢失位置感） */
.opt__pos {
  flex: 0 0 auto;
  margin-left: 8px;
  padding: 2px 8px;
  border-radius: 999px;
  background: rgba(94, 196, 111, .18);
  color: var(--accent);
  font-size: 12px;
  white-space: nowrap;
}

/* 解析 */

.explain {
  margin-top: 16px;
  padding: 14px;
  border: 1px solid var(--line-soft);
  border-left: 3px solid var(--accent);
  border-radius: var(--radius-sm);
  background: #141922;
}

.explain.is-wrong { border-left-color: var(--bad); }

.explain__verdict {
  margin: 0 0 8px;
  font-size: 15px;
  font-weight: 700;
}

.explain__verdict.is-correct { color: var(--good); }
.explain__verdict.is-wrong { color: var(--bad); }

.explain__body { margin: 0; font-size: 15px; }

/* 解析里的“正确摆法”（合成题的 answerHtml）：标签与小网格同一行，窄屏自动换行 */
.explain__answer {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
  margin: 10px 0 0;
  font-size: 14px;
  color: var(--text-dim);
}

/* 彩蛋：解析临时被换成彩蛋文字，点一下恢复真正解析（见 app.js 的 rollEgg / eggActive） */
.explain__body.egg__body {
  border-left: 3px solid var(--warn);
  padding-left: 10px;
  color: #ffe2b6;
  cursor: pointer;
}
.egg__hint {
  margin: 8px 0 0;
  font-size: 12px;
  color: var(--text-dim);
  cursor: pointer;
}
.egg__hint::before { content: "🥚 "; }

/* 解析里的零素材配方表：文本写 [grid: …]，渲染成 CSS 格子（见 questions.js 顶部说明）。
   色相 --h 由 app.js 按“材料出场顺序”稳定分配，只为区分材料，不表示游戏内任何信息。 */
.craft {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px;
  margin: 12px 0;
}

.craft__grid {
  display: grid;
  gap: 3px;
  padding: 3px;
  border-radius: var(--radius-sm);
  background: var(--line-soft);
}

.craft__cell {
  display: flex;
  align-items: center;
  justify-content: center;
  min-width: 48px;
  max-width: 84px;
  padding: 7px 5px;
  border-radius: 5px;
  background: hsl(var(--h, 200), 42%, 30%);
  font-size: 11px;
  line-height: 1.25;
  text-align: center;
}

.craft__cell.is-empty { background: transparent; box-shadow: inset 0 0 0 1px var(--line); }

.craft__cell--out {
  min-width: 58px;
  border: 1px solid var(--line);
  font-weight: 700;
}

.craft__arrow { color: var(--text-dim); font-size: 18px; }

/* ------------------------------------------------------ 合成题（craft）
 * 格子 / 箭头 / 输出格三张图取自 26.3 的 crafting_table.png（见 GAME_ASSETS.md）。
 * 尺寸一律用**整数倍**：格子 18→54（3×）、图标 16→48（3×）、箭头 22×14→66×42（3×）、
 * 产物格 26→78（3×，原版的产物格本来就比普通格子大）。
 * 图标 16→48 对**方块物品**也成立：方块渲染图（300×300）的画布本来就等价于 16×16
 * 物品区（内容 268×296 vs 原版 0.625 GUI 变换下的投影轮廓 88.4% × 98.3%），
 * 别再按 0.625 去缩 —— 那会小掉三成。依据与算式见 assets/img/GAME_ASSETS.md。
 * 再大就放不下了：375px 宽的屏上，3 格 + 箭头 + 输出格一行只能到 54px 这个档次。 */

/* ---------------------------------------------------------- 合成表
 * 尺寸全部用 --gui（一个「逻辑像素」）的整数倍表示。
 *
 * 为什么：原版 GUI 的每一个逻辑像素都等于**整数个设备像素**（选项里界面尺寸只有整数，
 * `Window.calculateScale` 取「仍能容纳 320×240 逻辑像素」的最大整数缩放），所以精灵、
 * 文字、底板永远落在设备像素网格上。我们在 CSS 里用固定 px 的话，dpr=1.25 时
 * 1 逻辑像素就变成 3.75 个设备像素，16×16 的精灵会出现宽窄不一的纹素。
 * ⇒ --gui 由 app.js 的 applyGuiUnit() 设成 k/dpr（k 是整数设备像素），见那里的说明。
 *
 * 下面的数字都是 GUI 像素单位：格子 18、物品 16、产物格 26、箭头 22×14、回顾小格 12。 */
:root { --gui: 3px; }        /* 没跑 JS 时的兜底（= dpr 1 下的值） */

.craft-board {
  margin: 2px 0 4px;
  /* 板子至少需要多少逻辑像素（app.js 按它和可用宽度算 k：装不下就降一档，
     与「原版窗口太小就掉一个界面尺寸」同理）。取两个约束里大的那个：
       · 合成那一行：3×18 格 + 2×3 间距 + 箭头 22 + 产物格 26 = **108**
       · 材料区一行：留 **7 个材料**的宽度 = 7×20 + 6×3 = **158**
     取 158 ⇒ 宽度预算按「7 个材料」算，而题目实际只有 5~6 种材料，板子就比容器窄，
     左右各留出约 25 逻辑像素的留白（作者 2026-10-01 要的观感）。
     副作用也正是想要的：材料多少不同，同一种题型的板子**大小一致**。 */
  --gui-min-w: 158;
}

/* 材料区（放在合成栏**下方**：先看题目、再看能拿什么） */
.craft-board__mats {
  display: flex;
  flex-wrap: wrap;
  gap: calc(var(--gui) * 3);
  justify-content: center;
  align-items: center;
  margin-top: 16px;
}

.craft-mat__btn {
  width: calc(var(--gui) * 20);
  height: calc(var(--gui) * 20);
  padding: 0;
  display: grid;
  place-items: center;
  border: 1px solid var(--line);
  border-radius: 10px;
  background: var(--card-soft);
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}

.craft-mat__btn.is-hand {
  border-color: var(--accent);
  background: rgba(94, 196, 111, .12);
}

.craft-mat__btn[disabled] { cursor: default; opacity: .55; }

.craft-clear {
  /* ⚠️ 原来这里只写了 height、没写 width，字号又是写死的 14px（不跟 --gui 走）——
     于是它**只在默认档位（--gui 3px）下恰好是正方形**：15 + 文字 29.6 + 15 ≈ 60
     = 20 逻辑像素。档位一大，材料按钮跟着胖、它却仍按 14px 算文字宽度，就"瘦"出一块
     （实测 --gui 5.6px：材料按钮 112×112，清空 85.6×112）。
     现在和材料按钮用同一套单位：20 × 20 逻辑像素的正方形，字号换成
     14/3 逻辑像素（= 默认档位下原来的 14px，观感不变，只是会跟着一起缩放）。 */
  width: calc(var(--gui) * 20);
  height: calc(var(--gui) * 20);
  padding: 0;
  border: 1px solid var(--line);
  border-radius: 10px;
  background: var(--card-soft);
  color: var(--text-dim);
  font-size: calc(var(--gui) * 14 / 3);
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}

.craft-clear[disabled] { cursor: default; opacity: .4; }

.craft-board__row {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: calc(var(--gui) * 3);
  /* 板子需要时允许吃掉卡片左右的 padding（--craft-pad-* 由 app.js 量出来），
     这样在 125%/150% 这种非整数 dpr 上不必为了对齐而降一档、把板子变小。 */
  margin-left: calc(-1 * var(--craft-pad-l, 12px));
  margin-right: calc(-1 * var(--craft-pad-r, 12px));
}

.craft-board__grid {
  display: grid;
  grid-template-columns: repeat(3, calc(var(--gui) * 18));
  grid-auto-rows: calc(var(--gui) * 18);
}

.craft__slot {
  padding: 0;
  border: 0;
  /* 两层背景：上面那层是揭晓用的染色（--craft-tint，默认 none），下面是格子底图。
     染色层尺寸写死 48px = 16×3，正好是底图 16×16 井位的大小 ⇒ **只染井位、不染 1px 边框**。
     多背景里第一层在最上面，所以染色落在底图之上、子元素（物品图标）之下。 */
  --craft-tint: none;
  background-image: var(--craft-tint), url('../img/craft-cell.png');
  background-size: calc(var(--gui) * 16) calc(var(--gui) * 16), calc(var(--gui) * 18) calc(var(--gui) * 18);
  background-position: center, center;
  background-repeat: no-repeat, no-repeat;
  display: grid;
  place-items: center;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}

.craft__slot[disabled] { cursor: default; }

/* 格子 / 输出格 / 箭头 / 回顾小格的**底图**都是原版像素图，按 2×~3× 整数倍放大，
   所以必须声明最近邻 —— 浏览器默认的双线性会把那 1px 边框糊成灰阶渐变
   （.craft-icon 早就写了 pixelated，这四处漏了）。
   ⚠️ 只加在“画底图”的元素上，别加到 .craft-board 这类容器上：容器里还有 300×300 的
      方块渲染图，它们是**非整数倍缩小**，最近邻反而会出锯齿。 */
.craft__slot,
.craft-board__out,
.craft-board__arrow,
.craft-mini__cell {
  image-rendering: pixelated;
}

/* 揭晓时逐格比对（配色照 Litematica 那套）：绿=放对、蓝=缺材料、红=放错、品红=多余。
   正确答案是空、玩家也没放 → 不加任何颜色。

   ⚠️ 染色走**渐变背景层**，另外两种做法都不行：
     · background-color：格子底图 craft-cell.png **完全不透明**（alpha 全 255、中心 rgb(139,139,139)），
       背景色画在底图**下面**，会被整块盖住、一点都看不见；
     · box-shadow inset：阴影跟着 **54px 的整个格子**走，会把外圈那 1px 边框一起染了 ——
       原版里被标记的是 16×16 的物品区，边框不属于它。
   尺寸 48px 与底图井位（16×16 → 48px）重合，于是染色只落在井位里。 */
.craft__slot.is-ok { --craft-tint: linear-gradient(rgba(60, 175, 85, .55), rgba(60, 175, 85, .55)); }
.craft__slot.is-missing { --craft-tint: linear-gradient(rgba(60, 130, 210, .55), rgba(60, 130, 210, .55)); }
.craft__slot.is-wrong { --craft-tint: linear-gradient(rgba(215, 70, 60, .55), rgba(215, 70, 60, .55)); }
.craft__slot.is-extra { --craft-tint: linear-gradient(rgba(200, 70, 200, .55), rgba(200, 70, 200, .55)); }

.craft-board__arrow {
  width: calc(var(--gui) * 22);
  height: calc(var(--gui) * 14);
  background: url('../img/craft-arrow.png') center / contain no-repeat;
  opacity: .85;
}

.craft-board__out {
  position: relative;                 /* 产物数量（.craft-out__count）的定位基准 */
  /* ⚠️ 原版合成界面里**产物格比普通格子大**：26×26（普通格子 18×18），
     物品区仍是 16×16、居中（每边 5 源像素）。所以这里 26→78px（3×），
     background-size 也要跟着改，否则底图会被拉伸。 */
  width: calc(var(--gui) * 26);
  height: calc(var(--gui) * 26);
  display: grid;
  place-items: center;
  background: url('../img/craft-out.png') center / calc(var(--gui) * 26) calc(var(--gui) * 26) no-repeat;
}

/* 产物数量：照原版画在输出格的**右下角**（白字 + 右下 1 逻辑像素的深色投影）。
   字号是按原版量出来的比例定的 —— 游戏里数量数字高 7 个 GUI 像素（MC 字体的数字是 7px 高），
   而物品区是 16 个：7/16 = 0.438；我们物品区 48px ⇒ 数字应高约 21px。
   浏览器实测 system-ui 的数字高 ≈ 0.79 × font-size，所以取 27px（≈21.3px）。
   位置锚在**物品区**的右下角：物品区在 78px 的格子里居中 ⇒ 距格子边 (78-48)/2 = 15px；
   bottom 给 12px 而不是 15px，是因为系统字体的数字基线下面还有 descent 的空隙。
   ⚠️ 纯显示：判定不看它（题库里写 craft 题的 resultCount）。 */
.craft-out__count {
  position: absolute;
  right: calc(var(--gui) * 5);
  bottom: calc(var(--gui) * 4);
  font-size: calc(var(--gui) * 9);
  line-height: 1;
  /* 字重回常规（2026-10-01）：原版的物品数量就是普通字重。
     当初加粗是怕 9 逻辑像素下太细，量过之后发现不必 —— 数字的**墨迹高度与字重无关**
     （canvas 实测 200px 下 400 与 700 都是 157px，h/fontSize = 0.785），粗体只是宽约 6%
     （"12" 的墨迹宽 205 → 217px）。⇒ 上面那个字号不用跟着调：
     9 逻辑像素 × 0.785 = 7.07 逻辑像素，正好是原版的 7。
     （观感上 MC 字体本身就偏粗；有些 UI 渲染优化 mod 画出来会更细。） */
  color: #fff;
  /* 投影照原版 —— 不是「四周描边」：原版把**文字形状的副本**往右下挪 1 个 GUI 像素垫在下面，
     颜色是文字色的 RGB × 0.25（白字 ⇒ #3f3f3f，alpha 不变 ⇒ 不透明）。
     依据（26.3，可复核）：Font.getShadowColor() → ARGB.scaleRGB(textColor, 0.25F)；
     GlyphInfo.getShadowOffset() → 1.0F。 */
  text-shadow: calc(var(--gui) * 1) calc(var(--gui) * 1) 0 #3f3f3f;
  pointer-events: none;
}

.craft-icon {
  width: calc(var(--gui) * 16);
  height: calc(var(--gui) * 16);
  image-rendering: pixelated;
}

.craft-icon--bad { color: var(--bad); }

/* 等轴渲染的方块由 types/craft.js **逐像素**画成 PNG（硬边、纹理最近邻采样），
   按目标尺寸的 **4 倍**渲染后由浏览器缩下来（相当于 SSAA）：轮廓平滑，纹理仍是硬像素。
   整块只有一张图，所以不会出现 CSS 3D 那种“每个面各自抗锯齿、公共棱漏背景”的暗缝。
   ⚠️ 正因为它自己超采样过了，这里要把 .craft-icon 的 pixelated 覆盖回 auto ——
      否则浏览器会拿最近邻把这 4× 的图画成粗块，超采样白做。 */
.craft-iso {
  image-rendering: auto;
}

/* 结果页错题回顾里的小网格：比作答区小一档，但仍是整数倍 */
.craft-mini {
  display: inline-grid;
  grid-template-columns: repeat(3, calc(var(--gui) * 12));
  grid-auto-rows: calc(var(--gui) * 12);
  vertical-align: middle;
  margin-top: 4px;
}

.craft-mini__cell {
  display: grid;
  place-items: center;
  background: url('../img/craft-cell.png') center / calc(var(--gui) * 12) calc(var(--gui) * 12) no-repeat;
}

/* 回顾小格里物品也留 1 逻辑像素的内缩（原版 18 格 → 16 物品的同比例缩小版） */
.craft-mini__cell .craft-icon { width: calc(var(--gui) * 10); height: calc(var(--gui) * 10); }

/* 题目配图：文本写 [img: 文件名 | 图注]，文件放 assets/img/ 并登记来源与许可 */
.rich-img {
  display: block;
  max-width: 100%;
  height: auto;
  margin: 12px auto;
  border: 1px solid var(--line-soft);
  border-radius: var(--radius-sm);
  background: var(--card-soft);
}

.rich-img-cap {
  display: block;
  margin: -6px 0 12px;
  color: var(--text-dim);
  font-size: 12px;
  text-align: center;
}

/* 行内图标（[img:inline 文件.png]）：不换行、无圆角/边框/底色，高度跟着文字；
   作者写 [img:inline 24 文件.png] 时由行内 style 指定像素高度 */
.rich-img--inline {
  display: inline-block;
  vertical-align: -0.18em;
  width: auto;
  height: 1.15em;
  margin: 0 1px;
  padding: 0;
  border: 0;
  border-radius: 0;
  background: none;
  object-fit: contain;
  image-rendering: pixelated;
}

/* 行内图标取不到图时，缺失贴图也得跟着变小（不然 220px 的棋盘方块直接砸进句子里） */
.rich-img--inline.rich-img--missing { width: auto; height: 1.15em; }

/* 题目外链（[link: …]）：点之前一个字节都不请求，只是引用 */
.rich-link {
  color: var(--accent);
  text-decoration: underline;
  text-decoration-style: dotted;
  text-underline-offset: 2px;
  overflow-wrap: anywhere;
}

.rich-link:hover { text-decoration-style: solid; }

/* 图片缺失时顶上来的“缺失贴图”：由 assets/js/missing.js 生成（16×16 黑+品红棋盘，零素材） */
.rich-img--missing {
  width: 220px;
  height: 220px;
  image-rendering: pixelated;
  border-color: rgba(255, 0, 255, .45);
}

/* 作者视角：dev 画廊里加载失败的配图，把文件名标成警示色 */
.dev__imgwrap img[data-missing="1"] + .dev__imgname { color: var(--warn); }

/* 图片缺失 / 写法写错时的提示（正常情况不该出现） */
.rich-img-missing {
  display: block;
  margin: 12px 0;
  padding: 10px 12px;
  border: 1px dashed rgba(224, 165, 74, .5);
  border-radius: var(--radius-sm);
  color: var(--warn);
  font-size: 12.5px;
  line-height: 1.5;
}

.actions { margin-top: 16px; }

/* 题目数据不完整时的提示（正常情况下不该出现，出现即说明题库写错了） */
.qnotice {
  margin: 14px 0 0;
  padding: 10px 12px;
  border: 1px dashed rgba(224, 165, 74, .5);
  border-radius: var(--radius-sm);
  color: var(--warn);
  font-size: 13.5px;
}

/* ---------- 结果页 ---------- */

.score { text-align: center; padding: 8px 0 4px; }

.score__num {
  margin: 0;
  font-size: 46px;
  font-weight: 800;
  letter-spacing: 1px;
  color: var(--accent);
}

.score__num small { font-size: 20px; color: var(--text-dim); font-weight: 600; }

.score__rank { margin: 6px 0 0; font-size: 19px; font-weight: 700; color: var(--text); }

/* 等级小图标：一颗纯色小方块（零素材；颜色由 --c 传入，见 app.js 的 rankColor） */
.rankicon {
  display: inline-block;
  width: 14px;
  height: 14px;
  margin-right: 8px;
  border-radius: 3px;
  vertical-align: -1px;
  background: var(--c, #9aa4ae);
  box-shadow:
    inset 0 3px rgba(255, 255, 255, .14),
    inset 0 -3px rgba(0, 0, 0, .22),
    0 0 0 1px rgba(255, 255, 255, .16);   /* 深色档（下界合金）在深底上也能看清 */
}

.score__rankdesc {
  margin: 6px 0 0;
  color: var(--text-dim);
  font-size: 14px;
  padding: 0 6px;
}

.score__pct { margin: 6px 0 0; color: var(--text-dim); font-size: 14px; }

/* 分享海报：整张图由 canvas 绘制，这里只负责显示 */
.poster {
  display: block;
  width: 100%;
  max-width: 340px;
  margin: 12px auto 0;
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  background: #0d1015;
}

.wrong-list { list-style: none; margin: 0; padding: 0; }

.wrong-list > li {
  padding: 12px 0;
  border-top: 1px solid var(--line-soft);
}

.wrong-list > li:first-child { border-top: 0; }

.wrong-item__stem { margin: 0 0 6px; font-weight: 600; font-size: 15.5px; }
.wrong-item__line { margin: 2px 0; font-size: 14px; color: var(--text-dim); }
.wrong-item__line b { color: var(--bad); font-weight: 600; }
.wrong-item__line b.is-correct { color: var(--good); }
.wrong-item__exp { margin: 6px 0 0; font-size: 14.5px; color: var(--text-dim); }

.copybox {
  width: 100%;
  min-height: 108px;
  margin-top: 10px;
  padding: 10px;
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  background: #10151c;
  color: var(--text-dim);
  font: 13px/1.6 ui-monospace, Consolas, monospace;
  resize: vertical;
}

.foot {
  margin-top: 22px;
  text-align: center;
  color: #6d7986;
  font-size: 12.5px;
  line-height: 1.8;
}

.foot code {
  padding: 1px 5px;
  border-radius: 4px;
  background: #1b212a;
  font-size: 12px;
}

/* 页脚里的引用链接（2026-10-01 撤掉 wiki 署名后暂时没用到，样式留着备用）：
   项目没有全局 a 样式，不写的话会落到浏览器默认的蓝 / 紫
   —— 深色底上又丑又不清楚。这里比正文略亮 + 下划线，静默但认得出来。 */
.foot a {
  color: var(--text-dim);
  text-decoration: underline;
  text-underline-offset: 2px;
}

.foot a:hover { color: var(--accent); }

/* 开发面板（仅在 ?dev=1 时插入 DOM） */

.dev {
  margin-top: 14px;
  padding: 12px 14px;
  border: 1px dashed rgba(224, 165, 74, .5);
  border-radius: var(--radius-sm);
  color: var(--warn);
  font-size: 12.5px;
  line-height: 1.7;
  overflow-wrap: anywhere;
}

.dev p { margin: 0 0 4px; }

.dev__head {
  margin: 12px 0 6px;
  font-weight: 700;
  color: #f0c479;
}

.dev__list { margin: 0; padding-left: 18px; }
.dev__list li { margin: 3px 0; }
.dev__list b { color: #ffd9a0; }

.dev__grid { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 6px; }

.dev__item {
  padding: 3px 8px;
  border: 1px solid rgba(224, 165, 74, .45);
  border-radius: 6px;
  background: transparent;
  color: inherit;
  font: inherit;
  font-size: 11.5px;
  cursor: pointer;
}

.dev__item:hover { background: rgba(224, 165, 74, .14); }
.dev__item:focus-visible { outline: 2px solid var(--warn); outline-offset: 1px; }

/* dev 面板里的配图画廊：一眼看出哪张图没加载出来 */
.dev__images { display: flex; flex-wrap: wrap; gap: 10px; margin-top: 6px; }
.dev__imgwrap { display: flex; flex-direction: column; align-items: center; gap: 4px; }
.dev__imgwrap .rich-img { margin: 0; }
.dev__imgname { color: var(--text-dim); font-size: 11px; text-align: center; word-break: break-all; }
.rich-img--thumb { max-height: 72px; width: auto; }

/* ---------- 进度（Java 的 Advancement；代码里用 adv 前缀） ---------- */

.adv-list { list-style: none; margin: 0; padding: 0; }

.adv {
  display: flex;
  gap: 12px;
  align-items: flex-start;
  padding: 12px;
  border: 1px solid var(--tier, var(--line-soft));
  border-radius: var(--radius-sm);
  background: var(--card-soft);
}

.adv + .adv { margin-top: 10px; }

/* 未达成：整体压暗，图标也变灰（颜色由 app.js 从条目的 color 传进 --c） */
.adv--locked { opacity: .55; }
.adv--locked .adv__icon { background: #4a525c; }

/* 进度图标：一颗纯色小方块，零素材（同结果页的 .rankicon） */
.adv__icon {
  flex: 0 0 auto;
  width: 22px;
  height: 22px;
  margin-top: 2px;
  border-radius: 5px;
  background: var(--c, #9aa4ae);
  box-shadow:
    inset 0 3px rgba(255, 255, 255, .16),
    inset 0 -3px rgba(0, 0, 0, .22),
    0 0 0 1px rgba(255, 255, 255, .16);
}

.adv__body { min-width: 0; }
.adv__name { margin: 0; font-size: 16px; font-weight: 700; }
.adv__desc { margin: 4px 0 0; color: var(--text-dim); font-size: 14px; }
.adv__meta { margin: 6px 0 0; color: var(--text-dim); font-size: 13px; }

/* 结果页：历史最高分 / 本轮满分露的进度条 */
.score__best { margin: 8px 0 0; color: var(--text-dim); font-size: 14px; }
.score__best b { color: var(--text); }
.score__adv { margin: 10px 0 0; color: var(--accent); font-size: 15px; font-weight: 700; }

/* 进度达成弹窗（模仿 Java 版右上角的“进度达成！”）：从右侧划入 → 停留 → 再划走。
   多个同时达成时在容器里自上而下堆叠；
   ⚠️ 浮层由 app.js 动态创建/移除，不参与 render() 重绘（否则每次重画都会重播动画）。 */
.adv-toasts {
  position: fixed;
  top: 12px;
  right: 12px;
  z-index: 60;
  display: flex;
  flex-direction: column;
  gap: 8px;
  align-items: flex-end;
  pointer-events: none;   /* 纯展示：不挡下面的按钮 */
}

.adv-toast {
  display: flex;
  gap: 10px;
  align-items: center;
  width: max-content;
  max-width: min(320px, calc(100vw - 24px));
  padding: 10px 14px;
  border: 1px solid var(--tier, var(--line));
  border-left-width: 3px;   /* 左侧竖条取分级色（同一条边框，只是加粗） */
  border-radius: var(--radius-sm);
  background: rgba(23, 28, 36, .94);
  box-shadow: var(--shadow);
  animation: adv-toast 4.6s cubic-bezier(.22, .8, .3, 1) both;
}

.adv-toast__icon {
  flex: 0 0 auto;
  width: 20px;
  height: 20px;
  border-radius: 5px;
  background: var(--c, #9aa4ae);
  box-shadow:
    inset 0 3px rgba(255, 255, 255, .16),
    inset 0 -3px rgba(0, 0, 0, .22),
    0 0 0 1px rgba(255, 255, 255, .16);
}

.adv-toast__body { min-width: 0; }
.adv-toast__title { margin: 0; color: var(--text-dim); font-size: 12px; font-weight: 600; }
.adv-toast__name { margin: 2px 0 0; font-size: 15px; font-weight: 700; }

/* 划入 → 停留 → 划走（时长要与 app.js 的 TOAST_MS 一致） */
@keyframes adv-toast {
  0%   { transform: translateX(115%); opacity: 0; }
  10%  { transform: translateX(0);    opacity: 1; }
  86%  { transform: translateX(0);    opacity: 1; }
  100% { transform: translateX(115%); opacity: 0; }
}

/* 分级（对齐 Java 版三档）：**框的样式按分级走**，与判定无关。
   进度 = 灰框；目标 = 青框；挑战 = 紫框 + 斜纹底（Java 版挑战就是这种花纹）。
   · 三档只给一个 `--tier`，由 .adv / .adv-toast 的 border 统一取用（缺省 = 原来的灰）；
   · 条目自己的 `color` 只留在图标上（进度页的方块 / 弹窗的方块）。 */
.adv--task,
.adv-toast--task { --tier: #3a4450; }

.adv--goal,
.adv-toast--goal { --tier: #3f7d8c; }

.adv--challenge,
.adv-toast--challenge {
  --tier: #8a5fb0;
  background-image: repeating-linear-gradient(135deg, rgba(138, 95, 176, .14) 0 6px, transparent 6px 12px);
}

/* ------------------------------------------------------ 连线题（match）
   两列一一对应：左列是题面项（带序号、固定），右列是选项（带字母、会打乱）。
   连到谁写在每项右侧的小标签里（左列显示对方字母，右列显示对方序号），
   所以从任意一列都能把整张对应关系读出来。
   揭晓配色与合成题同一套：绿=连对、红=连错、虚线压暗=没连。 */

.match {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 10px;
  align-items: start;
}

.match__col {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.match__item {
  display: flex;
  align-items: center;
  gap: 8px;
  width: 100%;
  /* 两列的框高一致：左列放图标、右列放文字时才不会一边高一边矮 */
  min-height: 54px;
  padding: 10px;
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  background: var(--card-soft);
  color: var(--text);
  font: inherit;
  font-size: 14.5px;
  text-align: left;
  cursor: pointer;
  transition: background-color .12s ease, border-color .12s ease;
}

.match__item:hover { background: #262e39; border-color: #3a4452; }
.match__item:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.match__item[disabled] { cursor: default; }
.match__item[disabled]:hover { background: var(--card-soft); border-color: var(--line); }

/* 左列的序号 / 右列的字母 */
.match__idx,
.match__key {
  flex: 0 0 auto;
  width: 22px;
  height: 22px;
  border-radius: 6px;
  background: #2b333f;
  color: var(--text-dim);
  font-size: 12px;
  font-weight: 700;
  display: flex;
  align-items: center;
  justify-content: center;
}

.match__text { flex: 1 1 auto; min-width: 0; overflow-wrap: anywhere; }

/* 连线题里的 [img: …] 按**图标**渲染：原版物品贴图只有 16×16，不放大就是一个小点
   （2 倍整数放大 + 最近邻，和合成题的图标一个路子）。
   ⚠️ 所以连线题两列里适合放**图标**；要放整张示意图/截图请写在题干或解析里。 */
.match__item .rich-img {
  width: auto;
  height: 32px;
  margin: 0;
  border: 0;
  border-radius: 0;
  background: none;
  object-fit: contain;
  image-rendering: pixelated;
}

/* 图标不带图注；万一写了 [img:文件|图注]，把它压成紧跟着的小字 */
.match__item .rich-img-cap {
  margin: 0 0 0 6px;
  font-size: 11px;
  text-align: left;
}

/* “连到谁”：没连时是一条短横线 */
.match__to {
  flex: 0 0 auto;
  min-width: 22px;
  padding: 1px 5px;
  border-radius: 6px;
  background: rgba(255, 255, 255, .06);
  color: var(--text-dim);
  font-size: 12px;
  font-weight: 700;
  text-align: center;
}

.match__item.is-linked { border-color: rgba(94, 196, 111, .5); }
.match__item.is-linked .match__idx,
.match__item.is-linked .match__key { background: rgba(94, 196, 111, .22); color: var(--accent); }
.match__item.is-linked .match__to { background: rgba(94, 196, 111, .2); color: var(--accent); }

/* 已经选中、正等着接线的左项 */
.match__item.is-picked {
  border-color: var(--accent);
  background: rgba(255, 255, 255, .06);
  box-shadow: inset 0 0 0 1px var(--accent);
}

.match__item.is-ok { border-color: var(--good); background: rgba(94, 196, 111, .14); }
.match__item.is-ok .match__to { background: var(--good); color: var(--accent-ink); }

.match__item.is-wrong { border-color: var(--bad); background: rgba(226, 105, 95, .13); }
.match__item.is-wrong .match__to { background: var(--bad); color: #fff; }

/* 压根没连上 */
.match__item.is-missing { opacity: .7; border-style: dashed; }

.match__foot { margin-top: 10px; text-align: right; }

.match-clear {
  padding: 6px 12px;
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  background: transparent;
  color: var(--text-dim);
  font: inherit;
  font-size: 13px;
  cursor: pointer;
}

.match-clear:hover { background: var(--card-soft); color: var(--text); }
.match-clear[disabled] { opacity: .45; cursor: not-allowed; }

/* ---------- 窄屏 ---------- */

@media (max-width: 420px) {
  .app { padding: 18px 12px 48px; }
  .hd__title { font-size: 23px; }
  .stem { font-size: 17.5px; }
  .score__num { font-size: 40px; }
  /* 连线题两列在窄屏上更挤，缩一档内边距与字号 */
  .match { gap: 8px; }
  .match__item { padding: 8px; gap: 6px; font-size: 13.5px; min-height: 46px; }
  .match__item .rich-img { height: 26px; }
  .match__idx, .match__key { width: 20px; height: 20px; font-size: 11.5px; }
  .match__to { min-width: 20px; font-size: 11.5px; }
}

@media (prefers-reduced-motion: reduce) {
  * { transition: none !important; animation: none !important; }
}
