/* ============ 对口升学 · 移动端优先样式 ============ */
* { margin:0; padding:0; box-sizing:border-box; -webkit-tap-highlight-color:transparent; }
/* 界面整体大小随屏幕自动缩放：--ui-scale 由 js/fit.js 按屏幕宽度写入（见该文件注释）。
   JS 未执行时保持默认值 1，界面与改动前完全一致。
   注意：这里是全站缩放的唯一入口 —— 下面的尺寸全部用 rem，都会跟着它一起缩放。 */
html { font-size:calc(16px * var(--ui-scale)); }
body {
  font-family:"PingFang SC","Microsoft YaHei","Segoe UI",system-ui,-apple-system,sans-serif;
  background:var(--bg); color:var(--ink);
  min-height:100vh; min-height:100dvh;
  -webkit-font-smoothing:antialiased;
}
button { font-family:inherit; border:none; background:none; color:inherit; cursor:pointer; }
input,select { font-family:inherit; font-size:1rem; }
:root {
  --ui-scale:1;                 /* 屏幕自适应比例，由 js/fit.js 按屏幕宽度写入：
                                   5寸手机(360px)→1.00 · 常见手机(390~430)→1.00~1.05
                                   电脑端锁在正常阅读尺度：1920→1.25 · 2560→1.27 · 3440→1.29
                                   （电脑端不再靠放大来利用屏幕，改由左侧导航 + 多列布局） */
  /* 内容区最大宽度，同样由 js/fit.js 写入（= max(32.5rem, 屏宽×0.82)）：
     手机/窄屏 → 32.5rem（与旧的写死值一致，手机端零变化）
     ≥1280px   → 屏宽 82% 接管，1920→1574px、2560→2099px，宽屏不再是中间一条窄缝。
     JS 未执行时兜底 32.5rem，与改动前完全一致。 */
  --ui-max:32.5rem;
  /* 桌面端左侧导航栏宽度（仅 wide / desk 档使用；手机端底栏不用它） */
  --side-w:11.5rem;
  --radius:1rem; --radius-s:0.625rem;
  /* 纸感：阴影极克制，靠 1px 描边与底色分层建立层次 */
  --shadow:0 1px 2px rgba(40,42,60,.04);
  --shadow-lift:0 4px 14px rgba(40,42,60,.10);
  --tabbar-h:3.875rem; --topbar-h:3.375rem;
  --pad:1rem;
}
/* 主题 · 纸感教材风
   设计取舍（去 AI 味四原则）：
   ① 主色整体降饱和、压深，避免"正色样板间"感；
   ② --bg 与 --card 明度差拉开，卡片近白带底色，不再死白压彩底；
   ③ --line 承担分层职责，阴影降到几乎不可见；
   ④ --brand-soft 兼作整页极淡底纹层，形成"纸张"呼吸感。
   --brand-rgb 供 rgba() 阴影/光圈复用；--gold-* 为金色系五档。 */
body.theme-indigo { --bg:#eef0f7; --card:#fdfdff; --ink:#20233a; --sub:#6e7391; --line:#dcdff0;
  --brand:#4b4f96; --brand2:#6f74b8; --brand-rgb:75,79,150; --brand-soft:#e8e9f6;
  --brand-line:#cdd0ea; --brand-glow:rgba(75,79,150,.30);
  --ok:#3f8a5c; --ok-soft:#e6f1e9; --warn:#b5822f; --warn-soft:#f6efe0; --warn-line:#e2d0ac;
  --bad:#b2483f; --bad-soft:#f6e8e6; --bad-line:#e0c3bf;
  --gold:#c8922f; --gold-soft:#f6eeda; --gold-line:#e3d2a8; --gold-ink:#8a6420; --gold-shine:#fdfaf1; }
body.theme-orange { --bg:#f8f1e9; --card:#fffdfa; --ink:#38291d; --sub:#8d7362; --line:#eadfd2;
  --brand:#b95b1f; --brand2:#d4863f; --brand-rgb:185,91,31; --brand-soft:#f7e8dc;
  --brand-line:#e0c4ae; --brand-glow:rgba(185,91,31,.30);
  --ok:#3f8a5c; --ok-soft:#e6f1e9; --warn:#b5822f; --warn-soft:#f6efe0; --warn-line:#e2d0ac;
  --bad:#b2483f; --bad-soft:#f6e8e6; --bad-line:#e0c3bf;
  --gold:#c8922f; --gold-soft:#f7ebd6; --gold-line:#e4cda4; --gold-ink:#8d5c18; --gold-shine:#fdfaf1; }
body.theme-green { --bg:#eaf2ec; --card:#fcfefd; --ink:#1f2c23; --sub:#6e8676; --line:#d8e6dd;
  --brand:#2f7a58; --brand2:#57a37e; --brand-rgb:47,122,88; --brand-soft:#e0efe7;
  --brand-line:#bcd8c8; --brand-glow:rgba(47,122,88,.28);
  --ok:#3f8a5c; --ok-soft:#e6f1e9; --warn:#b5822f; --warn-soft:#f6efe0; --warn-line:#e2d0ac;
  --bad:#b2483f; --bad-soft:#f6e8e6; --bad-line:#e0c3bf;
  --gold:#bb8d2c; --gold-soft:#f5edda; --gold-line:#e0d0a6; --gold-ink:#7e6220; --gold-shine:#fcfaf2; }
body.theme-pink { --bg:#f8eef2; --card:#fffdfe; --ink:#37232c; --sub:#967083; --line:#eedde5;
  --brand:#b0436c; --brand2:#cd7191; --brand-rgb:176,67,108; --brand-soft:#f8e2eb;
  --brand-line:#e3c0d0; --brand-glow:rgba(176,67,108,.28);
  --ok:#3f8a5c; --ok-soft:#e6f1e9; --warn:#b5822f; --warn-soft:#f6efe0; --warn-line:#e2d0ac;
  --bad:#b2483f; --bad-soft:#f6e8e6; --bad-line:#e0c3bf;
  --gold:#c08b33; --gold-soft:#f6ecd8; --gold-line:#e2cfa6; --gold-ink:#8a5c22; --gold-shine:#fdfaf4; }
body.theme-ocean { --bg:#e9f1f7; --card:#fbfdff; --ink:#1c2b38; --sub:#68808f; --line:#d5e3ee;
  --brand:#1f5f8b; --brand2:#4a8dbb; --brand-rgb:31,95,139; --brand-soft:#e0edf6;
  --brand-line:#bcd7e8; --brand-glow:rgba(31,95,139,.28);
  --ok:#3f8a5c; --ok-soft:#e6f1e9; --warn:#b5822f; --warn-soft:#f6efe0; --warn-line:#e2d0ac;
  --bad:#b2483f; --bad-soft:#f6e8e6; --bad-line:#e0c3bf;
  --gold:#c8922f; --gold-soft:#f6eeda; --gold-line:#e3d2a8; --gold-ink:#8a6420; --gold-shine:#fdfaf1; }
/* 深夜模式：唯一一套深底主题。底色/卡片都压暗，正文色提到浅色；
   --shadow 单独调深（浅色阴影在深底上等于没有）；--brand-soft 兼作整页底纹，必须跟着暗下来。 */
body.theme-dark { --bg:#161a2b; --card:#1e2338; --ink:#e8eaf6; --sub:#98a1c2; --line:#2c3350;
  --brand:#7b83d6; --brand2:#9aa1e8; --brand-rgb:123,131,214; --brand-soft:#252b45;
  --brand-line:#3a4166; --brand-glow:rgba(123,131,214,.34);
  --ok:#6fc48f; --ok-soft:#1e2f27; --warn:#dfae5c; --warn-soft:#2e2a1e; --warn-line:#4a4128;
  --bad:#e88176; --bad-soft:#31211f; --bad-line:#4e2f2b;
  --gold:#ddb160; --gold-soft:#2f2a1c; --gold-line:#4b4025; --gold-ink:#e3c07a; --gold-shine:#2a2517;
  --shadow:0 1px 3px rgba(0,0,0,.45); --shadow-lift:0 4px 14px rgba(0,0,0,.5);
  /* hero 卡渐变单独给一套深紫：--brand 在深色主题下必须够亮（当文字/图标色用），
     直接拿它当大面积背景会变成一块刺眼的浅紫。 */
  --hero-a:#3f4670; --hero-b:#5a6299;
  /* 代码着色：深底上用亮一档的颜色，保证对比度够（浅底的默认值在这里全不适用） */
  --code-kw:#c9a8f0; --code-str:#8fd9ae; --code-com:#7d86a8; --code-num:#f0a878; --code-fn:#8fc4f0; }

/* ============ 布局 ============ */
#app { max-width:var(--ui-max); margin:0 auto; min-height:100vh; min-height:100dvh; display:flex; flex-direction:column; position:relative; }

/* 启动加载占位（脚本就绪后 UI.render 首次执行会自动清除） */
#boot-splash { display:flex; flex-direction:column; align-items:center; justify-content:center; gap:0.875rem; min-height:62vh; animation:bsFade .25s ease; }
#boot-splash .bs-logo { font-size:3.5rem; line-height:1; animation:bsBounce 1.2s ease-in-out infinite; }
#boot-splash .bs-name { font-size:1.125rem; font-weight:800; color:var(--brand); letter-spacing:0.125rem; }
#boot-splash .bs-bar { width:7.5rem; height:0.375rem; border-radius:6.1875rem; background:var(--brand-soft); overflow:hidden; }
#boot-splash .bs-bar i { display:block; height:100%; width:40%; border-radius:6.1875rem; background:var(--brand); animation:bsSlide 1s ease-in-out infinite; }
@keyframes bsBounce { 0%,100% { transform:translateY(0); } 50% { transform:translateY(-0.5rem); } }
@keyframes bsSlide { 0% { transform:translateX(-110%); } 100% { transform:translateX(320%); } }
@keyframes bsFade { from { opacity:0; } to { opacity:1; } }
/* ★ 「自救提示」：只在启动页停留超过 7 秒后才浮现（纯 CSS，不需要 JS）。
   正常打开时启动页 1 秒内就被 UI.render() 清掉，永远看不到这段；
   若脚本被浏览器禁掉 / 文件在微信里被拦，这段就是用户唯一能看到的可操作指引。
   注意：动画被全局禁用时（像素回归会注入 animation:none）它会保持 opacity:0，不会误入截图。 */
#boot-splash .bs-hint { opacity:0; animation:bsHint .5s ease 7s forwards; max-width:21rem; margin-top:1.5rem;
  padding:0.875rem 1rem; border:1px solid var(--line); border-radius:0.875rem; background:var(--card);
  font-size:.78rem; line-height:1.8; color:var(--sub); text-align:left; }
#boot-splash .bs-hint b { display:block; font-size:.86rem; color:var(--ink); margin-bottom:0.375rem; }
#boot-splash .bs-hint .bs-href { display:inline-block; margin-top:0.3125rem; font-weight:800; color:var(--brand); word-break:break-all; }
@keyframes bsHint { to { opacity:1; } }
@media(min-width:640px){ #app { box-shadow:0 0 0 1px var(--line),0 20px 60px rgba(30,35,90,.12); } }
/* 顶栏：与页面底色同色，仅用 1px 发丝线分隔，去掉"白条顶栏"的生成式 UI 结构 */
#topbar {
  position:sticky; top:0; z-index:50; height:var(--topbar-h);
  display:flex; align-items:center; justify-content:space-between;
  padding:0 var(--pad); background:var(--bg); border-bottom:1px solid var(--line);
}
.brand { font-weight:800; font-size:1.05rem; color:var(--brand); letter-spacing:0.03125rem; }
.topchips { display:flex; align-items:center; gap:0.5rem; }
.chip { font-size:.78rem; font-weight:700; padding:0.25rem 0.5rem; border-radius:0.25rem; background:var(--bg); border:1px solid var(--line); }
.chip-fire { color:var(--warn); background:var(--warn-soft); border-color:var(--warn-line); }
.chip-coin { color:var(--gold-ink); background:var(--gold-soft); border-color:var(--gold-line); }
.chip.bump { animation:bump .5s ease; }
@keyframes bump { 0%{transform:scale(1)} 40%{transform:scale(1.25)} 100%{transform:scale(1)} }
.avatar { width:2.125rem; height:2.125rem; border-radius:50%; background:var(--brand-soft); font-size:1.05rem; display:flex; align-items:center; justify-content:center; }

/* 侧栏导航按钮（v121，★ v126 改为全档位显示）：积分商店 / 设置。
   ★★ v126：这两个按钮**不能再隐藏**了 —— 用户要求「我的」页里不要有
     积分商城 / 设置，于是手机上只剩顶栏这一条路能进去，藏起来等于把功能锁死。
     顶栏挤不下时让 .brand 收缩（见下面的 #topbar .brand），按钮自己不动。
   ⚠ 手机档收窄到 1.75rem（28px）的方钮，桌面档则跟 #btn-me 长成同一族：
     撑满侧栏、同一圆角、同一底色。
   ⚠ 老内核规矩：先写 display:block 兜底，再写 display:flex。 */
.snav {
  display:block; display:flex; align-items:center; justify-content:center;
  flex:none; width:1.75rem; height:1.75rem; border-radius:0.5rem;
  border:0; padding:0; background:var(--brand-soft); color:var(--brand);
  cursor:pointer; line-height:0;
}
html[data-lay="wide"] .topchips .snav,
html[data-lay="desk"] .topchips .snav {
  width:100%; height:2.25rem; border-radius:0.6875rem;
}
.snav svg { width:1rem; height:1rem; }
html[data-lay="wide"] .topchips .snav svg,
html[data-lay="desk"] .topchips .snav svg { width:1.0625rem; height:1.0625rem; }
.snav:active { opacity:.72; }
/* ⚠★ 顶栏挤不下时**先牺牲品牌名**，不要牺牲按钮 ——
   #brand（当前学科名，点它可换学科）在窄屏上收缩成省略号，
   再窄就整个让位。这样顶栏永远只占一行，_qin 的"不横向溢出"才守得住。 */
#topbar .brand { min-width:0; overflow:hidden; white-space:nowrap; text-overflow:ellipsis; }
.topchips { min-width:0; }

/* ★★ v126：顶栏多了两个侧栏按钮 → 240px 的极窄屏（多亲 Qin3 那类）横向溢出 23px
   （`_qin` 实测：`#btn-me` 被挤到 17px、顶栏 scrollWidth 263 > 240）。
   这里靠**瘦身**解决，不是靠隐藏：间距 0.5→0.25rem、chip 左右内边距 0.5→0.375rem、
   .snav 1.75→1.5rem、顶栏左右内边距 1→0.625rem；同时给 .avatar 加 flex:none ——
   否则它会被压成 17px 的扁圆，比溢出还难看。
   ⚠⚠ 绝不能改成 display:none：用户 v126 已经删掉「我的」页里的入口行，
      窄档一藏就等于手机上根本进不去积分商店 / 设置。
   ⚠ 这些值都会被 wide/desk 的规则覆盖（它们各自写了 gap / padding / width:100%），
      所以桌面侧栏不受影响。 */
.topchips { gap:0.1875rem; }
.chip { padding:0.25rem 0.375rem; }
.snav { width:1.5rem; height:1.5rem; }
.avatar { flex:none; }
#topbar { padding:0 0.5rem; }

/* 注意：下面的 padding-bottom / height 都先写一条「不含 env() 的兜底」再写含 env() 的版本。
   老内核（Android WebView 68 及以前）不认识 env()，会把整条声明判为无效丢弃 ——
   若只写 env() 版本，底栏高度会直接塌成 0、内容也会被底栏压住，这正是「手机上显示不对」的典型成因。 */
#view { flex:1; padding:var(--pad); padding-bottom:calc(var(--tabbar-h) + 1.375rem); padding-bottom:calc(var(--tabbar-h) + env(safe-area-inset-bottom,0px) + 1.375rem); }
#tabbar {
  position:fixed; bottom:0; left:50%; transform:translateX(-50%); width:100%; max-width:var(--ui-max); z-index:60;
  /* 同上：先兜底后 env()，避免不认 env() 的内核把高度声明整条丢掉、底栏塌陷 */
  height:var(--tabbar-h);
  height:calc(var(--tabbar-h) + env(safe-area-inset-bottom,0px));
  padding-bottom:0;
  padding-bottom:env(safe-area-inset-bottom,0);
  display:flex; background:var(--bg); border-top:1px solid var(--line);
}
.tab { flex:1; display:flex; flex-direction:column; align-items:center; justify-content:center; gap:0.125rem; font-size:.7rem; color:var(--sub); font-weight:600; }
.tab .t-ico { font-size:1.35rem; line-height:1; filter:grayscale(.4); transition:.2s; }
.tab.active { color:var(--brand); }
.tab.active .t-ico { filter:none; transform:translateY(-0.125rem) scale(1.12); }

/* ============ 通用组件 ============ */
.card { background:var(--card); border-radius:var(--radius); box-shadow:var(--shadow); border:1px solid var(--line); padding:1rem; margin-bottom:0.875rem; }
.card-title { font-size:1rem; font-weight:800; display:flex; align-items:center; gap:0.5rem; margin-bottom:0.625rem; }
.card-title .more { margin-left:auto; font-size:.75rem; color:var(--brand); font-weight:600; }
/* ★ v85 卡片标题：文字块 + 右侧标签。
   旧版「今日必做任务<span class="badge">未完成将受罚</span>」是一个 flex 容器直接装
   文本节点 + inline-block 标签 —— 文本节点会当成匿名 flex item 参与分配，窄屏被挤成
   「今日必做任 / 务」两行，标签自己也被压成两行「未完成将受 / 罚」。实测标题高 42px、
   标签高 36px 都是两行。改成：给标题文字包一层 .ct-t（min-width:0 可缩、nowrap 不折行），
   标签 flex:none 且 nowrap —— 挤不下时让标题出省略号，而不是把两个字拆到两行。 */
.card-title .ct-t { flex:1 1 auto; min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.card-title > .badge { flex:none; margin-left:0; white-space:nowrap; }
/* 手机档再让一步：图标与标签都收一点，务必给标题留出整句宽度 */
html[data-lay="narrow"] .card-title { font-size:0.94rem; gap:0.375rem; }
html[data-lay="narrow"] .card-title .ct-t { overflow:visible; text-overflow:clip; }
.sub { color:var(--sub); font-size:.82rem; line-height:1.55; }
.btn {
  display:inline-flex; align-items:center; justify-content:center; gap:0.375rem;
  padding:0.75rem 1.125rem; border-radius:0.875rem; font-size:.95rem; font-weight:700;
  background:var(--brand); color:#fff; transition:.15s; user-select:none;
  box-shadow:0 1px 2px rgba(var(--brand-rgb),.22);
}
.btn:active { transform:scale(.96); }
.btn.ghost { background:var(--brand-soft); color:var(--brand); box-shadow:none; }
.btn.gray { background:var(--bg); color:var(--sub); box-shadow:none; }
.btn.warn { background:var(--bad); box-shadow:0 1px 2px rgba(178,72,63,.22); }
.btn.gold { background:var(--gold); box-shadow:0 1px 2px rgba(200,146,47,.24); }
.btn.big { width:100%; padding:0.9375rem; font-size:1.05rem; }
.btn.sm { padding:0.4375rem 0.75rem; font-size:.8rem; border-radius:0.625rem; }
/* 「下载离线版」用的是 <a class="btn">（必须带 download 属性才能真的保存文件，
   直接跳转 .html 只会被渲染成页面）—— 把链接默认的下划线去掉 */
a.btn { text-decoration:none; }
.btn:disabled { opacity:.45; pointer-events:none; }
.row { display:flex; gap:0.625rem; align-items:center; }
.row.wrap { flex-wrap:wrap; }
.grid2 { display:grid; grid-template-columns:1fr 1fr; gap:0.625rem; }
.grid3 { display:grid; grid-template-columns:1fr 1fr 1fr; gap:0.625rem; }
.mt8{margin-top:0.5rem}.mt12{margin-top:0.75rem}.mt16{margin-top:1rem}.mb8{margin-bottom:0.5rem}

/* 页头（子页返回） */
.pagehead { display:flex; align-items:center; gap:0.625rem; margin-bottom:0.875rem; }
.pagehead .back { width:2.25rem; height:2.25rem; border-radius:0.75rem; background:var(--card); box-shadow:var(--shadow); border:1px solid var(--line); font-size:1.1rem; display:flex; align-items:center; justify-content:center; }
.pagehead h2 { font-size:1.1rem; font-weight:800; flex:1; }
.pagehead .right { font-size:.8rem; color:var(--sub); font-weight:700; }

/* 进度条与环 */
.pbar { height:0.625rem; background:var(--bg); border-radius:62.4375rem; overflow:hidden; }
/* 0% 的进度槽纯属空占位（旁边数字已经写着 0%），整条隐掉 */
.pbar.zero { display:none; }
/* ★★ v85 修一个隐蔽 bug：上面这条 `.pbar.zero`（0,2,0）压不过桌面档那几条
   `html[data-lay="desk"] #view > .card > .pbar`（1,2,1）的 `margin/max-width !important`，
   于是桌面上 0% 的空槽照样显示出来 —— 手机档看不出问题，只有宽屏才露馅，
   正好是最容易漏测的一档。补一条同权重、更靠后的规则把它关掉。 */
html #view > .card > .pbar.zero,
html #view > .card > .hero-card > .pbar.zero,
html #view > .hero-card > .pbar.zero { display:none !important; }
/* 去 AI 味：进度条不再用「主色→辅色」横向渐变（模板感最强的元素之一），改纯主色实心。 */
.pbar > i { display:block; height:100%; background:var(--brand); border-radius:62.4375rem; transition:width .4s ease; }
.ring { --p:0; --sz:4.625rem; width:var(--sz); height:var(--sz); border-radius:50%;
  background:conic-gradient(var(--brand) calc(var(--p)*1%), var(--bg) 0);
  display:flex; align-items:center; justify-content:center; flex:none; }
.ring::after { content:""; position:absolute; width:calc(var(--sz) - 1.125rem); height:calc(var(--sz) - 1.125rem); border-radius:50%; background:var(--card); }
.ring { position:relative; }
.ring b { position:relative; z-index:1; font-size:.95rem; }
/* ★ v85 环里显示分母：1/5 里的「/5」比「1」小一号、颜色 --sub。
   旧版整串同号同色，只能读成「1斜杠5」；分开后一眼就是「五件里做完一件」。
   ★ 用 span 包、不引新 class 语义冲突：只在这枚环里生效。 */
.ring b small { font-size:.72rem; font-weight:700; color:var(--sub); }

/* 学科切换条 */
.subj-pill { flex:1; display:flex; flex-direction:column; align-items:center; gap:0.125rem; font-size:1.15rem; padding:0.5rem 0.125rem 0.375rem; border-radius:0.75rem; background:var(--bg); border:2px solid transparent; color:var(--ink); }
.subj-pill div { font-size:.68rem; font-weight:700; }
.subj-pill.on { border-color:var(--brand); background:var(--brand-soft); color:var(--brand); }

/* 任务列表 */
.task { display:flex; align-items:center; gap:0.625rem; padding:0.625rem 0; border-bottom:1px dashed var(--line); }
.task:last-child { border-bottom:none; }
.task .tk-ico { width:1.75rem; height:1.75rem; display:flex; align-items:center; justify-content:center; color:var(--brand); font-size:1.15rem; flex:none; }
.task .tk-body { flex:1; min-width:0; }
.task .tk-name { font-size:.88rem; font-weight:700; }
.task .tk-prog { font-size:.72rem; color:var(--sub); margin-top:0.125rem; }
.task .tk-done { color:var(--ok); font-weight:800; font-size:.85rem; flex:none; }
.task .tk-goto { flex:none; font-size:.75rem; color:var(--brand); font-weight:700; background:var(--brand-soft); padding:0.3125rem 0.5625rem; border-radius:0.375rem; }

/* ---------- 「今日必做任务」任务卡片（.taskgrid / .ttile）★ 2026-10-13 第六轮 ----------
   旧版用的是 .task 长条行：名字在左、按钮在右，两端对齐。窄屏没问题，
   但宽屏下每列被拉到 300~500px，中间一大片空；5 条任务在第 2 行只剩 1 条、后 3 格全空。
   新版每条是一张小卡：图标 + 名称 / 进度条 / 数字 + 操作，按 11.5rem 自适应列数。
   ★ 用 auto-fit 而不是 auto-fill —— auto-fill 会先铺满空轨道，5 条任务右边会多出一个空位；
     auto-fit 让已有卡片直接撑满整行（1920 下 5 列正好一行排完）。 */
.taskgrid { display:grid; grid-template-columns:repeat(auto-fit,minmax(11.5rem,1fr)); gap:0.5rem; margin-top:0.75rem; }
/* 去 AI 味（卡片套卡片）：旧版每条任务是在外层白卡里再套一张有底、有框、有圆角的小卡，
   两层容器都带背景=模板感。现改成「描边条目」：不留底色，只留一圈细边，层次交给外层卡片。 */
.ttile {
  display:grid; gap:0.375rem 0.5rem;
  padding:0.625rem 0.6875rem; border-radius:0.5rem;
  background:none; border:1px solid var(--line);
}
/* 手机档：单行 —— 图标 / 名称(占满剩余) / 数字 / 操作。见下方 narrow 的 grid-template-areas。
   ★ v85：原写法「ico name act / ico bar num」在 360px 下把 5 条任务的行高拉到 74px，
     一屏只放得下 3.5 条（首屏看不到「做真题」后面的任务，很容易以为只有 4 个任务）。
     去掉 progress 轨道那一行后行高降到 ~50px，5 条任务一屏排完。 */
.ttile { grid-template-columns:auto 1fr auto; grid-template-areas:"ico name act" "ico bar num"; }
/* 图标不再坐一块浅色底方块（二十来个色块排下来就是「彩色贴纸墙」）；
   直接一根主色描边图标，跟卡片标题的图标同一套语言。 */
.tt-ico { grid-area:ico; align-self:center; width:1.75rem; height:1.75rem;
  display:flex; align-items:center; justify-content:center; color:var(--brand); font-size:0.95rem; }
.tt-name { grid-area:name; font-size:0.84rem; font-weight:700; min-width:0; align-self:center; }
.tt-bar { grid-area:bar; align-self:center; height:0.25rem; border-radius:62.4375rem; background:var(--line); overflow:hidden; }
/* 进度为 0：整条隐掉（保留占位不影响网格），避免满屏空槽像没填完的模板 */
.tt-bar.zero { visibility:hidden; }
.tt-bar i { display:block; height:100%; border-radius:inherit; background:var(--brand); }
.tt-num { grid-area:num; align-self:center; justify-self:end; font-size:0.7rem; color:var(--sub); font-weight:600; white-space:nowrap; }
.tt-num b { font-size:0.8rem; color:var(--ink); }
.tt-state { grid-area:act; align-self:center; justify-self:end; }
.tt-act { font-size:0.72rem; font-weight:700; color:var(--brand); background:var(--brand-soft);
  border:none; padding:0.25rem 0.5rem; border-radius:0.375rem; white-space:nowrap; }
.tt-done { font-size:0.72rem; font-weight:800; color:var(--ok); white-space:nowrap; }
/* ★ v85 黑夜主题下 --ok(#6fc48f) 配 0.72rem 小字实在太细（截图确认「已完成」几乎糊成一团绿），
   深底上要加字号/字重才够读。只对 dark 生效，白天档不动。 */
body.theme-dark .tt-done { font-size:0.76rem; font-weight:900; }
body.theme-dark .tt-num { color:#aeb6d4; }
body.theme-dark .tt-num b { color:#f0f2fb; }
/* 完成态：不再把整条铺成绿底（一块块绿色最像「自动生成的看板」），
   只让描边转绿、对勾转绿，信息一样清楚但安静得多。 */
.ttile.done { border-color:var(--ok); }
.ttile.done .tt-bar i { background:var(--ok); }
.ttile.done .tt-name { color:var(--sub); }
/* 平板及以上：宽松三行 —— 名称独占一行不被按钮挤，进度条通栏更醒目 */
/* 手机档：5 条任务不再各自成一张描边小盒（盒套盒），
   拆成一条条平铺行、行间一根细线 —— 像课本的目录页，信息密度更高也更安静。 */
html[data-lay="narrow"] .taskgrid { gap:0; }
html[data-lay="narrow"] .ttile { border:none; border-bottom:1px solid var(--line); border-radius:0; padding:0.6875rem 0.125rem;
  grid-template-columns:auto 1fr auto auto; grid-template-areas:"ico name num act"; align-items:center; gap:0.5rem; }
html[data-lay="narrow"] .tt-bar { display:none; }   /* 单行布局用数字表达进度，条不要了 */
html[data-lay="narrow"] .ttile:last-child { border-bottom:none; }
/* ★ v85 任务卡底部的后果提示：一整行、极小、--warn 色 + 上边细线。
   不进标题行（标题行只有 200px 可分配，塞不下）、不占 badge（badge 只表达状态）。 */
.task-warn { margin-top:0.625rem; padding-top:0.5rem; border-top:1px solid var(--line);
  font-size:0.7rem; line-height:1.5; color:var(--warn); display:flex; align-items:flex-start; gap:0.3125rem; }
.task-warn .ico { flex:none; margin-top:0.15rem; }
/* 深底上 0.7rem 的 --warn(#dfae5c) 与卡片底(#1e2338) 对比度偏低 → 补一层浅底承托 */
body.theme-dark .task-warn { background:var(--warn-soft); border-top-color:transparent;
  border-radius:0.375rem; padding:0.4375rem 0.5rem; margin-top:0.5rem; }

html:not([data-lay="narrow"]) .ttile {
  grid-template-columns:auto 1fr; grid-template-areas:"ico name" "bar bar" "num act";
  padding:0.6875rem 0.75rem;
}
html:not([data-lay="narrow"]) .tt-ico { align-self:start; }
html:not([data-lay="narrow"]) .tt-bar { grid-column:1 / -1; }

/* 宽屏（内容区被 --ui-max 撑宽后）行内留白优化：
   手机上内容区 = 屏宽，行内元素本来就贴边，无需处理；
   电脑上内容区远宽于内容，任务行的名字和右侧按钮之间会空出一大段。
   这里只是把行内两端对齐撑开、并给行一点垂直呼吸，不改变任何字号与比例 ——
   所以手机端（内容区=屏宽）不受影响，视觉与改动前完全一致。 */
@media(min-width:1024px){
  .task { padding:0.75rem 0; }
  .task .tk-body { padding-right:1rem; }
}

/* 「去完成」跳转后的目标定位：一次性高亮环 + 指引气泡 */
.anchor-hit { position:relative; z-index:5; animation:anchorRing 2.6s ease-out; }
@keyframes anchorRing {
  0%   { box-shadow:0 0 0 0 rgba(var(--brand-rgb),.55); }
  40%  { box-shadow:0 0 0 6px rgba(var(--brand-rgb),.28); }
  100% { box-shadow:0 0 0 0 rgba(var(--brand-rgb),0); }
}
.anchor-hit { border-color:var(--brand) !important; }
.anchor-tip {
  position:fixed; right:1rem; z-index:320; pointer-events:none;
  background:var(--brand); color:#fff; font-size:.74rem; font-weight:700;
  padding:0.375rem 0.75rem; border-radius:62.4375rem; box-shadow:var(--shadow-lift);
  animation:tipIn .28s ease;
}
@keyframes tipIn { from { opacity:0; transform:translateY(-0.375rem); } to { opacity:1; transform:none; } }
@keyframes tipIn { from { opacity:0; transform:translateY(-0.375rem); } to { opacity:1; transform:none; } }

/* 主卡（首页问候 / 冲刺页当前阶段 / 我的页名片）
   ★★ 去 AI 味重灾区：旧版是「主色→辅色 150deg 渐变铺满整块 + 反白字 + 右上角一个半透明白圆」，
      这套组合是生成式 UI 的招牌，一眼假。
   现改成纸感：纸白底 + 左侧 3px 主色竖条（课本页边的章节色标），文字回到正文色；
   整卡只留「距高考」KPI 一块主色浅底做唯一强调点，其余全部让位给内容。
   ⚠ overflow:hidden 保留（里面可能有宠物条），只是装饰圆不再生成。 */
.hero-card { background:var(--card); color:var(--ink); border:1px solid var(--line); border-left:3px solid var(--brand); position:relative; overflow:hidden; }
/* 老内核兼容：不删 ::after 规则（删了有的内核会解析错），直接关掉 */
.hero-card::after { content:""; display:none; }
.hero-card .hero-kpi { text-align:center; background:var(--brand-soft); color:var(--brand); border-radius:var(--radius-s); padding:0.5rem 0.75rem; flex:none; }
.hero-card .hero-kpi b { font-size:1.15rem; font-weight:800; white-space:nowrap; }
.hero-card .hero-kpi span { font-size:.68rem; opacity:.85; white-space:nowrap; display:block; }
/* 纸感化后副标题不再压在深色底上，回到常规灰字（旧版这里写的是半透明白，会看不见） */
.hero-card .sub { color:var(--sub); }
.hero-sub { font-size:.82rem; color:var(--sub); line-height:1.6; }
/* ★ v85 「我的」头像卡里的三条数据带。
   旧版是一行流水句「累计获得 x 分 · 连续打卡最佳 y 天 · 学习 z 天」，三个信息挤成一句、
   数字和单位混在一起；下一行「英语段位 · 再赚 300 分晋升「单词学徒」📖」还带个 emoji 收尾，
   读起来像模板自动拼的。现在：三条等宽格（数字 0.95rem/800 + 标签 .66rem/--sub），
   用 1px 竖线分隔（沿用 .stat 的做法），晋升进度单独一行、图标换成描边皇冠。 */
.hero-facts { display:flex; align-items:center; justify-content:center; margin-top:0.75rem; }
.hero-facts .hf { flex:1 1 0; min-width:0; position:relative; padding:0.125rem 0; }
.hero-facts .hf + .hf::before { content:""; position:absolute; left:0; top:18%; bottom:18%; width:1px; background:var(--line); }
.hero-facts .hf b { display:block; font-size:0.95rem; font-weight:800; color:var(--ink); line-height:1.25; }
.hero-facts .hf span { display:block; font-size:0.66rem; color:var(--sub); margin-top:0.0625rem; }
.hero-next { margin-top:0.625rem; font-size:0.76rem; color:var(--sub); }
.hero-next b { color:var(--brand); font-weight:800; }
.hero-next .ico { vertical-align:-2px; color:var(--brand); }

/* 横幅 */
.banner { border-radius:var(--radius-s); padding:0.6875rem 0.8125rem; font-size:.83rem; font-weight:600; display:flex; gap:0.5rem; align-items:center; margin-bottom:0.75rem; line-height:1.45; }
.banner.bad { background:var(--bad-soft); color:var(--bad); border:1px solid var(--bad-line); }
.banner.warn { background:var(--warn-soft); color:var(--warn); border:1px solid var(--warn-line); }
.banner.ok { background:var(--ok-soft); color:var(--ok); border:1px solid var(--ok-soft); }
.banner.info { background:var(--brand-soft); color:var(--brand); border:1px solid var(--brand-line); }
.banner .b-btn { margin-left:auto; flex:none; background:var(--bad); color:#fff; border-radius:0.375rem; padding:0.375rem 0.6875rem; font-size:.75rem; font-weight:700; }
.banner.info .b-btn,.banner.ok .b-btn { background:var(--brand); }
/* ★ v116 待领取成就横幅：金色（对应成就墙的金色），按钮也用金 ——
   一眼就能和"出事了"的红/黄横幅区分开。 */
.banner.gold { background:var(--gold-soft); color:var(--gold-ink); border:1px solid var(--gold-line); }
.banner.gold .b-btn { background:var(--gold); color:#fff; }

/* 快捷入口 */
/* 6 个入口：旧版用 4 列 → 第一行 4 个、第二行 2 个，右下角永远缺一块（最像自动排版）。
   改成手机 3 列（2×3 刚好填满）、宽屏一行 6 个（工具栏式）。 */
.quick { display:grid; grid-template-columns:repeat(3,1fr); gap:0.5rem; }
html[data-lay="wide"] .quick, html[data-lay="desk"] .quick { grid-template-columns:repeat(6,1fr); }
/* 快捷入口：白卡 + 描边 + 阴影一层套一层，六格排下来像电商首页的图标宫格。
   改成无边框的通栏宫格，只留极淡底色做点击区，视觉上退到内容后面。 */
.quick button { display:flex; flex-direction:column; align-items:center; gap:0.3125rem; padding:0.75rem 0.125rem;
  background:var(--bg); border-radius:0.5rem; border:none; box-shadow:none; font-size:.7rem; font-weight:700; color:var(--ink); }
.quick button:active { background:var(--brand-soft); }
.quick .q-ico { font-size:1.45rem; }

/* ============ 升学地图 ============ */
.lvpath { position:relative; padding:0.375rem 0.25rem 0.375rem; }
.lvnode { position:relative; display:flex; gap:0.8125rem; align-items:center; padding:0.5625rem 0; }
.lvnode::before { content:""; position:absolute; left:1.9375rem; top:0; bottom:0; width:0.1875rem; background:var(--line); }
.lvnode:first-child::before { top:50%; }
.lvnode:last-child::before { bottom:50%; }
.lvnode.passed::before { background:var(--brand); }
.lvball { width:3.75rem; height:3.75rem; border-radius:50%; flex:none; z-index:1; display:flex; align-items:center; justify-content:center; font-size:1.6rem;
  background:var(--card); border:3px solid var(--line); box-shadow:var(--shadow); position:relative; }
.lvnode.current .lvball { border-color:var(--brand); animation:pulse 1.8s infinite; }
@keyframes pulse { 0%,100%{box-shadow:0 0 0 0 var(--brand-glow)} 50%{box-shadow:0 0 0 10px rgba(var(--brand-rgb),0)} }
.lvnode.locked .lvball { filter:grayscale(1); opacity:.55; }
.lvnode .lvbody { flex:1; background:var(--card); border-radius:0.875rem; box-shadow:var(--shadow); padding:0.6875rem 0.8125rem; }
.lvnode .lvname { font-weight:800; font-size:.92rem; display:flex; align-items:center; gap:0.375rem; }
.lvnode .lvdesc { font-size:.75rem; color:var(--sub); margin-top:0.1875rem; line-height:1.4; }
.lvstars { font-size:.78rem; color:var(--gold); letter-spacing:0.0625rem; margin-left:auto; flex:none; }
.lvlock { font-size:.7rem; color:var(--sub); margin-left:auto; flex:none; }
.pass-tag { font-size:.62rem; background:var(--ok-soft); color:var(--ok); padding:0.125rem 0.375rem; border-radius:0.25rem; font-weight:700; flex:none; }

/* ---------- 升学地图：宽屏改「关卡卡网格」★ 2026-10-13 第六轮 ----------
   手机/平板保持原竖向关卡路径（圆形关卡球 + 连接竖线）。
   但桌面端内容区有 1600px 宽，一条关卡被拉成整行，左侧一个小球、右边两行字，
   右侧整片留白 —— 比手机还难看。宽屏改成关卡卡网格：卡内横排「图标 + 名称/描述/星数」，
   竖线连接（::before）隐藏，按 24rem 自适应列数（1920 → 3 列 · 1280 → 2 列）。 */
html[data-lay="wide"] .lvpath,
html[data-lay="desk"] .lvpath {
  display:grid; grid-template-columns:repeat(auto-fit,minmax(24rem,1fr));
  gap:0.75rem; padding:0;
}
html[data-lay="wide"] .lvnode,
html[data-lay="desk"] .lvnode { padding:0; align-items:stretch; gap:0.75rem; }
html[data-lay="wide"] .lvnode::before,
html[data-lay="desk"] .lvnode::before { display:none; }
html[data-lay="wide"] .lvball,
html[data-lay="desk"] .lvball {
  width:3.25rem; height:3.25rem; font-size:1.4rem; border-width:2px;
  align-self:center; box-shadow:none; background:var(--bg);
}
html[data-lay="wide"] .lvbody,
html[data-lay="desk"] .lvbody { display:flex; flex-direction:column; justify-content:center; gap:0.1875rem; }
html[data-lay="wide"] .lvnode .lvdesc,
html[data-lay="desk"] .lvnode .lvdesc { margin-top:0; }
html[data-lay="wide"] .lvstars,
html[data-lay="desk"] .lvstars { margin-left:0; }

/* ============ 测验/练习 ============ */
.qmeta { display:flex; align-items:center; gap:0.5rem; row-gap:0.25rem; flex-wrap:wrap; margin-bottom:0.75rem; }
.qcount { font-size:.8rem; font-weight:800; color:var(--brand); background:var(--brand-soft); padding:0.25rem 0.5625rem; border-radius:0.25rem; }
.qcat { font-size:.75rem; color:var(--sub); font-weight:600; }
.qtext { font-size:1.02rem; font-weight:700; line-height:1.6; margin-bottom:0.875rem; white-space:pre-wrap; }
.passage { background:var(--bg); border-radius:var(--radius-s); padding:0.8125rem; font-size:.9rem; line-height:1.8; margin-bottom:0.8125rem; white-space:pre-wrap; }
.opts { display:flex; flex-direction:column; gap:0.625rem; }
.opt {
  text-align:left; padding:0.8125rem 0.9375rem; border-radius:0.875rem; background:var(--card);
  border:2px solid var(--line); font-size:.93rem; font-weight:600; line-height:1.5; display:flex; gap:0.5rem;
}
.opt:active { transform:scale(.98); }
.opt.sel { border-color:var(--brand); background:var(--brand-soft); }
.opt.right { border-color:var(--ok); background:var(--ok-soft); animation:pop .35s; }
.opt.wrong { border-color:var(--bad); background:var(--bad-soft); animation:shake .4s; }
@keyframes pop { 0%{transform:scale(1)} 45%{transform:scale(1.03)} 100%{transform:scale(1)} }
@keyframes shake { 0%,100%{transform:translateX(0)} 25%{transform:translateX(-5px)} 75%{transform:translateX(5px)} }
.fb { margin-top:0.8125rem; border-radius:var(--radius-s); padding:0.75rem 0.875rem; font-size:.85rem; line-height:1.65; animation:slideup .25s ease; }
.fb.right { background:var(--ok-soft); color:var(--ok); }
.fb.wrong { background:var(--bad-soft); color:var(--bad); }
@keyframes slideup { from{opacity:0; transform:translateY(8px)} to{opacity:1; transform:none} }

/* 听力播放器 */
.lplayer { background:var(--brand-soft); border:1px solid var(--line); border-radius:var(--radius); padding:0.875rem; margin-bottom:0.875rem; }
.lplayer .lp-btns { display:flex; gap:0.5rem; flex-wrap:wrap; }
.lplayer .lp-status { font-size:.75rem; color:var(--sub); margin-top:0.5rem; font-weight:600; }
.lscript { background:var(--bg); border-radius:var(--radius-s); padding:0.75rem; font-size:.9rem; line-height:1.8; margin-top:0.625rem; white-space:pre-wrap; }
.lscript b { color:var(--brand); }

/* 跟读录音 */
.follow { display:flex; gap:0.5rem; align-items:center; flex-wrap:wrap; margin-top:0.625rem; }
.follow .rec-dot { width:0.625rem; height:0.625rem; border-radius:50%; background:var(--bad); animation:blink 1s infinite; }
@keyframes blink { 50%{opacity:.2} }
.follow .rec-tip { font-size:.75rem; color:var(--sub); font-weight:600; }

/* ============ 单词卡 ============ */
.wcard { background:var(--card); border-radius:var(--radius); box-shadow:var(--shadow-lift); padding:1.625rem 1.25rem; text-align:center; position:relative; overflow:hidden; }
.wcard .wword { font-size:2.3rem; font-weight:800; letter-spacing:0.03125rem; }
.wcard .wphon { color:var(--sub); font-size:1rem; margin-top:0.375rem; }
.wcard .wpos { display:inline-block; font-size:.72rem; color:var(--brand); background:var(--brand-soft); border-radius:0.25rem; padding:0.1875rem 0.5rem; margin-top:0.625rem; font-weight:700; }
.wcard .wmean { font-size:1.25rem; font-weight:800; margin-top:0.875rem; }
.wcard .wmem { margin-top:0.75rem; background:var(--warn-soft); color:var(--warn); border-radius:var(--radius-s); padding:0.625rem 0.75rem; font-size:.85rem; line-height:1.6; text-align:left; }
.wcard .wcol { margin-top:0.625rem; font-size:.9rem; line-height:1.7; color:var(--ink); }
.wcard .wex { margin-top:0.5rem; font-size:.9rem; line-height:1.7; color:var(--sub); font-style:italic; }
.wcard .waudio { position:absolute; top:0.75rem; right:0.75rem; width:2.625rem; height:2.625rem; border-radius:50%; background:var(--brand-soft); font-size:1.2rem; display:flex; align-items:center; justify-content:center; }
.wcard .wnum { position:absolute; top:0.875rem; left:0.875rem; font-size:.72rem; color:var(--sub); font-weight:700; }
.grade-row { display:flex; gap:0.625rem; margin-top:1rem; }
.grade-row .btn { flex:1; }
.flip-hint { font-size:.78rem; color:var(--sub); margin-top:0.875rem; }

/* 列表行 */
.lrow { display:flex; align-items:center; gap:0.6875rem; padding:0.8125rem 0.875rem; background:var(--card); border-radius:0.875rem; box-shadow:var(--shadow); border:1px solid var(--line); margin-bottom:0.625rem; }
/* 图标底从「主色浅块」换成「页面底色」：一整列浅紫方块排下来像贴纸墙，
   退成底色之后，彩色的单元 emoji 和单色描边图标都能坐得住。 */
.lrow .lr-ico { width:2.625rem; height:2.625rem; border-radius:0.8125rem; background:var(--bg); display:flex; align-items:center; justify-content:center; font-size:1.25rem; flex:none; }
.lrow .lr-body { flex:1; min-width:0; }
.lrow .lr-t { font-size:.92rem; font-weight:800; }
.lrow .lr-s { font-size:.74rem; color:var(--sub); margin-top:0.125rem; }
.lrow .lr-end { flex:none; color:var(--sub); font-size:1rem; }
.badge { display:inline-block; font-size:.68rem; font-weight:800; padding:0.1875rem 0.4375rem; border-radius:0.25rem; background:var(--brand-soft); color:var(--brand); margin-left:0.375rem; vertical-align:middle; }
.badge.gold { background:var(--gold-soft); color:var(--gold-ink); }
.badge.gray { background:var(--bg); color:var(--sub); }
.badge.red { background:var(--bad-soft); color:var(--bad); }
.badge.green { background:var(--ok-soft); color:var(--ok); }

/* 数学分步详解 */
/* C 语言代码块：等宽字体保证缩进对齐
   ★ 老内核兜底：等宽字体栈写全，最后一定落到通用 monospace；
     `font-variant-ligatures:none` 关掉连字 —— 否则 `!=` 在某些字体下会被连成一个字符，
     看着像写错了。 */
.qtext.code {
  font-family: Consolas, Monaco, "DejaVu Sans Mono", "Courier New", monospace;
  font-size: .92rem;
  line-height: 1.75;
  background: var(--bg);
  padding: 0.75rem 0.875rem;
  border-radius: 0.625rem;
  border-left: 4px solid var(--brand);
  font-variant-ligatures: none;
  /* ★ 窄屏兜底：代码宁可横向滚动，也不能把整张卡片撑破
       （多亲 Qin3 的 CSS 视口只有 360px，一行 60 字符的代码必然溢出）。 */
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
}
/* 选项里的代码片段：只换等宽字体，不套整块背景
   （.opt 是 flex 容器，塞一个带 padding/背景的块会破坏行内对齐）。 */
.opt .mono {
  font-family: Consolas, Monaco, "DejaVu Sans Mono", "Courier New", monospace;
  font-variant-ligatures: none;
  font-size: .88rem;
  letter-spacing: 0;
  white-space: pre-wrap;
  word-break: break-word;
  min-width: 0;
  overflow-x: auto;
}
.steps-detail .mono, .ri-details .mono {
  font-family: Consolas, Monaco, "DejaVu Sans Mono", "Courier New", monospace;
  font-variant-ligatures: none;
  white-space: pre-wrap;
  overflow-x: auto;
}

/* ★ v136 分步讲解里的代码块（C 语言参考代码、改正后的代码）
   ⚠ .steps-detail li 默认没有 white-space，多行代码会被折叠成一段话，
     所以这里必须显式 pre；窄屏宁可横向滚动也不能撑破卡片（同 .qtext.code）。 */
.steps-detail li .st-code {
  font-family: Consolas, Monaco, "DejaVu Sans Mono", "Courier New", monospace;
  font-size: .8rem;
  line-height: 1.7;
  white-space: pre;
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  font-variant-ligatures: none;
  background: var(--bg);
  padding: 0.5rem 0.625rem;
  border-radius: 0.5rem;
  border-left: 3px solid var(--brand);
  margin: 0.25rem 0;
}

/* 难度标：难度名 + 星点 + 分值。
   ★ 不用彩色底块（去 AI 味铁律⑤：图标不带彩色底方块），只给一点极淡的底色区分档位；
     分值用 <i> 单独加粗，右对齐，扫一眼就知道这题值几分。 */
.qmeta .dq {
  flex:none; display:inline-flex; align-items:center; gap:0.1875rem;
  font-size:0.66rem; font-weight:800; letter-spacing:0.02em;
  padding:0.125rem 0.375rem; border-radius:0.25rem;
  background:var(--bg); color:var(--sub); border:1px solid var(--line);
}
.qmeta .dq i { font-style:normal; color:var(--ink); font-weight:900; }
.qmeta .dq.d1 { color:var(--brand); border-color:var(--brand-line); }
.qmeta .dq.d2 { color:var(--warn); border-color:var(--warn-line); background:var(--warn-soft); }
.qmeta .dq.d3 { color:var(--gold-ink); border-color:var(--gold-line); background:var(--gold-soft); }
body.theme-dark .qmeta .dq { background:var(--bg); }

/* 代码着色：四色 + 库函数，全部走主题变量，白天黑夜都跟着变 */
.ck-kw  { color: var(--code-kw,  #7b3fb5); font-weight: 700; }
.ck-str { color: var(--code-str, #1f7a4d); }
.ck-com { color: var(--code-com, #8a90a8); font-style: italic; }
.ck-num { color: var(--code-num, #b3541e); }
.ck-fn  { color: var(--code-fn,  #1f5f9e); }
.qtext.steps-detail, .steps-detail code { font-family: inherit; }
.details-code, .ri-details .qtext.code { margin: 0; }

/* 数学分步详解 */
.steps-detail { margin-top:0.5625rem; background:var(--card); border-radius:0.625rem; padding:0.5625rem 0.75rem; text-align:left; }
.steps-detail b { font-size:.8rem; color:var(--warn); }
.steps-detail ol { margin:0.375rem 0 0 1.125rem; }
.steps-detail li { font-size:.83rem; line-height:1.75; margin:0.1875rem 0; }
details.ri-details { margin-top:0.4375rem; }
details.ri-details summary { font-size:.78rem; color:var(--brand); font-weight:700; cursor:pointer; }
details.ri-details .steps-detail { background:var(--bg); }

/* ★ v133 考试技巧页的小节跳转条（技巧 30+ 条，一屏装不下）
   ⚠ .chiprow 装在 .card 里面：宽屏 #view 是瀑布流，裸的 flex 容器会被分栏切碎。 */
.chiprow { display:flex; flex-wrap:wrap; gap:0.375rem; }
.chiprow .chip { font-family:inherit; cursor:pointer; text-align:left; }

/* ★ v133 英语书面表达（写作题）
   ① .wrd 作答前的「结构 + 提醒」两块；② .wsteps 交卷后的「结构/句型/提醒/范文/译文」五块。
   ⚠ 颜色一律走 CSS 变量（四套主题 + 纸白都要能看），不写死色值。 */
.wrd { background:var(--bg); border-radius:0.625rem; padding:0.5rem 0.6875rem; }
.wrd-l { font-size:.72rem; font-weight:800; color:var(--warn); letter-spacing:.03em; }
.wrd-b { font-size:.83rem; line-height:1.7; color:var(--ink); margin-bottom:0.4375rem; }
.wrd-b:last-child { margin-bottom:0; }
.wsteps { margin-top:0.5625rem; display:flex; flex-direction:column; gap:0.4375rem; }
.ws { background:var(--card); border-radius:0.625rem; padding:0.5rem 0.6875rem; }
.ws-l { font-size:.72rem; font-weight:800; color:var(--sub); letter-spacing:.03em; }
.ws-l.c-warn { color:var(--warn); }
.ws-l.c-brand { color:var(--brand); }
.ws-b { font-size:.83rem; line-height:1.75; margin-top:0.125rem; color:var(--ink); }
/* **强调** 转出来的 <b>：只加粗上色，不再单独造块 */
.ws-b b { color:var(--warn); }
/* 提醒：整块浅警示底 + 左侧竖条，一眼能看见"这篇用什么时态" */
.ws-warn { background:var(--warn-soft); border-left:3px solid var(--warn-line); }
/* 范文：英文原文单独成块，用主色竖条区别于译文 */
.ws-model { background:var(--brand-soft); border-left:3px solid var(--brand-line); }
/* 译文：浅一档的字色，紧挨范文下方，英文一句对中文一句 */
.ws-cn .ws-b { color:var(--sub); }
/* 万能句型：并列清单，一条一行（与 v132「例子一条一行」同一条规矩） */
.ws-bs { display:flex; flex-direction:column; gap:0.1875rem; margin-top:0.25rem; }
.ws-pat { font-size:.82rem; line-height:1.6; }

/* 语法详情 */
.gp { border-left:4px solid var(--brand); background:var(--bg); border-radius:0 var(--radius-s) var(--radius-s) 0; padding:0.6875rem 0.875rem; margin-bottom:0.625rem; }
.gp h4 { font-size:.9rem; font-weight:800; margin-bottom:0.3125rem; }
.gp p { font-size:.85rem; line-height:1.8; }
.gtips { background:var(--ok-soft); color:var(--ok); border-radius:var(--radius-s); padding:0.75rem 0.875rem; font-size:.88rem; font-weight:700; margin:0.75rem 0; }
.gtraps { background:var(--bad-soft); border-radius:var(--radius-s); padding:0.75rem 0.875rem; margin:0.75rem 0; }
.gtraps h4 { color:var(--bad); font-size:.88rem; margin-bottom:0.4375rem; }
.gtraps li { font-size:.82rem; line-height:1.75; color:var(--bad); margin-left:1.125rem; }

/* 词汇浏览 */
.wordrow { padding:0.6875rem 0.875rem; background:var(--card); border-radius:0.8125rem; box-shadow:var(--shadow); border:1px solid var(--line); margin-bottom:0.5625rem; }
.wordrow .wr-t { display:flex; align-items:center; gap:0.5rem; }
.wordrow .wr-w { font-weight:800; font-size:1rem; }
.wordrow .wr-p { color:var(--sub); font-size:.78rem; }
.wordrow .wr-m { margin-left:auto; font-size:.85rem; color:var(--ink); font-weight:700; text-align:right; }
.wordrow .wr-d { display:none; margin-top:0.5625rem; border-top:1px dashed var(--line); padding-top:0.5625rem; font-size:.8rem; line-height:1.75; color:var(--sub); }
.wordrow.open .wr-d { display:block; }
.playbtn { width:2.125rem; height:2.125rem; border-radius:50%; background:var(--brand-soft); border:1px solid var(--brand-line); font-size:.95rem; display:inline-flex; align-items:center; justify-content:center; flex:none; }

/* 锁遮罩 */
.lockover { text-align:center; padding:3.125rem 1.5rem; }
.lockover .lo-ico { font-size:3.4rem; margin-bottom:0.875rem; }
.lockover h3 { font-size:1.15rem; margin-bottom:0.625rem; }
.lockover .sub { margin-bottom:1.125rem; }

/* 统计格 */
/* 4 项统计铺满一行，避免 3 列网格下末项落单留大片空档 */
.statgrid { display:grid; grid-template-columns:repeat(4,1fr); gap:0.5rem; }
/* 自适应列数（响应式排版的一部分）：固定 4 列在窄卡片里会挤、在宽屏上又太散。
   auto-fill + minmax 让列数随可用宽度自动增减，手机端（宽度不足时）仍落在 4 列以内，
   观感与原来一致。minmax 下限用 rem，跟着 --ui-scale 一起缩放。 */
html:not([data-lay="narrow"]) .statgrid { grid-template-columns:repeat(auto-fit,minmax(6.5rem,1fr)); }
/* 去 AI 味（四宫格数字卡）：四个并排的小卡 = 「指标看板」模板感。
   改成一条数据带：只有外圈一条描边，内部靠竖分隔线分区，数字与标签上下叠。 */
.stat { background:none; border:none; box-shadow:none; border-radius:0; padding:0.625rem 0.375rem; text-align:center; position:relative; }
.stat + .stat::before { content://; position:absolute; left:0; top:22%; bottom:22%; width:1px; background:var(--line); }
.statgrid { background:var(--card); border:1px solid var(--line); border-radius:var(--radius-s); padding:0.125rem 0.25rem; }
.stat b { font-size:1.15rem; display:block; }
.stat span { font-size:.68rem; color:var(--sub); font-weight:600; }

/* 成就 */
/* ★ v85 四列小格里塞不下「条件」那一行（每格只有约 4.4rem 宽），所以手机档改成两列 ——
   一格 8rem 足够放「累计学 300 个单词」这种说明，成就墙从「一排看不懂的图标」
   变成「能读懂的目标清单」。宽屏仍按可用宽度自适应多列。 */
.achgrid { display:grid; grid-template-columns:repeat(2,1fr); gap:0.5625rem; }
/* 同上：宽屏下成就墙按可用宽度自动排更多列，避免卡片撑得过宽显得空 */
html:not([data-lay="narrow"]) .achgrid { grid-template-columns:repeat(auto-fit,minmax(7rem,1fr)); }
.ach { background:var(--card); border-radius:0.8125rem; box-shadow:var(--shadow); padding:0.6875rem 0.25rem; text-align:center; border:2px solid transparent; }
.ach .a-ico { font-size:1.5rem; }
.ach .a-t { font-size:.68rem; font-weight:700; margin-top:0.25rem; color:var(--ink); line-height:1.3; }
/* 条件说明：锁着时写「怎么拿到」，拿到之后变绿说一句「已达成」 */
.ach .a-d { font-size:.6rem; color:var(--sub); line-height:1.35; margin-top:0.1875rem; padding:0 0.25rem; }
.ach .a-p { height:0.1875rem; border-radius:62.4375rem; background:var(--line); margin:0.3125rem 0.4375rem 0; overflow:hidden; }
.ach .a-p i { display:block; height:100%; border-radius:inherit; background:var(--brand); }
.ach.got { border-color:var(--gold); background:var(--gold-shine); }
.ach.got .a-t { color:var(--gold-ink); }
.ach.got .a-d { color:var(--ok); }
/* ============ v116 成就：难度分档 + 领取按钮 ============
   ① 档位（入门 / 进阶 / 困难 / 地狱 / 传说）在名字下面一行小字。
      ⚠ 不用胶囊：去 AI 味第 ③ 条（小标签别做成胶囊），它只是个说明不是按钮。
      难度越高颜色越重，扫一眼就能看出哪几条是真难。 */
.ach .a-lv { display:block; font-style:normal; font-weight:400; font-size:.55rem; color:var(--sub); margin-top:0.0625rem; line-height:1.3; }
.ach.lv3 .a-lv { color:var(--brand); }
.ach.lv4 .a-lv { color:var(--gold-ink); }
.ach.lv5 .a-lv { color:var(--gold-ink); font-weight:700; }
/* 传说档：边框用虚线区分，拿到之后再加一层描边，让它在一排金色里也跳出来 */
.ach.lv5 { border-width:2px; border-style:dashed; border-color:var(--gold-line); }
.ach.lv5.got { border-style:solid; border-color:var(--gold); }
/* ② 已达成但还没领分：边框加粗成主色，和"已领取"的金色区分开 ——
      不然用户看不出哪些还能点，一整墙金色会让人以为都领过了。 */
.ach.pend { border-color:var(--brand); background:var(--brand-soft); }
.ach.pend .a-t { color:var(--ink); }
.ach.pend .a-d { color:var(--sub); }
.ach-claim { margin-top:0.375rem; padding-top:0.1875rem; padding-bottom:0.1875rem; padding-left:0.5rem; padding-right:0.5rem; font-size:.6rem; }
.ach .a-ok { font-size:.58rem; color:var(--ok); margin-top:0.3125rem; }
/* ③ 待领取横幅：成就可能在做题时悄悄达成，没有它只能靠碰巧翻到成就墙 */
.ach-bar { display:flex; align-items:center; justify-content:space-between; gap:0.5rem;
  background-color:var(--gold-soft); background-image:none; border-radius:0.6875rem;
  padding-top:0.5rem; padding-right:0.6875rem; padding-bottom:0.5rem; padding-left:0.6875rem;
  margin-bottom:0.5625rem; font-size:.72rem; color:var(--gold-ink); }
.ach-bar b { color:var(--gold-ink); }

/* ============ v116 学习报告 ============ */
/* 30 天打卡网格：30 个小方片，完成的那天填主色。
   ⚠ 用 grid 固定 10 列（3 行），不靠自动换行 —— 换行在窄屏上会变成 7/8 列，
     一眼看不出"这是按周排的"。 */
.rp-grid { display:grid; grid-template-columns:repeat(10,1fr); gap:0.1875rem; margin-top:0.25rem; }
.rp-day { display:block; height:0.75rem; border-radius:0.1875rem; background:var(--line); }
.rp-day.on { background:var(--brand); }
.rp-legend { display:inline-flex; align-items:center; gap:0.25rem; margin-top:0.25rem; }
.rp-legend .rp-dot { display:inline-block; width:0.75rem; height:0.75rem; border-radius:0.1875rem; background:var(--brand); }
/* 四科进度行：科名 / 进度条 / 通过关数 三段，别做成卡片套卡片 */
.rp-row { display:flex; align-items:center; gap:0.5rem; padding:0.4375rem 0; border-top:1px solid var(--line); }
.rp-row:first-child { border-top:0; }
.rp-rl { width:5.25rem; flex:none; min-width:0; }
.rp-rl b { display:block; font-size:.82rem; }
.rp-rl span { display:block; font-size:.64rem; color:var(--sub); }
.rp-rb { flex:1; min-width:0; }
.rp-rr { width:4.5rem; flex:none; text-align:right; }
.rp-rr b { display:block; font-size:.82rem; }
.rp-rr span { display:block; font-size:.64rem; color:var(--sub); }

/* ============ v85 首次引导弹窗（.ob-*） ============
   旧版整段是「emoji + 短句 + <br>」堆出来的：四个学科各一个 emoji、每行结尾 <br>，
   行距靠 inline style="line-height:2" 撑 —— 这是"生成式文案"最典型的样子。
   新版：学科做成一条带边框的学科条（图标 + 名字），学习机制做成带图标的真实列表，
   规则说明降为次级小字。全部用 class、不用内联样式。 */
.ob-sub { font-size:.76rem; color:var(--sub); margin:-0.25rem 0 0.75rem; }
.ob-subj { display:grid; grid-template-columns:repeat(4,1fr); gap:0.375rem; margin-bottom:0.875rem; }
.ob-sj { display:flex; flex-direction:column; align-items:center; gap:0.1875rem;
  padding:0.5rem 0.125rem; border:1px solid var(--line); border-radius:0.5rem; color:var(--brand); }
.ob-sj span { font-size:.68rem; font-weight:700; color:var(--ink); }
.ob-h { font-size:.82rem; font-weight:800; color:var(--ink); margin:0.75rem 0 0.375rem;
  padding-left:0.4375rem; border-left:2px solid var(--brand); line-height:1.2; }
.ob-list { list-style:none; margin:0; padding:0; }
/* ⚠ 别把 <b> 和它后面的文字直接塞进 flex（会各自变成一个 flex item，
   加粗标题被挤成左一列、正文缩到右一列，看着像两列表格）。
   图标 flex:none 占位，其余全部内容（<b> + 文本）装进同一个 .ob-t 里正常折行。 */
.ob-list li { display:flex; align-items:flex-start; gap:0.4375rem; font-size:.78rem;
  line-height:1.55; color:var(--ink); padding:0.375rem 0; border-bottom:1px solid var(--line); }
.ob-list li:last-child { border-bottom:none; }
.ob-list li > .ico { flex:none; color:var(--brand); margin-top:0.1875rem; }
.ob-list .ob-t { flex:1; min-width:0; }
.ob-list .ob-t b { font-weight:800; margin-right:0.25rem; }
.ob-note { font-size:.74rem; line-height:1.65; color:var(--sub); }
.ob-warn { margin-top:0.625rem; font-size:.72rem; line-height:1.5; color:var(--warn);
  background:var(--warn-soft); border:1px solid var(--warn-line); border-radius:0.375rem; padding:0.5rem 0.5625rem;
  display:flex; align-items:flex-start; gap:0.3125rem; }
.ob-warn .ico { flex:none; margin-top:0.1rem; }
/* ⚠ 本项目**一律不用 @media**（响应式只在 fit.js 给 <html> 打 data-lay 一处判定）。
   窄档学科条退成两列：360px 下四列每格只有 ~78px，「计算机应用」五个字放不下会折行。 */
html[data-lay="narrow"] .ob-subj { grid-template-columns:repeat(2,1fr); }
/* ★ 三个入口按钮并成一行后必须横排：窄屏下 .row 不换行时按钮会被压到 60px，
   「先学 12 个新词」放不下 → 允许 flex 收缩 + 字号略降，图标在此处隐藏（纯文字更清楚）。
   ⚠★ sticky 按钮行是「浮」在内容之上的：它会盖住正下方的最后一屏内容（实测盖住了
   底部那条惩罚提示，用户滚到底也看不见）。所以给吸附行补一条 54px 的占位留白
   （padding-bottom 加在行自身没用 —— sticky 元素的 padding 跟着它一起走）。 */
.ob-acts { gap:0.375rem; }
.ob-acts + * { margin-top:0; }
.modal > .ob-pad { height:3.25rem; }
.ob-acts .btn { padding-left:0.25rem; padding-right:0.25rem; font-size:.78rem; }
.ob-acts .btn .ico { display:none; }
html[data-lay="narrow"] .ob-acts .btn { font-size:.74rem; }

/* 设置 */
.setrow { display:flex; align-items:center; gap:0.625rem; padding:0.8125rem 0.125rem; border-bottom:1px dashed var(--line); }
.setrow:last-child { border-bottom:none; }
.setrow .sr-t { flex:1; }
.setrow .sr-t b { font-size:.9rem; display:block; }
.setrow .sr-t span { font-size:.72rem; color:var(--sub); }
.setrow select,.setrow input[type=date] { background:var(--bg); border:1px solid var(--line); border-radius:0.5625rem; padding:0.4375rem 0.5625rem; font-size:.82rem; color:var(--ink); max-width:9.375rem; }

/* 「我的」页的两行入口（2026-10-17）：积分商城 / 设置 各自进独立页面
   ⚠ 不用卡片套卡片：一行就是一个可点的整行，靠右侧箭头和 hover 底色表示可点，
      比再包一层小卡片干净，也不会让「我的」页看着像俄罗斯套娃。 */
.optrow { display:flex; align-items:center; gap:0.6875rem; width:100%; text-align:left;
  padding:0.6875rem 0.5rem; border-top-width:1px; border-top-style:dashed; border-top-color:var(--line);
  background:none; border-left:none; border-right:none; border-bottom:none; cursor:pointer; color:var(--ink); }
.optrow:first-of-type { border-top:none; }
.optrow:active { background:var(--bg); }
.optrow .or-i { font-size:1.25rem; line-height:1; flex:none; }
.optrow .or-t { flex:1; min-width:0; }
.optrow .or-t b { display:block; font-size:.9rem; font-weight:800; }
.optrow .or-t i { display:block; font-style:normal; font-size:.72rem; color:var(--sub); margin-top:0.125rem; }
.optrow .or-go { flex:none; font-size:1.1rem; color:var(--sub); }
.seg { display:flex; background:var(--bg); border-radius:0.625rem; padding:0.1875rem; }
.seg button { padding:0.375rem 0.6875rem; border-radius:0.5rem; font-size:.76rem; font-weight:700; color:var(--sub); }
.seg button.on { background:var(--card); color:var(--brand); box-shadow:var(--shadow); }

/* 弹窗 & Toast */
/* ⚠ inset 是 Chrome 87+ 才认的简写。老内核会**整条丢掉**这行 → position:fixed 的偏移
   全变 auto → 弹窗按「静态位置」落到文档最底部（实测 y≈3578px，屏幕外），
   用户看到的就是「点『查看奖池』没反应」。所以必须先写 top/right/bottom/left 兜底，
   再写 inset —— 与上面 env() 的写法约定一致。 */
#modal-root { position:fixed; top:0; right:0; bottom:0; left:0; inset:0; z-index:200; pointer-events:none; }
.modal-mask { position:fixed; top:0; right:0; bottom:0; left:0; inset:0; background:rgba(15,18,40,.5); pointer-events:auto; display:flex; align-items:flex-end; justify-content:center; animation:fadein .2s; }
@keyframes fadein { from{opacity:0} }
.modal { background:var(--card); width:100%; max-width:var(--ui-max); border-radius:1.375rem 1.375rem 0 0; padding:1.25rem var(--pad); padding:1.25rem var(--pad) calc(1.25rem + env(safe-area-inset-bottom,0px)); max-height:82vh; overflow-y:auto; animation:slideup .28s ease; }
.modal h3 { font-size:1.1rem; font-weight:800; margin-bottom:0.625rem; display:flex; align-items:center; gap:0.5rem; }
.modal .m-close { position:absolute; top:0.875rem; right:0.875rem; color:var(--sub); font-size:1.1rem; padding:0.25rem; }
#toast-root { position:fixed; left:0; right:0; bottom:calc(var(--tabbar-h) + 1.625rem); z-index:300; display:flex; flex-direction:column; align-items:center; gap:0.5rem; pointer-events:none; }
.toast { background:rgba(30,34,53,.92); color:#fff; font-size:.83rem; font-weight:600; padding:0.625rem 1.125rem; border-radius:62.4375rem; animation:slideup .25s; max-width:86%; text-align:center; line-height:1.5; }

/* 结算页 */
.result-hero { text-align:center; padding:1.375rem 0 0.625rem; }
.result-hero .rh-ico { font-size:3.6rem; }
.result-hero h2 { font-size:1.4rem; margin-top:0.5rem; }
.result-hero .stars { font-size:1.7rem; color:var(--gold); letter-spacing:0.25rem; margin-top:0.375rem; }
.result-hero .sub { margin-top:0.5rem; }
.reviewitem { padding:0.75rem 0.875rem; border-radius:0.8125rem; background:var(--card); box-shadow:var(--shadow); border:1px solid var(--line); margin-bottom:0.625rem; }
.reviewitem .ri-q { font-size:.85rem; font-weight:700; line-height:1.55; }
.reviewitem .ri-a { font-size:.78rem; margin-top:0.375rem; line-height:1.65; }

/* ---------- 积分商城 2.0 ---------- */
/* 「我的」页宽屏：取消瀑布流，改为单列通栏。
   这页的卡要么本来就得跨整行（资料 / 数据 / 商城 / 设置），要么是「成就墙」「学习日志」
   这类矮卡 —— 在 columns 里会被前面的跨行卡切成一段段，每段只剩一张卡、右侧整片空白。
   （column-count:1 而不是 display:block —— 分栏是 column-* 属性，改 display 取消不掉。） */
html[data-lay="wide"] #view:has(> .hero-profile),
html[data-lay="desk"] #view:has(> .hero-profile) { column-count:1; }
/* 学习日志条目多，通栏后每行被拉得很长 → 卡内再自适应分栏 */
html:not([data-lay="narrow"]) .log-card { column-width:22rem; column-gap:1rem; }
html:not([data-lay="narrow"]) .log-card .setrow { break-inside:avoid; }
/* 商品多，宽屏下让整张商城卡跨满整行 —— 否则它被挤进瀑布流的一列里，
   16.5rem 的商品格只能排 1 列，商城变成一条长长的竖条。 */
html:not([data-lay="narrow"]) #view > .card:has(.shopgrid) { column-span:all; }
.shopgrid { display:grid; grid-template-columns:repeat(auto-fill,minmax(16.5rem,1fr)); gap:0.5rem; margin-top:0.625rem; }
.shopgrid.fadein { animation:fadein .22s; }
.shopitem { display:flex; align-items:center; gap:0.625rem; padding:0.625rem 0.6875rem;
  border-radius:0.8125rem; background:var(--bg); border:1px solid var(--line); }
.shopitem.on { border-color:var(--brand); background:var(--brand-soft); }
.shopitem .si-prev { width:3rem; height:3rem; border-radius:0.8125rem; flex:none; border:1px solid var(--line);
  display:flex; align-items:center; justify-content:center; font-size:1.5rem; overflow:visible; }
.si-emoji { font-size:1.5rem; line-height:1; }
.shopitem .si-body { flex:1; min-width:0; }
.shopitem .si-body > b { font-size:.86rem; }
.shopitem .si-body .sub { font-size:.72rem; line-height:1.45; margin-top:0.125rem; }
.si-stock { margin-top:0.25rem; }
.si-on { color:var(--ok); }
.si-lack { font-style:normal; font-weight:800; color:var(--bad); }
/* 价格与「还差 N 分」竖排，别把商品描述挤折行 */
.shopitem .si-act .btn { flex-direction:column; gap:0.0625rem; line-height:1.3; }
.shopitem .si-act .si-lack { font-size:.66rem; }
.shopitem .si-act { flex:none; }
.shop-collect { margin-top:0.5rem; font-size:.72rem; }
.shop-collect b { color:var(--brand); }
/* 商城里的补充说明（如「深夜模式不用买，顶栏开关免费切」） */
.shop-note { margin-top:0.625rem; padding:0.5rem 0.625rem; font-size:.72rem; line-height:1.6; border-radius:0.5rem; background:var(--brand-soft); color:var(--ink); }
.shop-note b { color:var(--brand); }
/* 刚买到手的那张卡闪一下 */
.shopitem.si-flash { animation:siFlash 1.4s ease-out; }
@keyframes siFlash {
  0% { box-shadow:0 0 0 0 var(--brand-glow); border-color:var(--brand); background:var(--brand-soft); }
  60% { box-shadow:0 0 0 0.4rem transparent; }
  100% { box-shadow:none; }
}

/* 扭蛋机 */
.gacha { margin-top:0.75rem; padding:0.75rem 0.8125rem; border-radius:0.875rem;
  background:var(--brand-soft); border:1px solid var(--brand-line); }
.gacha-hd { display:flex; align-items:center; gap:0.5rem; }
.gacha-hd b { font-size:.9rem; }
.gacha-ico { font-size:1.6rem; line-height:1; animation:gachaShake 3.4s ease-in-out infinite; }
@keyframes gachaShake { 0%,88%,100% { transform:rotate(0) } 92% { transform:rotate(-13deg) } 96% { transform:rotate(13deg) } }
.gacha-btns { display:flex; gap:0.5rem; margin-top:0.625rem; }
.gacha-btns .btn { flex:1; }
.gacha-btns .btn.ghost { background:var(--card); border:1px solid var(--brand-line); }
/* 积分不够时按钮是 disabled + gray，底色会和容器撞在一起，看起来像纯文字 → 补个边框 */
.gacha-btns .btn.gray { background:var(--card); border:1px solid var(--line); }
.gacha-best { margin-top:0.5rem; font-size:.72rem; }
/* ★ 免费额度说明条：素文字 + 左侧金色竖条，跟「去 AI 味」里的 .rep-note 同一套语言。
   ⚠ 老内核「先长写兜底」：border-radius 分四条写、margin/padding 用长写。 */
.gacha-free { margin-top:0.625rem; padding-top:0.5rem; padding-right:0.625rem; padding-bottom:0.5rem; padding-left:0.625rem;
  border-top-left-radius:0.625rem; border-top-right-radius:0.625rem; border-bottom-right-radius:0.625rem; border-bottom-left-radius:0.625rem;
  background:var(--gold-soft); border-left-width:3px; border-left-style:solid; border-left-color:var(--gold);
  font-size:.76rem; line-height:1.7; color:var(--sub); }
.gacha-free b { color:var(--gold-ink); }

/* ---------- 扭蛋 2.0：保底 / 奖池公示 / 稀有度 ---------- */
.gacha-save { font-style:normal; font-size:.66rem; font-weight:800; opacity:.85; margin-left:0.1875rem; }
.pity-row { display:flex; align-items:center; gap:0.5rem; margin-top:0.5rem; }
.pity-row .pity-txt { flex:1; min-width:0; font-size:.72rem; font-weight:700; color:var(--sub); }
.pity-row .pity-txt b { color:var(--gold-ink); }
.pity-row .btn.ghost.sm { flex:none; background:var(--card); border:1px solid var(--brand-line); }
/* 开奖动画：抽的时候先摇一摇，别瞬间就出结果 */
.gacha.spin { animation:gachaSpin .62s ease-in-out; }
.gacha.spin .gacha-ico { animation:spinIco .62s linear infinite; }
@keyframes gachaSpin {
  0%, 100% { transform:translate(0, 0) rotate(0); }
  20% { transform:translate(-0.3rem, 0) rotate(-1.2deg); }
  45% { transform:translate(0.3rem, 0) rotate(1.2deg); }
  70% { transform:translate(-0.18rem, 0) rotate(-0.6deg); }
}
@keyframes spinIco { to { transform:rotate(360deg); } }

/* ============ 原神式开奖动画（.gx-*） ============
   ★★ 结构：全屏遮罩 → 星尘天空 + 三颗流星 → 光柱（升起来时才显色）→ 竖排卡牌翻面。
   ★ 三档颜色就是项目的三档稀有度，不套原神四星五星：
       普通 蓝 / 稀有 紫 / 金 金
   ★ 颜色在**光柱阶段**就泄底 —— 这是用户要的"提前知道自己有什么级别"：
     看到金光就知道这次出金了，紫光就知道最好只是稀有。
   ★★ 老内核铁律：`inset` 必须「先长写兜底、后简写」两条；
      `@keyframes` 里只用 transform/opacity（性能最好的两个属性），别用 filter。
   ★ 卡片是 3D 翻面 → `.gx-card` 要给 `transform-style:preserve-3d`，
     而父级 `.gx-cards` 不能有 overflow:hidden（会裁掉 3D）。 */
.gx {
  position:fixed; left:0; right:0; top:0; bottom:0;
  inset:0;
  z-index:900;                     /* 高于弹窗(400)与顶栏(50)，低于启动报错层(9999) */
  display:flex; align-items:center; justify-content:center;
  flex-direction:column; overflow:hidden;
  background:radial-gradient(circle at 50% 62%, #1b2140 0%, #0b0e1c 62%, #05060d 100%);
  animation:gxIn .22s ease-out;
}
@keyframes gxIn { from { opacity:0 } to { opacity:1 } }
.gx.gx-out { animation:gxOut .2s ease-in forwards; }
@keyframes gxOut { to { opacity:0 } }

/* 星尘：用两层小圆点 + 缓慢漂移，纯 CSS，不加 DOM 数量 */
.gx-sky {
  position:absolute; left:0; right:0; top:0; bottom:0; inset:0;
  background-image:
    radial-gradient(1.5px 1.5px at 18% 22%, rgba(255,255,255,.85), transparent),
    radial-gradient(1.5px 1.5px at 72% 18%, rgba(255,255,255,.6), transparent),
    radial-gradient(1px 1px at 42% 68%, rgba(255,255,255,.55), transparent),
    radial-gradient(1.5px 1.5px at 88% 62%, rgba(255,255,255,.7), transparent),
    radial-gradient(1px 1px at 30% 88%, rgba(255,255,255,.5), transparent),
    radial-gradient(1px 1px at 62% 40%, rgba(255,255,255,.45), transparent);
  animation:gxDrift 6s linear infinite alternate;
}
@keyframes gxDrift { from { transform:translate3d(0,0,0) } to { transform:translate3d(-8px,-6px,0) } }

/* 三颗流星：方向统一（都往左下），时间先后错开 —— 和主题过场同一套"流星雨不像梳子"的口径 */
.gx-star {
  position:absolute; top:-14%; left:52%;
  width:2px; height:9rem; border-radius:2px;
  background:linear-gradient(to bottom, rgba(255,255,255,0), rgba(255,255,255,.95));
  transform:rotate(-28deg); opacity:0;
  animation:gxStar 0.72s cubic-bezier(.4,0,.7,1) forwards;
}
.gx-star.s1 { left:58%; animation-delay:.02s; height:9rem; }
.gx-star.s2 { left:42%; animation-delay:.11s; height:7rem; opacity:0 }
.gx-star.s3 { left:70%; animation-delay:.19s; height:5.5rem; opacity:0 }
@keyframes gxStar {
  0% { opacity:0; transform:rotate(-28deg) translateY(0) }
  18% { opacity:.95 }
  100% { opacity:0; transform:rotate(-28deg) translateY(34rem) }
}

/* 光柱：平时是暗的，`.gx-beam-on` 之后冲天亮起并按稀有度显色。
   ★ 用两段渐变叠出"中心白热 + 外圈有色"，比单色更像真的光。 */
/* ★★ 光柱要在卡牌**背后**从下往上冲 —— 所以：
     ① z-index 必须比 .gx-cards(2) 低（设 1），否则光柱盖在卡牌前面像一块白板；
     ② 高度只到屏幕 62%（顶部留黑，光才有"聚到顶"的感觉）；
     ③ 用 to top 渐变：底部白热 → 中间有色 → 顶部透明，
        这样光柱是"从地面涌上来"而不是"从天上垂下来一根柱子"。
   踩到的坑：早先 z-index 没写（默认 auto），DOM 里又排在 cards 之后 →
   光柱直接糊在卡牌下沿，截图看起来像块灰白挡板。 */
.gx-beam {
  position:absolute; left:50%; bottom:0; z-index:1;
  width:9rem; height:0; margin-left:-4.5rem;
  opacity:0; transition:opacity .28s ease;
  background:
    linear-gradient(to top, rgba(255,255,255,.92), rgba(255,255,255,.28) 38%, transparent 82%),
    linear-gradient(to top, var(--gxc, #5a9bff), transparent 74%);
  border-radius:50% 50% 0 0 / 10% 10% 0 0;
  filter:none;
  pointer-events:none;
}
.gx.gx-beam-on .gx-beam {
  opacity:.92; height:62%;
  animation:gxBeamPulse .9s ease-out .3s 2 alternate;
}
@keyframes gxBeamPulse { from { opacity:.62 } to { opacity:.95 } }

/* 三档颜色：只改一个变量，光柱/卡片/边框全都跟着变 */
.gx-blue   { --gxc:#5a9bff; --gxc2:#8fc0ff; }
.gx-purple { --gxc:#a877f0; --gxc2:#cfa9ff; }
.gx-gold   { --gxc:#ffc23d; --gxc2:#ffe9a8; }

/* 卡牌区 */
.gx-cards {
  position:relative; z-index:2;
  display:flex; flex-wrap:wrap; gap:0.625rem;
  align-items:center; justify-content:center;
  width:86%; max-width:22rem;
}
.gx-multi .gx-cards { max-width:20rem; }
.gx-multi .gx-card { width:3.6rem; height:4.8rem; }
.gx-card {
  position:relative; width:9rem; height:12rem;
  transform-style:preserve-3d;
  animation:gxFlip 0.62s cubic-bezier(.34,1.36,.5,1) both;
}
@keyframes gxFlip {
  0%   { transform:rotateY(180deg) scale(.55); opacity:0 }
  55%  { opacity:1 }
  100% { transform:rotateY(0deg) scale(1); opacity:1 }
}
.gx-face {
  position:absolute; left:0; right:0; top:0; bottom:0; inset:0;
  border-radius:0.75rem; display:flex; flex-direction:column;
  align-items:center; justify-content:center; gap:0.25rem;
  backface-visibility:hidden; -webkit-backface-visibility:hidden;
}
.gx-back {
  transform:rotateY(180deg);
  background:linear-gradient(150deg, #2a2f52, #161a2e);
  border:1px solid rgba(255,255,255,.16);
}
.gx-back::after {
  content:""; width:38%; height:38%; border-radius:50%;
  border:2px solid var(--gxc, #5a9bff); opacity:.55;
}
.gx-front {
  background:linear-gradient(160deg, rgba(255,255,255,.14), rgba(255,255,255,.04));
  border:1.5px solid var(--gxc, #5a9bff);
  box-shadow:0 0 1.2rem -0.2rem var(--gxc, #5a9bff), inset 0 0 1.6rem -0.8rem var(--gxc2, #8fc0ff);
}
.gx-front .gx-ico { font-size:1.9rem; line-height:1; }
.gx-multi .gx-front .gx-ico { font-size:1.15rem; }
.gx-front b {
  font-size:.66rem; font-weight:800; color:#fff; text-align:center;
  padding:0 .25rem; line-height:1.25;
  text-shadow:0 1px 2px rgba(0,0,0,.5);
}
.gx-multi .gx-front b { font-size:.5rem; }
/* 普通档不发光，避免"每张卡都在闪"= 没有对比度 */
.gx-front.t-n { border-color:rgba(255,255,255,.3); box-shadow:none; }

/* UP / 歪 角标 */
.gx-flag {
  position:absolute; top:-0.4rem; right:-0.3rem;
  font-style:normal; font-size:.54rem; font-weight:900; letter-spacing:.04em;
  padding:.08rem .26rem; border-radius:.25rem; color:#20233a;
  background:var(--gxc2, #8fc0ff);
}
.gx-flag.mg { background:#e88176; color:#fff; }
.gx-multi .gx-flag { font-size:.46rem; }

/* 底部说明：这一束光是什么颜色 = 最好那件的级别 */
.gx-tip {
  position:relative; z-index:2; margin-top:1.5rem;
  font-size:.8rem; font-weight:800; color:var(--gxc2, #fff);
  letter-spacing:.06em; text-align:center;
}
.gx-tip span {
  display:block; margin-top:.375rem;
  font-size:.62rem; font-weight:600; color:rgba(255,255,255,.42); letter-spacing:0;
}

/* 结果弹窗里的「歪 / UP」角标与说明条 */
.gacha-res .gr-tag.up { background:var(--gold); color:#fff; }
.gacha-res .gr-tag.mg { background:var(--bad); color:#fff; }
.gx-note {
  margin-top:0.625rem; padding:0.5rem 0.625rem; border-radius:0.5rem;
  font-size:0.72rem; line-height:1.6; background:var(--brand-soft); color:var(--ink);
}
.gx-note b { color:var(--brand); }
.gx-note.mg { background:var(--warn-soft); border:1px solid var(--warn-line); }
.gx-note.mg b { color:var(--warn); }
.gx-note.up { background:var(--gold-soft); border:1px solid var(--gold-line); }
.gx-note.up b { color:var(--gold-ink); }

/* 系统开了「减少动态效果」→ 动画全关，直接给最终态
   ⚠ 这是唯一合法的 @media 用法（系统偏好，没有 data-lay 等价物）。 */
@media (prefers-reduced-motion: reduce) {
  .gx, .gx-card, .gx-star, .gx-beam, .gx-sky { animation:none !important; transition:none !important; }
  .gx-star { opacity:0 !important; }
  .gx.gx-beam-on .gx-beam { opacity:.85; height:80%; }
  .gx-card { transform:none !important; opacity:1 !important; }
}
.gr-sum { font-size:.82rem; color:var(--sub); margin-bottom:0.625rem; }
.gr-sum b { color:var(--ink); }
.c-rare { color:var(--gold-ink); }
.c-warn { color:var(--warn); }
.gacha-res .gr { position:relative; }
.gacha-res .gr.t-g { border-color:var(--gold-line); background:var(--gold-soft); }
.gacha-res .gr.t-r { border-color:var(--gold); background:var(--gold-shine); box-shadow:inset 0 0 0 1px var(--gold); }
.gacha-res .gr.best { box-shadow:inset 0 0 0 1px var(--gold), 0 0 0.6rem rgba(200,146,47,.35); }
.gacha-res .gr-tag { position:absolute; top:-0.42rem; right:0.5rem; font-size:.6rem; font-weight:800;
  padding:0.0625rem 0.375rem; border-radius:62.4375rem; background:var(--gold); color:var(--gold-shine); }
.gacha-res .gr-tag.g { background:var(--gold-line); color:var(--gold-ink); }
.pool-list { display:grid; gap:0.375rem; margin-top:0.625rem; }
.pool-row { display:flex; align-items:center; gap:0.5rem; padding:0.5rem 0.625rem;
  border-radius:0.625rem; background:var(--bg); border:1px solid var(--line); }
.pool-row.t-g { border-color:var(--gold-line); background:var(--gold-soft); }
.pool-row.t-r { border-color:var(--gold); background:var(--gold-shine); }
.pool-row .pr-ico { font-size:1.15rem; line-height:1; flex:none; }
.pool-row .pr-n { font-size:.8rem; font-weight:800; flex:none; display:flex; align-items:center; gap:0.25rem; }
.pool-row .pr-tag { font-style:normal; font-size:.58rem; font-weight:800; padding:0.0625rem 0.3125rem;
  border-radius:62.4375rem; background:var(--gold); color:var(--gold-shine); }
.pool-row .pr-tag.g { background:var(--gold-line); color:var(--gold-ink); }
.pool-row .pr-d { flex:1; min-width:0; font-size:.7rem; color:var(--sub); overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.pool-row .pr-p { font-size:.78rem; color:var(--gold-ink); flex:none; }

/* ---------- 扭蛋图鉴 / 好运符 / 加速沙漏（2026-10-14 第三批） ---------- */
.c-lucky { color:var(--ok); }
.pity-row .btn.ghost.sm.lucky { border-color:var(--ok); color:var(--ok); }
.dex-row { display:flex; align-items:center; gap:0.5rem; padding:0.5rem 0.625rem;
  border:1px solid var(--line); border-radius:0.625rem; background:var(--card); }
.dex-row.t-g { border-color:var(--gold-line); background:var(--gold-soft); }
.dex-row.t-r { border-color:var(--gold); background:var(--gold-shine); }
.dex-row.lock { opacity:.5; }
.dex-row .dx-ico { font-size:1.15rem; line-height:1; flex:none; }
.dex-row .dx-n { font-size:.8rem; font-weight:800; flex:none; }
.dex-row .dx-d { flex:1; min-width:0; font-size:.7rem; color:var(--sub); overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
/* 探险里「立刻回来」和时间提示并排平分 */
.exped .gacha-btns .btn { flex:1; }

/* 抽奖结果 */
.gacha-res { display:grid; gap:0.5rem; max-height:54vh; overflow:auto; }
.gacha-res.multi { grid-template-columns:repeat(auto-fill,minmax(12rem,1fr)); }
.gacha-res .gr { display:flex; align-items:center; gap:0.625rem; padding:0.625rem 0.75rem; border-radius:0.75rem;
  background:var(--bg); border:1px solid var(--line); animation:popin .3s backwards; }
.gacha-res .gr:nth-child(2) { animation-delay:.05s } .gacha-res .gr:nth-child(3) { animation-delay:.1s }
.gacha-res .gr:nth-child(4) { animation-delay:.15s } .gacha-res .gr:nth-child(5) { animation-delay:.2s }
.gacha-res .gr:nth-child(n+6) { animation-delay:.24s }
.gacha-res .gr b { font-size:.85rem; }
.gacha-res .gr .sub { font-size:.72rem; margin-top:0.0625rem; }
.gacha-res .gr-ico { font-size:1.5rem; line-height:1; flex:none; }
@keyframes popin { from { opacity:0; transform:scale(.86) } }

/* ★★ v105（2026-10-18）：头像框样式整块删除
   —— 用户定「不使用头像了」，人像头像与头像框一起去掉。
   删掉的是：.av 基础圆底、.av::after 光圈、十款 .af-*（star/flower/crown/flame/rainbow
   + aurora/scholar/galaxy/comet/phoenix）与 @keyframes fr-breathe。
   ⚠ 连 .av 基础类一起删，是因为它已经没有任何使用者：
      core.js 的 avatarHtml() 现在只把 emoji 原样返回，不再生成 <span class="av">，
      sizeCls（av-sm / av-lg）参数也随之失效。留着就是没人用的死样式。
   ⚠ 别把 .pf-av（「我的」资料卡那个大圈）一起删了 —— 它是另一个类，还在用。 */

/* 首页学习伙伴
   ⚠ 这条 bar 长在 hero 卡里，旧版靠「半透明白底 + 白字」压在深色渐变上；
   hero 卡 2026-10-18 改成纸白底后，半透明白底等于没有边界、白字也直接消失。
   现统一改成主色浅底 + 主色描边，文字回到正文色。 */
.petbar { display:flex; align-items:center; gap:0.5rem; margin-top:0.75rem; padding:0.5rem 0.625rem;
  border-radius:0.75rem; background:var(--brand-soft); border:1px solid var(--brand-line); position:relative; z-index:1; cursor:pointer; }
.petbar:active { background:var(--bg); }
.pet-ico { font-size:1.5rem; line-height:1; flex:none; }
.pet-name { font-size:.72rem; font-weight:800; color:var(--ink); }
.pet-line { font-size:.74rem; color:var(--sub); margin-top:0.0625rem; line-height:1.35; }
.pet-go { color:var(--sub); font-size:1rem; flex:none; }

/* 🍽 伙伴饱食度（2026-10-17：可以投喂了）
   ⚠ 这条 bar 长在 hero 卡里：旧版 hero 是深色渐变，所以轨道用半透明黑、填充用纯白。
   hero 纸感化后必须反过来 —— 轨道用描边色、填充用主色（饿了转警示色）。 */
.petbar { flex-wrap:wrap; }            /* 极窄屏宁可换行也不横向溢出 */
.pet-sat { display:flex; align-items:center; gap:0.375rem; margin-top:0.1875rem; }
.pet-sat .ps-t { font-size:.68rem; color:var(--sub); white-space:nowrap; flex:none; }
.pet-sat .ps-bar { flex:1 1 3rem; min-width:2.5rem; height:0.3125rem; background:var(--line); border-radius:62.4375rem; overflow:hidden; }
.pet-sat .ps-bar > i { display:block; height:100%; border-radius:62.4375rem; background:var(--brand); transition:width .4s ease; }
.petbar.hung .pet-sat .ps-bar > i { background:var(--warn); }
.pet-feed { flex:none; padding:0.25rem 0.5rem; font-size:.7rem; border-radius:0.5rem; background:rgba(255,255,255,.9); color:#3a3556; box-shadow:none; }

/* 投喂弹窗：一行一份食物，图标 + 名字描述 + 「喂一口」 */
.fd-head { display:flex; align-items:center; gap:0.625rem; margin-bottom:0.5rem; }
.fd-av { font-size:1.75rem; line-height:1; flex:none; }
.fd-list { margin-top:0.75rem; }
.fd-row { display:flex; align-items:center; gap:0.625rem; padding:0.5rem; border:1px solid var(--line); border-radius:0.625rem; margin-top:0.5rem; }
.fd-row.none { opacity:.55; }
.fd-ico { font-size:1.375rem; line-height:1; flex:none; }
.fd-b { flex:1; min-width:0; }
.fd-b > b { font-size:.86rem; }
.fd-b .sub { font-size:.72rem; line-height:1.45; margin-top:0.125rem; }

/* 商城「伙伴 / 投喂」区的投喂提示条 —— 样式同 .shop-note，但故意不同类名：
   那条深夜模式说明是按「页面上第一条 .shop-note」取的，共用类名会被误读到。 */
.shop-feedbox { margin-top:0.625rem; padding:0.5rem 0.625rem; font-size:.72rem; line-height:1.6; border-radius:0.5rem; background:var(--brand-soft); color:var(--ink); }
.shop-feedbox b { color:var(--brand); }
.fb-top { display:flex; align-items:center; gap:0.5rem; justify-content:space-between; flex-wrap:wrap; }
.fb-top > span { min-width:0; flex:1 1 12rem; }
.fb-top .btn { flex:none; }

/* 商城分区切换（三个按钮平分） */
/* ★ v115：分类从 4 个变 5 个（加了「背包」），沿用原来的 0.6875rem 内边距会把
   「装扮」挤成「装 / 扮」两行 —— 390px 宽下每个按钮只剩约 71px。
   三处一起收：不换行 + 收窄左右内边距 + 字略小一点点。
   ⚠ 别只写 white-space:nowrap 就完事：内容真的超宽时它会直接溢出压到隔壁按钮上。

   ★ v121：240px 这种极窄屏（_qin 的 UC 小屏档）实测**横向溢出 29px** ——
     5 个「emoji + 两字」最小内容宽约 270px，flex:1 压不下去，整页被撑出横向滚动。
     这里允许换行：240px 会折成两排（3+2），320px 以上仍然是一排（5×54 ≈ 270 < 320），
     所以**正常手机的分段栏观感完全不变**，只有真的放不下时才折行。 */
.shop-seg { margin-top:0.75rem; flex-wrap:wrap; }
.shop-seg button { flex:1; white-space:nowrap; padding-left:0.1875rem; padding-right:0.1875rem; font-size:0.72rem; }

/* ---------- 商城顶部「玩」的两块：扭蛋 + 每日好运签 ---------- */
.fun-row { display:grid; grid-template-columns:1fr; gap:0.5rem; }
html:not([data-lay="narrow"]) .fun-row { grid-template-columns:repeat(auto-fit,minmax(20rem,1fr)); }
.fun-row .gacha { margin-top:0; }

.omen-box { padding:0.75rem 0.8125rem; border-radius:0.875rem;
  background:var(--gold-soft); border:1px solid var(--gold-line); }
.omen-box.ready .gacha-ico { animation:omenBob 2.6s ease-in-out infinite; }
@keyframes omenBob { 0%,100% { transform:translateY(0) rotate(0) } 50% { transform:translateY(-0.1875rem) rotate(-7deg) } }

/* ---------- 伙伴探险 ---------- */
.exped { margin-top:0.5rem; padding:0.75rem 0.8125rem; border-radius:0.875rem;
  background:var(--brand-soft); border:1px solid var(--brand-line); }
.exped.done { border-color:var(--ok); border-style:dashed; }
.exped.done .gacha-ico { animation:omenBob 1.8s ease-in-out infinite; }
.exped .gacha-btns .ex-btn { flex:1; flex-direction:column; gap:0.0625rem; padding:0.4375rem 0.25rem; line-height:1.25; }
.ex-btn .ex-ico { font-size:1.05rem; }
.ex-btn i { font-style:normal; font-size:.66rem; opacity:.72; font-weight:600; }

/* ---------- 签 / 探险结果弹窗 ---------- */
.omen-res { text-align:center; padding:0.5rem 0 0.25rem; }
.omen-res .or-ico { font-size:3rem; line-height:1; animation:popin .35s; }
.omen-res .or-lv { font-size:1.15rem; font-weight:800; color:var(--brand); margin-top:0.375rem; letter-spacing:0.1875rem; }
.omen-res .or-tip { font-size:.85rem; margin-top:0.4375rem; line-height:1.65; color:var(--ink); }
.omen-res .or-pts { display:inline-block; margin-top:0.75rem; padding:0.25rem 0.875rem; border-radius:62.4375rem;
  background:var(--gold-soft); border:1px solid var(--gold-line); color:var(--gold-ink); font-weight:800; font-size:.85rem; }
.omen-res .or-extra { margin-top:0.5rem; font-size:.8rem; color:var(--ok); font-weight:700; }

/* ---------- 个性签名 ----------
   ⚠ 这两条旧版写的是「白色半透明」（因为压在 hero 的深色渐变上）。
   hero 卡改成纸白底后白字会直接消失，必须回到灰色斜体。 */
.motto { margin-top:0.5rem; font-size:.82rem; color:var(--sub); font-weight:700; font-style:italic; }
.hero-motto { font-size:.76rem; color:var(--sub); margin-top:0.3125rem; font-style:italic; }

/* 提示卡排掉的选项 */
.opt.hinted { opacity:.32; text-decoration:line-through; }

/* ---------- 答题连击 ---------- */
.combo-hud { display:inline-flex; align-items:center; margin-left:0.5rem; padding:0.0625rem 0.4375rem;
  border-radius:62.4375rem; background:var(--gold-soft); border:1px solid var(--gold-line);
  color:var(--gold-ink); font-size:.72rem; font-weight:800; white-space:nowrap;
  animation:comboPop .34s cubic-bezier(.2,1.5,.5,1); }
.combo-tag { display:inline-block; margin-left:0.4375rem; padding:0.0625rem 0.4375rem;
  border-radius:62.4375rem; background:var(--gold-soft); border:1px solid var(--gold-line);
  color:var(--gold-ink); font-size:.74rem; font-weight:800; vertical-align:middle;
  animation:comboPop .34s cubic-bezier(.2,1.5,.5,1); }
/* 重复递减提示（v97）：♻️ 第 2 次 · 只给 30%
   ★ 刻意做成**素文字**而不是彩色胶囊：它是"说明"不是"奖励"，
     跟旁边金色的连击胶囊挨在一起时不能抢眼，也不违反「小标签不用胶囊」。
   ⚠ 老内核铁律：不认 var() 会丢弃整条声明 → 颜色只留一个 var，别叠 fallback 链。 */
.rep-tag { display:inline-block; margin-left:0.4375rem; color:var(--sub);
  font-size:.74rem; font-weight:700; vertical-align:middle; white-space:nowrap; }
/* 结算页的重复递减说明（v97）：只在"这一组里真有重复题"时才出现。
   ★ 刻意做成**素卡片 + 左侧竖条**（跟 hero 卡同一套语言），不用彩色警示块：
     它不是错误提示，是一条规则说明，不该让人以为自己做错了什么。 */
.rep-note { margin-top:0.625rem; padding:0.625rem 0.75rem; border-radius:0.75rem;
  background:var(--bg); border-left:0.1875rem solid var(--brand);
  font-size:.82rem; line-height:1.75; color:var(--sub); }
.combo-best { margin-top:0.625rem; text-align:center; font-size:.86rem; font-weight:800; color:var(--gold-ink); }
.combo-best.weak { font-weight:700; color:var(--sub); }
@keyframes comboPop { from { transform:scale(.62); opacity:0; } to { transform:scale(1); opacity:1; } }

/* 动画碎片 */
.confetti { position:fixed; top:-0.75rem; font-size:1.2rem; z-index:400; pointer-events:none; animation:fall linear forwards; }
@keyframes fall { to { transform:translateY(105vh) rotate(340deg); opacity:.7; } }

/* 学习步骤条 */
.steps { display:flex; gap:0.375rem; margin-bottom:0.875rem; }
.steps .st { flex:1; text-align:center; font-size:.68rem; font-weight:700; color:var(--sub); padding:0.4375rem 0.125rem; border-radius:62.4375rem; background:var(--bg); }
.steps .st.on { background:var(--brand); color:#fff; }
.steps .st.done { background:var(--ok-soft); color:var(--ok); }

.empty { text-align:center; padding:2.125rem 0.625rem; color:var(--sub); font-size:.85rem; }
.empty .e-ico { font-size:2.6rem; display:block; margin-bottom:0.625rem; }
::-webkit-scrollbar { width:0; height:0; }

/* ---------- 整卷模拟 ---------- */
.opt.sel{border-color:var(--brand);background:var(--brand-soft)}
.mock-timer{font-variant-numeric:tabular-nums;font-weight:800}
.mock-timer.low{color:var(--bad);animation:blink 1s infinite}
@keyframes blink{50%{opacity:.4}}
.ansgrid{display:grid;grid-template-columns:repeat(auto-fill,minmax(2.625rem,1fr));gap:0.5rem}
.ansgrid button{padding:0.5625rem 0;border-radius:0.625rem;border:1px solid var(--line);background:var(--card);font-weight:700;color:var(--ink)}
.ansgrid button.on{background:var(--brand);color:#fff;border-color:transparent}
.sec-score{display:flex;justify-content:space-between;gap:0.5rem;padding:0.5625rem 0.125rem;border-bottom:1px dashed var(--line);font-size:.85rem}
.spark{display:flex;align-items:flex-end;gap:0.1875rem;height:2.875rem;margin:0.5rem 0 0.25rem}
.spark i{flex:1;background:var(--brand);border-radius:0.1875rem 0.1875rem 0 0;opacity:.7;min-height:0.25rem}

/* ---------- 单词消消乐（英中配对消除） ---------- */
.mg-head { display:flex; align-items:center; gap:0.5rem; margin-bottom:0.75rem; }
.mg-stat { flex:1; text-align:center; background:var(--card); border:1px solid var(--line); border-radius:var(--radius-s); padding:0.5rem 0.25rem; }
.mg-stat b { display:block; font-size:1.15rem; font-weight:800; font-variant-numeric:tabular-nums; }
.mg-stat span { font-size:.66rem; color:var(--sub); font-weight:700; }
.mg-stat.warn b { color:var(--warn); }
.mg-stat.bad b { color:var(--bad); }

/* 棋盘：3 列网格（格子更宽，避免长单词被挤断行） */
.mg-board { display:grid; grid-template-columns:repeat(3,1fr); gap:0.5rem; margin:0.125rem 0 0.875rem; }
.mg-tile {
  position:relative; display:flex; flex-direction:column; align-items:center; justify-content:center; text-align:center;
  min-height:4.125rem; padding:0.5rem 0.3125rem; border-radius:0.75rem;
  background:var(--card); border:1.5px solid var(--line);
  font-size:.82rem; font-weight:700; color:var(--ink); line-height:1.2;
  transition:transform .12s ease, background .15s ease, border-color .15s ease, opacity .2s ease;
  overflow-wrap:anywhere; word-break:break-word; -webkit-user-select:none; user-select:none;
}
.mg-tile .mg-en { font-size:.9rem; font-weight:800; letter-spacing:0.0125rem; }
.mg-tile .mg-cn { font-size:.8rem; font-weight:700; }
.mg-tile.zh { background:var(--brand-soft); }
.mg-tile:active { transform:scale(.95); }
.mg-tile.sel { border-color:var(--brand); background:var(--brand); color:#fff; box-shadow:0 0 0 2px var(--brand-glow); transform:scale(.97); }
.mg-tile.sel .mg-sub { color:rgba(255,255,255,.75); }
/* 副信息（音标 / 词性）单独一行、小字号，不与主文抢位 */
.mg-tile .mg-sub { display:block; font-size:.58rem; font-weight:600; color:var(--sub); margin-top:0.1875rem; line-height:1.15; }
/* 配对成功：淡出并腾位 */
.mg-tile.matched { pointer-events:none; animation:mgPop .38s ease forwards; }
@keyframes mgPop { 0%{transform:scale(1)} 45%{transform:scale(1.14); background:var(--ok-soft); border-color:var(--ok)} 100%{transform:scale(.6); opacity:0} }
/* 配对失败：抖动 */
.mg-tile.bad { animation:shake .4s; border-color:var(--bad); background:var(--bad-soft); }
/* 空位占位（保持网格不塌） */
.mg-tile.gone { visibility:hidden; }

/* 连击飘字 */
.mg-fly { position:absolute; left:50%; top:42%; transform:translate(-50%,-50%);
  font-size:1.05rem; font-weight:800; color:var(--gold);
  text-shadow:0 1px 0 var(--gold-shine); pointer-events:none; animation:mgFly .8s ease-out forwards; z-index:5; }
@keyframes mgFly { 0%{opacity:0; transform:translate(-50%,-30%) scale(.7)} 25%{opacity:1; transform:translate(-50%,-50%) scale(1.1)} 100%{opacity:0; transform:translate(-50%,-140%) scale(1)} }

.mg-hint { text-align:center; font-size:.78rem; color:var(--sub); margin:0.25rem 0 0.625rem; }
.mg-combo { display:inline-block; margin-left:0.375rem; color:var(--gold-ink); font-weight:800; }
.mg-combo.hide { display:none; }

/* 结算 */
.mg-done { text-align:center; padding:0.375rem 0 0.125rem; }
.mg-done .mg-big { font-size:2.6rem; font-weight:800; color:var(--brand); font-variant-numeric:tabular-nums; }
.mg-done .mg-dsub { font-size:.82rem; color:var(--sub); margin-top:0.125rem; }

/* 入口行内的小进度条（单词页） */
.mg-entry-badge { font-variant-numeric:tabular-nums; }

/* ============================================================================
   ★ 响应式排版（用户要求：界面不是「原样等比放大」，而是排版随屏幕大小改变）
   ----------------------------------------------------------------------------
   由 js/fit.js 按屏幕宽度给 <html> 打 data-lay 档位，这里按档位重排：
     narrow  <760px   手机 / 竖屏平板 —— 下列规则一条都不命中，渲染与旧版完全一致
     medium  760-1099 平板 / 横屏 —— 卡片两列
     wide    1100-1499 笔记本 —— 卡片两列 + 入口列表两列
     desk    ≥1500     台式大屏 —— 卡片三列 + 入口列表两列

   为什么用 data-lay 而不是 @media：
     档位判定只在 js/fit.js 一处，CSS 与 JS 不会各说各话（曾出现曲线两处不一致的坑）；
     且 data-lay 由同一个 apply() 维护，resize 时与 --ui-scale/--ui-max 原子更新，不会闪。
   所有规则一律用 :not([data-lay="narrow"]) 起手，保证手机端零命中。
   ============================================================================ */

/* ---------- ① 卡片区：首页 / 我的 等多卡片页面 → 多列瀑布流 ----------
   为什么用 CSS columns（瀑布流）而不是 grid：
     grid 是按「行」对齐的 —— 同行的卡片会被最高的那张撑高，短卡片下半截就空一大片；
     首页三张卡（周任务 395 / 月任务 507 / 继续学习 263）参差不齐正是这个原因。
     columns 是竖着「先填满第一列再填第二列」，每张卡保持自然高度、像砖墙一样错落，
     没有行对齐的空洞，也不需要给每张卡单独算位置。
   代价：阅读顺序变成「先上后下再右列」（对卡片式首页可接受，本来就不是线性阅读）。
   ⚠★ 知识点页（带 .mindbox）必须排除 —— 见本节 ①b，否则会出现「左边饱满、右边空空如也」。 */
html:not([data-lay="narrow"]) #view:has(> .card):not(:has(> .lrow)):not(:has(> .lvpath)):not(:has(> .mindbox)) {
  display:block;                       /* 覆盖可能存在的 grid */
  column-gap:1rem;
}
/* 列数：交给浏览器按可用宽度自动算。
   · medium（平板 / 横屏，底部栏）→ 固定 2 列；
   · wide / desk（有左侧导航栏）→ 用 column-width 让**列数随屏幕变多**：
     内容区越宽列越多，不必为每个尺寸写死一个数。
   20rem ≈ 每列 370~400px，刚好放得下「图标 + 标题 + 数值/徽章 + 按钮」四件套而不折行
   （早先写死 3 列、每列仅 414px 时，「词汇总复习测 ≥ 70%」会被拦腰折行）。
   实测：1280→3 列 · 1440→3 列 · 1920→4 列 · 2560→5 列。 */
html[data-lay="medium"] #view:has(> .card):not(:has(> .lrow)):not(:has(> .lvpath)):not(:has(> .mindbox)) {
  column-count:2;
}
html[data-lay="wide"] #view:has(> .card):not(:has(> .lrow)):not(:has(> .lvpath)):not(:has(> .mindbox)),
html[data-lay="desk"] #view:has(> .card):not(:has(> .lrow)):not(:has(> .lvpath)):not(:has(> .mindbox)) {
  column-width:20rem;
}
/* 卡片不能被拦腰截断到两列之间 */
html:not([data-lay="narrow"]) #view:has(> .card):not(:has(> .lrow)):not(:has(> .lvpath)):not(:has(> .mindbox)) > .card {
  break-inside:avoid; -webkit-column-break-inside:avoid; page-break-inside:avoid;
  display:block; width:auto; margin:0 0 0.875rem 0;
}
/* 占整行的横向卡（英雄区 / 学科栏 / 锁定横幅）：在 columns 里用 column-span 跨列 */
html:not([data-lay="narrow"]) #view > .card.hero-card,
html:not([data-lay="narrow"]) #view > .banner,
html:not([data-lay="narrow"]) #view > .card.subj-bar,
html:not([data-lay="narrow"]) #view > .card-stat,
html:not([data-lay="narrow"]) #view > .pagehead {
  column-span:all; -webkit-column-span:all;
  margin-bottom:0.875rem;
}

/* ---------- ①b 知识点 / 语法详情页（带 .mindbox）：不参与瀑布流 ----------
   2026-10-19 用户截图：桌面宽屏下「左边饱满，右边空空如也」。
   根因是它套用了 ① 的瀑布流（column-width:20rem）—— 页头 + 图示卡 + 要点卡被切成
   三列又高又窄的竖条，最后没填满的列就是右侧那片空白；要点卡里的 .gp 又被
   「7·3 要点块」切成了 19rem 的小格子，整页像被切碎的纸片。
   正确做法：
     · 图示卡（.mindbox）跨整行 —— 思维导图最怕被挤窄，宽度全给它；
     · 要点卡恢复成一整块，要点按 auto-fit 铺满整行，读到哪算到哪；
     · 手机上（narrow）一条都不命中，保持原有单列堆叠。 */
html:not([data-lay="narrow"]) #view:has(> .mindbox) {
  display:grid; grid-template-columns:minmax(0,1fr);
  gap:0.875rem; align-content:start;
  column-count:auto; column-width:auto;
}
html:not([data-lay="narrow"]) #view:has(> .mindbox) > .pagehead { margin-bottom:0; }
html:not([data-lay="narrow"]) #view:has(> .mindbox) > .mindbox { margin-bottom:0; }
/* 要点卡本身是网格容器（见 7·3），这里只保证它占满一整行 */
html:not([data-lay="narrow"]) #view:has(> .mindbox) > .card {
  break-inside:auto; width:auto; margin:0;
}
/* 图示卡里的 SVG 可以比正文宽 —— 宽屏下 32rem 太小，根本看不清字 */
html[data-lay="wide"] #view > .mindbox .mind-svg,
html[data-lay="desk"] #view > .mindbox .mind-svg { max-width:44rem; }
html[data-lay="medium"] #view > .mindbox .mind-svg { max-width:36rem; }
/* 内容特别长的卡（今日必做任务 / 学习数据 / 设置）跨整行，避免把单列拉得老长 */
html:not([data-lay="narrow"]) #view > .card.card-tall,
html:not([data-lay="narrow"]) #view > .card.card-wide {
  column-span:all; -webkit-column-span:all; margin-bottom:0.875rem;
}
/* 混入的非卡片块（空态提示）也跨列 */
html:not([data-lay="narrow"]) #view:has(> .card) > .empty {
  column-span:all; -webkit-column-span:all;
}

/* ---------- ② 入口列表（.lrow）：单词 / 听力 / 题库 → 自适应多列 ----------
   这里用 grid + auto-fill：**列数随可用宽度自动增长**，且每列等宽、最后一行不满时
   也不会像 flex 那样被拉变形。18rem 比卡片区的 20rem 略窄 —— 入口行内容少
   （图标 + 标题 + 副标题 + 箭头），窄一点更紧凑。
   实测列数：1100→2 · 1280→2 · 1440→3 · 1920→4 · 2560→5。 */
html[data-lay="wide"] #view:has(> .lrow),
html[data-lay="desk"] #view:has(> .lrow) {
  display:grid; grid-template-columns:repeat(auto-fill, minmax(18rem, 1fr)); gap:0.75rem;
  /* ★ 必须 align-content:start —— #view 是 flex:1、高度被撑满整屏，grid 默认 align-content:normal
     等同 stretch，会把**所有行按剩余高度摊开**：卡片与 .lrow 都被拉高，内容居中留出大片空白。
     实测「词汇进度」卡被撑到 218px（内容其实只有 69px），这就是它看着空的原因。
     （行内仍是 align-items 默认值，同一行的卡片照样等高，不会参差。） */
  align-content:start;
}
html[data-lay="wide"] #view:has(> .lrow) > .lrow,
html[data-lay="desk"] #view:has(> .lrow) > .lrow { margin:0; }
/* ★ 列表页里**只有 .lrow 是网格项**，其余直接子元素（页头 / 说明卡 / banner /
   分节小标题 / 宽按钮 / 空态）一律跨整行。
   早先只给 .card 和 .pagehead 加了 grid-column:1/-1，结果「模拟卷」页的
   「📑 卷面结构」小标题、「📊 模考历史」小标题、说明文字被当成普通网格项，
   掉进第 2、3 列，和行列表并排错位（实测 1920 下挤成一团）。改成通配更稳。 */
html[data-lay="wide"] #view:has(> .lrow) > *:not(.lrow),
html[data-lay="desk"] #view:has(> .lrow) > *:not(.lrow) {
  grid-column:1 / -1; margin:0;
}
/* 分节小标题不能紧贴上面的行列表 */
html[data-lay="wide"] #view:has(> .lrow) > .mt16,
html[data-lay="desk"] #view:has(> .lrow) > .mt16 { margin-top:0.5rem !important; }

/* ---------- ③ 学习页（学新词 / 复习到期）→ 单列居中「专注模式」 ----------
   原来是 repeat(2, 1fr)：闪卡占一半、按钮占另一半，1920 下两栏各 796px ——
   闪卡里只有「一个单词 + 音标」孤零零居中，右侧按钮也被拉成 796px 的一条。
   而且 #view 是 flex:1 撑满整屏，grid 默认 align-content:normal(=stretch) 把两行
   按剩余高度摊开（行高 375/550），内容被顶到屏幕中间、上面一大片空。
   改成：单列限宽居中 + align-content:start，就是标准的「一张闪卡 + 下面按钮」专注模式。 */
html[data-lay="wide"] #view:has(> .wcard) ,
html[data-lay="desk"] #view:has(> .wcard) {
  display:grid; grid-template-columns:minmax(0,34rem);
  justify-content:center; align-content:start; align-items:start; gap:0.875rem;
}
html[data-lay="wide"] #view > .pagehead,
html[data-lay="desk"] #view > .pagehead { grid-column:1 / -1; }

/* ---------- ③b 整卷模拟作答区（.pk-flow）：不参与瀑布流 ----------
   ★ v133：书面表达的反馈卡里有「范文 / 范文译文」两块，被 CSS 多栏切开后
     英文在左、中文在右，读的时候要跳来跳去（v132 知识点页刚踩过同一个坑）。
   所以把作答区整体包一层 .pk-flow，宽屏改成单列网格、内容限宽居中，
   与闪卡页（.wcard）同一套做法，但**宽度给到 46rem**：
   题干 + 输入框 + 范文卡都要横向空间，34rem 会把作文挤成竖条。 */
html[data-lay="wide"] #view:has(> .pk-flow),
html[data-lay="desk"] #view:has(> .pk-flow) {
  display:grid; grid-template-columns:minmax(0,46rem);
  justify-content:center; align-content:start; align-items:start; gap:0.875rem;
  column-count:auto; column-width:auto;
}
html[data-lay="wide"] #view:has(> .pk-flow) > .pagehead,
html[data-lay="desk"] #view:has(> .pk-flow) > .pagehead { grid-column:1 / -1; }
html[data-lay="wide"] #view:has(> .pk-flow) > .pbar,
html[data-lay="desk"] #view:has(> .pk-flow) > .pbar,
html[data-lay="wide"] #view:has(> .pk-flow) > .banner,
html[data-lay="desk"] #view:has(> .pk-flow) > .banner { grid-column:1 / -1; }
.pk-flow > .qmeta:first-child { margin-top:0; }

/* ---------- ④ 语法 / 知识点 阅读页：正文限宽，避免超宽屏一行过长 ---------- */
html[data-lay="desk"] #view > .card:not(.hero-card) > .sub,
html[data-lay="desk"] #view > .card:not(.hero-card) > .card-title { max-width:60rem; }

/* ---------- ⑤ 桌面端：左侧导航栏 + 右侧内容区铺开 ★ 2026-10-13 第二轮「换排版」 ----------
   用户反馈两条：①「左右侧空白地方都没用上」②「用电脑打开大得要死」。
   前几轮的做法都是「把手机界面等比放大、居中」，结果两侧各留一大片空白、字还特别大。
   这一轮换掉整个布局语言，用桌面 Web 应用的常规做法：
     · 底部 Tab 栏 → 左侧固定导航栏（竖排、图标 + 文字）——左边那片空白真正被用上；
     · #app 让出侧栏宽度，内容区横向铺开，不再居中留白；
     · 字号锁在 1.2 倍左右（见 js/fit.js 的 ANCHORS），空间交给「更多列」而不是「更大的字」。
   全部规则限定在 wide / desk 两档，手机与平板（narrow / medium）一条都不命中。 */
html[data-lay="wide"] #app,
html[data-lay="desk"] #app {
  max-width:none;                /* 不再受 --ui-max 约束，内容随屏宽铺开 */
  margin-left:var(--side-w);     /* 给左侧导航栏让位 */
  margin-right:0;
  box-shadow:none;               /* 铺开后不再有「居中一张卡」的立体感，去掉投影 */
}
html[data-lay="wide"] #tabbar,
html[data-lay="desk"] #tabbar {
  top:0; bottom:0; left:0; right:auto;
  width:var(--side-w); max-width:none;
  transform:none;                /* 覆盖手机端的 translateX(-50%) 居中 */
  height:auto;
  padding:0.75rem 0.625rem 1rem;                              /* 兜底（不含 env） */
  padding-bottom:calc(1rem + env(safe-area-inset-bottom,0px));
  flex-direction:column; align-items:stretch; justify-content:flex-start; gap:0.1875rem;
  background:var(--card);
  border-top:none; border-right:1px solid var(--line);
}
/* 侧栏顶部应用名：纯 CSS 生成，不改 DOM（手机端不出现） */
html[data-lay="wide"] #tabbar::before,
html[data-lay="desk"] #tabbar::before {
  content:"🎓 对口升学";
  display:block;
  font-size:1.02rem; font-weight:800; color:var(--brand); letter-spacing:0.02rem;
  padding:0.5rem 0.75rem 1rem;
}
/* 导航项：由「竖排图标 + 文字」改为「横排图标 + 文字、左对齐」 */
html[data-lay="wide"] #tabbar .tab,
html[data-lay="desk"] #tabbar .tab {
  flex:none;
  flex-direction:row; align-items:center; justify-content:flex-start; gap:0.6875rem;
  padding:0.6875rem 0.75rem; border-radius:0.6875rem; font-size:0.9rem;
}
html[data-lay="wide"] #tabbar .tab .t-ico,
html[data-lay="desk"] #tabbar .tab .t-ico { font-size:1.2rem; }
html[data-lay="wide"] #tabbar .tab.active,
html[data-lay="desk"] #tabbar .tab.active { background:var(--brand-soft); }
html[data-lay="wide"] #tabbar .tab.active .t-ico,
html[data-lay="desk"] #tabbar .tab.active .t-ico { transform:none; }
/* 导航栏移到左侧后，底部不必再给底栏留空间 */
html[data-lay="wide"] #view,
html[data-lay="desk"] #view {
  padding:1.25rem 1.5rem;
  padding-bottom:1.5rem;
}
/* 弹窗：手机端是「底部抽屉」，桌面端改成「居中对话框」 */
html[data-lay="wide"] .modal-mask,
html[data-lay="desk"] .modal-mask { align-items:center; padding:1.5rem; }
html[data-lay="wide"] .modal,
html[data-lay="desk"] .modal { max-width:34rem; border-radius:1.25rem; }
/* 「我的」页个人资料卡：桌面端由「上下居中堆叠」改为「左图标 + 右信息」横向卡。
   原来是竖着居中一列，铺满 1690px 后中间只有窄窄一行字、两边全是渐变底色，显得空；
   改横排后卡片高度从 ~200px 降到 ~90px，同样宽度下就充实多了。
   ⚠ 必须带 !important：① display 会被上面「卡片区分栏」那条
   `#view:has(> .card)… > .card { display:block }` 盖住（它的 :has() 链特异性更高）；
   ② text-align 是行内样式 style="text-align:center"，只能靠 !important 压过。 */
html[data-lay="wide"] #view > .hero-card.hero-profile,
html[data-lay="desk"] #view > .hero-card.hero-profile {
  display:grid !important;
  grid-template-columns:auto minmax(0,1fr);
  align-items:center;
  column-gap:1.5rem; row-gap:0.3rem;
  text-align:left !important;
  padding:1.25rem 1.5rem !important;
}
html[data-lay="wide"] #view > .hero-card.hero-profile > div:first-child,
html[data-lay="desk"] #view > .hero-card.hero-profile > div:first-child {
  grid-row:1 / span 6; font-size:2.75rem !important; line-height:1;
}
html[data-lay="wide"] #view > .hero-card.hero-profile > h3,
html[data-lay="desk"] #view > .hero-card.hero-profile > h3 { margin:0; font-size:1.15rem; }
html[data-lay="wide"] #view > .hero-card.hero-profile > .pbar,
html[data-lay="desk"] #view > .hero-card.hero-profile > .pbar { margin:0.4rem 0 0 !important; max-width:24rem !important; }
/* 快捷入口 4 连按钮：宽内容区下不要摊成 4 个大宽块 */
html[data-lay="wide"] .quick,
html[data-lay="desk"] .quick { max-width:34rem; }

/* ---------- ⑥ 最大化窗口后的细节优化（2026-10-13 第四轮） ---------- */

/* 6·1 把顶栏的「⚡积分 / 🔥打卡 / 👤头像」移到左侧导航栏**底部**。
   原因：侧栏只有 5 个导航项，占不满一屏高，下面一大片空白（窗口最大化后尤其刺眼）。
   做法：纯 CSS 把 .topchips 从顶栏「摘」出来 —— position:fixed 相对视口定位，
   直接落在侧栏区域底部，DOM 与 JS 一行都不用改（#chip-streak/#chip-points/#btn-me 的引用不受影响）。
   注意：#topbar 是 position:sticky，sticky 不会成为 fixed 的包含块，所以这里能正常相对视口定位。 */
html[data-lay="wide"] .topchips,
html[data-lay="desk"] .topchips {
  position:fixed; left:0; bottom:0; width:var(--side-w); z-index:61;
  flex-direction:column; align-items:stretch; gap:0.375rem;
  padding:0.875rem 0.625rem;
  padding-bottom:calc(0.875rem + env(safe-area-inset-bottom,0px));
  background:var(--card); border-top:1px solid var(--line);
}
html[data-lay="wide"] .topchips .chip,
html[data-lay="desk"] .topchips .chip {
  display:block; text-align:center; padding:0.4375rem 0.5rem; font-size:0.82rem;
}
html[data-lay="wide"] .topchips .avatar,
html[data-lay="desk"] .topchips .avatar {
  width:100%; height:2.25rem; border-radius:0.6875rem;
}
/* 侧栏导航项下方留出 chips 的高度，避免长屏时导航项与底部信息挤在一起 */
html[data-lay="wide"] #tabbar,
html[data-lay="desk"] #tabbar { padding-bottom:11rem; }

/* 6·2 顶栏：chips 搬走后只剩「当前学科」。
   ⚠ 这里必须把 #topbar 的 z-index 抬到侧栏（60）之上，否则 chips 点不到：
      #topbar 是 position:sticky + z-index:50 → **它自己就是一个层叠上下文**，
      .topchips 的 z-index:61 只在这个上下文「内部」有效，整个顶栏仍排在 #tabbar(60) 下面。
      实测报错「<nav id="tabbar"> intercepts pointer events」，点击头像/积分/打卡全部失效。
      #topbar 在 #app 内部（已 margin-left 让出侧栏），抬高不会盖住侧栏本身。 */
html[data-lay="wide"] #topbar,
html[data-lay="desk"] #topbar { padding:0 2rem; z-index:62; }
html[data-lay="wide"] #topbar .brand,
html[data-lay="desk"] #topbar .brand { font-size:1.15rem; }

/* 6·3 学科切换栏：4 个按钮各占满 1/4 屏宽（桌面 400px 一个）显得很空，
   改成「左侧文字标签 + 右侧并排按钮」，一眼能看出这一栏是干什么的。 */
html[data-lay="wide"] .subj-bar,
html[data-lay="desk"] .subj-bar {
  display:flex; align-items:center; gap:0.875rem; padding:0.625rem 1rem !important;
}
html[data-lay="wide"] .subj-bar::before,
html[data-lay="desk"] .subj-bar::before {
  content:"切换学科"; flex:none; font-size:0.84rem; font-weight:700; color:var(--sub);
}
html[data-lay="wide"] .subj-bar > .row,
html[data-lay="desk"] .subj-bar > .row { flex:1; min-width:0; }
/* 学科按钮的副标题（关卡数 · 题量）：手机档隐藏，平板及以上显示 */
.subj-pill .sp-sub { display:none; }
html:not([data-lay="narrow"]) .subj-pill .sp-sub {
  display:block; font-size:0.62rem; font-weight:600; color:var(--sub); margin-top:0.0625rem;
}
/* 只有 desk（≥1500）按钮才够宽敞，才改横排「图标 · 学科名 · 副标题」；
   wide（1100~1499）每个按钮只有 ~175px，横排会把「计算机应用」挤到换行，反而更乱。 */
html[data-lay="desk"] .subj-pill {
  flex-direction:row; align-items:center; justify-content:center; gap:0.5rem;
  font-size:1.2rem; padding:0.5rem 0.75rem;
}
html[data-lay="desk"] .subj-pill .sp-sub { font-size:0.72rem; margin-top:0; }
/* 横排后学科名要够大，否则会比副标题还小（.subj-pill div 基础只有 .68rem） */
html[data-lay="desk"] .subj-pill > div { font-size:0.88rem; }

/* 6·4 内容区左右留白稍加宽：1690px 内容贴到离屏幕边只有 24px，太挤；
   加到 2rem 后仍有 1600px+ 的可用宽度，但卡片不再像贴边。 */
html[data-lay="wide"] #view,
html[data-lay="desk"] #view {
  padding:1.5rem 2rem;
  padding-bottom:2rem;
}

/* 6·5 首页问候横幅在宽屏下给足内边距，撑起第一屏的视觉重量 */
html[data-lay="wide"] #view > .hero-card,
html[data-lay="desk"] #view > .hero-card { padding:1.375rem 1.75rem; }
html[data-lay="desk"] #view > .hero-card.hero-profile { padding:1.5rem 1.75rem !important; }
/* 整行宽卡片的「卡内行式列表」再分栏 —— 这是宽屏最关键的一步。
   卡片铺到 1600px 后，若内部仍是单列行，每行就成了「文字在左、按钮/徽章在右、
   中间一大片空」，比窄屏还难看。这里让行列表按 22rem（≈430px）自适应列数：
   1920 下约 3 列、1280 下约 2 列。注意只对**整行卡**生效 ——
   普通卡在页面级分栏里本来就只占一列（约 400px），再分栏就挤了。
   两种结构分别处理：
     A. 首页「今日必做任务」→ 第六轮已改成 .taskgrid 自适应网格（见文件上方 .ttile），
        不再需要这里分栏，原来的 `#view > .card-tall > .mt12` 规则已删除。
     B. 行直接是卡片子元素（我的页「学习数据」「设置」→ .setrow）→ 给卡片分栏、标题跨列。
   ⚠⚠ 这四条必须**拆成四条规则**：老内核不认 :has()，而 CSS 的规矩是「选择器列表里
   只要有一个选择器不被识别，**整条规则都会被丢掉**」。如果像以前那样把
   `...:has(> .setrow)` 和 `... > .card-wide` 写在同一个列表里，老内核连
   `.card-wide` 的分栏、`.card-title` 的跨列一起废掉 —— 明明那些选择器它是认识的。
   （2026-10-15 扫出来的，和 inset 是同一类「静默失效」） */
html[data-lay="wide"] #view > .card-tall:has(> .setrow),
html[data-lay="desk"] #view > .card-tall:has(> .setrow) {
  column-width:22rem; column-gap:1.25rem;
}
html[data-lay="wide"] #view > .card-wide,
html[data-lay="desk"] #view > .card-wide {
  column-width:22rem; column-gap:1.25rem;
}
html[data-lay="wide"] #view > .card-tall:has(> .setrow) > .card-title,
html[data-lay="desk"] #view > .card-tall:has(> .setrow) > .card-title {
  column-span:all; -webkit-column-span:all;
}
html[data-lay="wide"] #view > .card-wide > .card-title,
html[data-lay="desk"] #view > .card-wide > .card-title {
  column-span:all; -webkit-column-span:all;
}
/* 行元素不许被拦腰截断到两列之间 */
html[data-lay="wide"] #view > .card-tall > .setrow,
html[data-lay="desk"] #view > .card-tall > .setrow,
html[data-lay="wide"] #view > .card-wide > .setrow,
html[data-lay="desk"] #view > .card-wide > .setrow {
  break-inside:avoid; -webkit-column-break-inside:avoid; page-break-inside:avoid;
}

/* ---------- ⑦ 宽屏「大而不当」的收尾 ★ 2026-10-13 第六轮 ---------- */

/* 7·1 卡片主按钮（.btn.big 默认 width:100%）在桌面端被拉成 1500px 的一条长按钮
   （听力页「开始今日听力」实测 1566px）。限宽 + 居中，读起来才像按钮。
   ⚠ .btn 基础是 display:inline-flex，行内级盒子加 margin:auto 不会居中，要改成 flex。 */
html[data-lay="wide"] #view > .card > .btn.big,
html[data-lay="desk"] #view > .card > .btn.big,
html[data-lay="wide"] #view > .btn.big,
html[data-lay="desk"] #view > .btn.big {
  display:flex; width:auto; min-width:18rem; max-width:26rem;
  margin-left:auto; margin-right:auto;
  justify-self:center;                 /* 列表页里它是跨行网格项，靠 justify-self 居中 */
}

/* 7·2 进度卡（单词页「词汇进度」/ 其它科「知识点进度」）：
   宽屏下是「标题行 / 1500px 长的一条 10px 细线 / 一行统计」，三行竖着堆，右侧全空、卡片还高。
   改成**一行三栏**：标题+百分比 | 进度条（自适应铺开）| 统计文字。卡片高度 ~140px → ~62px，
   长进度条两侧有了文字夹持，看着就是一条正常的「仪表条」而不是一根孤零零的线。 */
html[data-lay="wide"] #view > .card:has(> .pbar),
html[data-lay="desk"] #view > .card:has(> .pbar) {
  display:grid !important;                 /* 会被「卡片区分栏」那条 :has() 链的 display:block 盖掉，必须 !important */
  grid-template-columns:auto minmax(8rem,1fr) auto;
  align-items:center; column-gap:1.5rem;
}
html[data-lay="wide"] #view > .card:has(> .pbar) > .row,
html[data-lay="desk"] #view > .card:has(> .pbar) > .row { grid-column:1; }
html[data-lay="wide"] #view > .card:has(> .pbar) > .pbar,
html[data-lay="desk"] #view > .card:has(> .pbar) > .pbar { grid-column:2; margin-top:0 !important; max-width:none; }
html[data-lay="wide"] #view > .card:has(> .pbar) > .sub,
html[data-lay="desk"] #view > .card:has(> .pbar) > .sub { grid-column:3; margin-top:0 !important; text-align:right; }

/* 7·3 「要点块」(.gp) 卡片：宽屏下 N 个要点一行一个地铺满 1600px，右边全空。
   改成自适应并排（听力「零基础三步法」3 个要点、知识点详情页的要点列表）。 */
html[data-lay="wide"] #view > .card:has(> .gp),
html[data-lay="desk"] #view > .card:has(> .gp) {
  display:grid !important; align-content:start;
  grid-template-columns:repeat(auto-fit,minmax(19rem,1fr)); gap:0.75rem;
}
html[data-lay="wide"] #view > .card:has(> .gp) > .card-title,
html[data-lay="desk"] #view > .card:has(> .gp) > .card-title { grid-column:1 / -1; margin-bottom:0; }
html[data-lay="wide"] #view > .card:has(> .gp) > .gp,
html[data-lay="desk"] #view > .card:has(> .gp) > .gp { margin-bottom:0; }

/* 7·4 关卡详情页（.lv-main / .lv-side ★ 见 views-home.js 注释）：
   宽屏排成「左主栏 + 右操作栏」，主栏放本关词汇/语法/场景/拼读，右栏堆「练一练 / 关卡测验」。
   平板（medium）单栏堆叠、两张操作卡并排。 */
html[data-lay="wide"] #view:has(> .lv-side),
html[data-lay="desk"] #view:has(> .lv-side) {
  display:grid !important; grid-template-columns:minmax(0,1fr) 24rem;
  gap:0.875rem; align-content:start; align-items:start;
}
html[data-lay="medium"] #view:has(> .lv-side) {
  display:grid !important; grid-template-columns:minmax(0,1fr);
  gap:0.875rem; align-content:start; align-items:start;
}
html[data-lay="wide"] #view:has(> .lv-side) > .pagehead,
html[data-lay="desk"] #view:has(> .lv-side) > .pagehead,
html[data-lay="wide"] #view:has(> .lv-side) > .steps,
html[data-lay="desk"] #view:has(> .lv-side) > .steps { grid-column:1 / -1; margin-bottom:0; }
html[data-lay="wide"] #view:has(> .lv-side) > .lv-main,
html[data-lay="desk"] #view:has(> .lv-side) > .lv-main { margin:0 !important; min-width:0; }
html[data-lay="wide"] #view:has(> .lv-side) > .lv-side,
html[data-lay="desk"] #view:has(> .lv-side) > .lv-side { display:grid; gap:0.875rem; align-content:start; }
html[data-lay="wide"] #view:has(> .lv-side) > .lv-side > .card,
html[data-lay="desk"] #view:has(> .lv-side) > .lv-side > .card { margin:0; }
html[data-lay="medium"] #view:has(> .lv-side) > .lv-main { margin:0 !important; }
html[data-lay="medium"] #view:has(> .lv-side) > .lv-side { display:grid; grid-template-columns:repeat(2,minmax(0,1fr)); gap:0.875rem; }
html[data-lay="medium"] #view:has(> .lv-side) > .lv-side > .card { margin:0; }

/* 7·5 关卡详情页的两处收尾：
   · .steps 三个步骤胶囊在宽屏被拉成整行三等分（每个 280px），限宽回正常按钮尺寸；
   · 自然拼读 26 个字母原本一行一个铺满 1100px，改成自适应多列网格（.phonics-grid 由 JS 包一层）。 */
html[data-lay="wide"] #view > .steps,
html[data-lay="desk"] #view > .steps { max-width:32rem; }
html[data-lay="wide"] .phonics-grid,
html[data-lay="desk"] .phonics-grid { display:grid; grid-template-columns:repeat(auto-fit,minmax(19rem,1fr)); gap:0.4375rem; }
html[data-lay="wide"] .phonics-grid > .wordrow,
html[data-lay="desk"] .phonics-grid > .wordrow { margin-bottom:0; }
html[data-lay="wide"] .phonics-grid > .wordrow .wr-t,
html[data-lay="desk"] .phonics-grid > .wordrow .wr-t { flex-wrap:nowrap; }

/* 8 开场动画（2026-10-15 改，js/intro.js）
   去掉了原来的进门密码，改成打开即播：图标弹入 → 光环扩散 → 文字上浮 → 进度条走满 → 整屏淡出。
   ⚠ z-index 刻意**低于** #compat-bar(9000)：万一微信里打开、内核过旧，
   那条「换个浏览器打开」的提示必须还能压在动画上面，不然用户连原因都看不到。
   ⚠ .it-ring::after 用了 inset —— 按本项目规矩先写 top/right/bottom/left 兜底。 */
.xy-intro { position:fixed; top:0; right:0; bottom:0; left:0; inset:0; z-index:8800; background:var(--bg); display:flex; align-items:center; justify-content:center; padding:2rem; text-align:center; cursor:pointer; overflow:hidden; }
/* 流星雨背景层（js/intro.js 的 shower() 往里塞 .it-met）
   ★ 绝对定位 → 不参与 flex 排布，不会把 .it-box 挤歪；
   ★ 但绝对定位元素默认画在静态元素**上面** → 必须 z-index:0 + .it-box 抬到 1，
     否则流星会盖住标题和 🎓；
   ★ pointer-events:none —— 不然「点屏幕任意处跳过」会被这层吃掉。 */
.xy-intro .it-sky { position:absolute; top:0; right:0; bottom:0; left:0; inset:0; z-index:0; overflow:hidden; pointer-events:none; }
.xy-intro .it-box { position:relative; z-index:1; display:flex; flex-direction:column; align-items:center; gap:0.55rem; width:100%; }
/* 图标 + 扩散光环 */
.xy-intro .it-ring { position:relative; width:6rem; height:6rem; border-radius:50%; border:3px solid var(--brand); display:flex; align-items:center; justify-content:center; animation:itPop .6s cubic-bezier(.2,1.45,.4,1) both; }
.xy-intro .it-ring::after { content:""; position:absolute; top:-3px; right:-3px; bottom:-3px; left:-3px; inset:-3px; border:3px solid var(--brand); border-radius:50%; opacity:.5; animation:itRing 1.1s ease-out .25s both; }
@keyframes itRing { from { transform:scale(.7); opacity:.6 } to { transform:scale(1.9); opacity:0 } }
@keyframes itPop { from { opacity:0; transform:scale(.5) } to { opacity:1; transform:scale(1) } }
.xy-intro .it-ico { font-size:2.75rem; line-height:1; }
/* 文字依次上浮 */
.xy-intro .it-title { margin-top:0.35rem; font-size:1.3rem; font-weight:800; letter-spacing:0.15rem; color:var(--ink); animation:itUp .5s ease-out .2s both; }
.xy-intro .it-sub { font-size:.75rem; color:var(--sub); animation:itUp .5s ease-out .32s both; }
.xy-intro .it-skip { margin-top:0.5rem; font-size:.7rem; color:var(--sub); opacity:.75; animation:itUp .5s ease-out .45s both; }
@keyframes itUp { from { opacity:0; transform:translateY(8px) } to { opacity:1; transform:translateY(0) } }
/* 进度条走满 */
.xy-intro .it-bar { margin-top:0.9rem; width:9rem; height:0.28rem; border-radius:99px; background:var(--line); overflow:hidden; }
.xy-intro .it-bar i { display:block; height:100%; width:0; border-radius:99px; background:var(--brand); animation:itFill 1.2s ease-out .1s forwards; }
@keyframes itFill { from { width:0 } to { width:100% } }
/* 整屏淡出（时长需与 js/intro.js 的 FADE 一致） */
.xy-intro.out { animation:itOut .5s ease forwards; }
@keyframes itOut { to { opacity:0; transform:scale(1.05); visibility:hidden } }

/* 9 「运行环境」里的功能自检清单（2026-10-15 加）
   手机反馈「有些功能用不了」，隔着屏幕没法复现 → 逐项真跑一遍，✕ 的就是坏的那块。
   注意：这里是诊断 UI，**不要用 :has() 之类的新选择器**，否则在正是要排查的旧内核上自己先失效。 */
.selfhead { display:flex; align-items:baseline; gap:0.375rem; font-size:.78rem; font-weight:600; color:var(--ink); margin:0 0 0.375rem; }
.selfhead .sh-ok { color:var(--ok); }
.selfhead .sh-bad { color:var(--bad); }
.selftest { border:1px solid var(--line); border-radius:0.75rem; overflow:hidden; background:var(--card); margin:0 0 0.75rem; }
.st-row { display:flex; align-items:flex-start; gap:0.5rem; padding:0.5rem 0.625rem; border-bottom:1px solid var(--line); font-size:.76rem; line-height:1.55; }
.st-row:last-child { border-bottom:0; }
.st-row.bad { background:var(--bad-soft); }
.st-i { flex:0 0 0.875rem; font-weight:700; }
.st-row.ok .st-i { color:var(--ok); }
.st-row.bad .st-i { color:var(--bad); }
.st-n { flex:0 0 auto; max-width:45%; font-weight:600; color:var(--ink); }
.st-d { flex:1; min-width:0; color:var(--sub); }
/* 窄屏把「名称 / 说明」折成两行，别横向挤成一团 */
html[data-lay="narrow"] .st-row { flex-wrap:wrap; }
html[data-lay="narrow"] .st-n { max-width:100%; }
html[data-lay="narrow"] .st-d { flex:1 0 100%; padding-left:1.375rem; }

/* ---------- ⑨ 白天 / 黑夜切换开关（壁纸引擎风）★ 2026-10-15 第十八轮 ----------
   顶栏那个胶囊开关：轨道里白天有云、黑夜有星，圆球从太阳滑到月亮；
   点下去时整屏还会有一次「从按钮处扩散 / 收缩」的过场（见 js/app.js 的 themeWipe）。
   ⚠ 老内核铁律：渐变 / clip-path / transition 这类新语法**丢了也不能让控件变形**，
     所以背景色先写一条纯色兜底，再写渐变；老内核拿不到渐变时至少还是个胶囊。 */

/* 9·1 开关本体：去掉按钮默认样式，只留轨道 */
.dn {
  padding:0; margin:0; border:0; background:none; cursor:pointer; line-height:0;
  -webkit-tap-highlight-color:transparent; touch-action:manipulation;
}
.dn-track {
  position:relative; display:block;
  width:3.25rem; height:1.625rem;
  border-radius:62.4375rem;
  border:1px solid var(--line);
  overflow:hidden;
  background:#bfe0f5;                                                   /* 兜底：纯色 */
  background:linear-gradient(160deg,#8ecdf3 0%,#cfe9fb 52%,#ffe3b0 100%); /* 白天：晴空到暖阳 */
  box-shadow:inset 0 0.0625rem 0.1875rem rgba(0,0,0,.12);
  transition:background .55s ease, border-color .35s ease;
}
body.theme-dark .dn-track {
  background:#232a4d;                                                   /* 兜底：纯色 */
  background:linear-gradient(160deg,#1a2040 0%,#2b3160 55%,#3f3568 100%); /* 黑夜：深空 */
}

/* 9·2 轨道里的云（白天）与星（黑夜）—— 两者靠 theme 切换淡入淡出 */
.dn-cloud, .dn-star { position:absolute; display:block; pointer-events:none; }
/* ★ v85 云重做：旧版是一块 14×7px 的白色圆角条 + 三层白色 box-shadow 拼「云」，
   在 52px 的轨道里右边缘还被裁掉，视觉上就是一团说不清的白色残屑（截图确认）。
   现在改成一颗真正的云形 SVG（inline、无网络请求、颜色跟轨道走），缩小到 13×9px，
   位置收到轨道右半部、留足边距 —— 一眼能认出是云，也压不住圆球。 */
.dn-cloud {
  right:0.375rem; top:0.3125rem;
  width:0.8125rem; height:0.5625rem;
  background:none;
  opacity:.92;
  transition:opacity .4s ease, transform .6s cubic-bezier(.68,-.35,.27,1.35);
}
.dn-cloud::before {
  content:""; display:block; width:100%; height:100%;
  background:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 16'%3E%3Cpath d='M6.2 15C2.8 15 0 12.4 0 9.2c0-2.9 2.2-5.3 5-5.9C6.4 1.3 8.7 0 11.3 0c3.2 0 5.9 2.2 6.6 5.2 2.7.2 4.8 2.3 4.8 5 0 2.7-2.3 4.8-5.1 4.8H6.2z' fill='%23ffffff'/%3E%3C/svg%3E") center/contain no-repeat;
}
/* 天黑了云就飘走 */
body.theme-dark .dn-cloud { opacity:0; transform:translateX(-1.25rem) scale(.6); }

.dn-star {
  width:0.125rem; height:0.125rem; border-radius:50%;
  background:#ffffff; opacity:0;
  transition:opacity .5s ease .12s;
}
.dn-s1 { left:0.4375rem;  top:0.375rem; }
.dn-s2 { left:0.8125rem;  top:0.6875rem; width:0.15625rem; height:0.15625rem; }
.dn-s3 { left:1.1875rem;  top:0.3125rem; }
/* 天黑了星星才亮起来 */
body.theme-dark .dn-star { opacity:.95; }

/* 9·3 圆球：白天停在左边托着太阳，黑夜滑到右边托着月亮 */
.dn-knob {
  position:absolute; top:0.125rem; left:0.125rem;
  width:1.25rem; height:1.25rem;
  border-radius:50%;
  background:#fff8e1;                                                   /* 兜底：纯色 */
  background:radial-gradient(circle at 35% 30%,#fffdf2 0%,#ffd977 100%);
  box-shadow:0 0.0625rem 0.25rem rgba(0,0,0,.28);
  display:flex; align-items:center; justify-content:center;
  transition:left .55s cubic-bezier(.68,-.35,.27,1.35), background .55s ease, transform .35s ease;
}
/* ⚠ 黑夜的圆球**不能做太白** —— 实测浅色球 + 🌙 emoji 对比度太低，
   在手机小尺寸下看着像"一个白点"，认不出是月亮。改成中等亮度的蓝灰。 */
body.theme-dark .dn-knob {
  left:1.8125rem;                                                       /* 3.25 - 1.25 - 0.125 - 0.125 */
  background:#b9c2e0;                                                   /* 兜底：纯色 */
  background:radial-gradient(circle at 35% 30%,#d8def2 0%,#9aa6cc 100%);
}
/* 按下去时圆球被"挤"一下，手感更像实体开关 */
.dn:active .dn-knob { transform:scaleX(1.2) scaleY(.86); }

/* 9·4 圆球里的太阳 / 月亮：一个淡出、一个转进来 */
.dn-face {
  position:absolute; font-size:.6875rem; line-height:1;
  /* ⚠ emoji 在不同系统上的基线不一样（有的偏下），用 flex 居中比 line-height 稳 */
  display:flex; align-items:center; justify-content:center;
  width:100%; height:100%;
  transition:opacity .35s ease, transform .55s cubic-bezier(.68,-.35,.27,1.35);
}
.dn-sun  { opacity:1; transform:rotate(0deg)   scale(1); }
.dn-moon { opacity:0; transform:rotate(60deg)  scale(.4); }
body.theme-dark .dn-sun  { opacity:0; transform:rotate(-70deg) scale(.4); }
body.theme-dark .dn-moon { opacity:1; transform:rotate(0deg)   scale(1); }

/* 9·5 整屏过场：从按钮处把「旧主题」收走，露出新主题（JS 创建的 .theme-wipe） */
.theme-wipe {
  position:fixed; top:0; right:0; bottom:0; left:0;   /* ⚠ 长写，别用 inset */
  z-index:8700;                                       /* 在弹窗(8800 以下)之下、内容之上 */
  pointer-events:none;
  will-change:clip-path;
}

/* 9·6 桌面档：chips 被搬到侧栏底部竖排，开关跟着撑满宽度
   ★★ 2026-10-18（v121）：这几条必须**只作用于侧栏里的那个开关**（`.topchips .dn`）。
      原来写的是全局 `.dn`，于是登录门自带的 `#ag-dn` 也被撑成整条 ——
      用户看到的就是「登录界面上一个又长又扁的昼夜条」，明确要求改成右上角的小控件。
      给选择器加 `.topchips` 后，`#ag-dn` 回到本体 3.25rem 的胶囊尺寸。
      ⚠ 顺带一提：`#authgate #ag-dn` 是 (2,0,0)，本来就压得过 (0,2,1)，但**别靠这个**，
        把范围收窄才是对的 —— 以后有人给 `.dn` 再加全局规则不会又踩回来。 */
html[data-lay="wide"] .topchips .dn,
html[data-lay="desk"] .topchips .dn { width:100%; }
html[data-lay="wide"] .topchips .dn-track,
html[data-lay="desk"] .topchips .dn-track { width:100%; height:2rem; }
/* ⚠ 轨道变成「撑满侧栏」后，9·3 里写死的 left:1.8125rem 就不再贴右边了 ——
   这里必须按百分比重算，否则黑夜时圆球停在轨道中间，看着像坏了。 */
html[data-lay="wide"] .topchips .dn-knob,
html[data-lay="desk"] .topchips .dn-knob { width:1.5rem; height:1.5rem; top:0.25rem; left:0.25rem; }
html[data-lay="wide"] body.theme-dark .topchips .dn-knob,
html[data-lay="desk"] body.theme-dark .topchips .dn-knob { left:calc(100% - 1.75rem); }
html[data-lay="wide"] .topchips .dn-face,
html[data-lay="desk"] .topchips .dn-face { font-size:.875rem; }

/* ==================================================================
   ⑩ 小屏可用度（为 Qin3 UC 这类 5 英寸 / 360×640 的矮窄屏而做）
   ────────────────────────────────────────────────────────────────
   背景：多亲 Qin3 UC 是 5.02 英寸 720×1520 的小屏机，CSS 视口只有 360px 宽、
   约 640px 高（若厂商把 DPR 锁成 3 甚至只有 240px 宽）。在这种屏上：
     ① 弹窗内容换行暴涨（奖池实测 761px），远超弹窗 82vh（640 屏上仅 525px），
        「知道了 / 收下 / 确定」被推到 y≈800 —— 屏幕外。
        弹窗本身能滚，但用户不知道要滚，表现就是"点了没反应 / 看不了"。
     ② grid 的 minmax(16.5rem,1fr) 最小值 264px 撑破 240px 容器 → 横向溢出。

   10·1 ★ 底部按钮吸底：弹窗里的大按钮、确认行永远贴在弹窗底部，够得着。
        ⚠ 老内核铁律：sticky 必须「先带前缀、后标准」分成两条写 —— 老内核不认
          标准值会丢掉第二条、留下带前缀那条；两条合写则整条被丢。 */
.modal > .btn.big { position:-webkit-sticky; }
.modal > .btn.big { position:sticky; bottom:0; z-index:3; }
.modal > .row.mt12 { position:-webkit-sticky; }
.modal > .row.mt12 { position:sticky; bottom:0; z-index:3; }
/* 吸底的按钮要挡住从它下面滑过去的内容：补一层同色底 + 上方渐变过渡。
   ⚠ left/right 用负的 --pad 把左右内边距区也铺满，否则两侧会漏出文字。 */
.modal > .row.mt12 { background:var(--card); padding-top:0.5rem; }
.modal > .btn.big::before,
.modal > .row.mt12::before {
  content:''; position:absolute; bottom:100%; height:0.875rem; pointer-events:none;
  left:calc(-1 * var(--pad)); right:calc(-1 * var(--pad));
  background:var(--card);                                   /* 老内核兜底：纯色 */
  background:linear-gradient(to top, var(--card) 12%, rgba(0,0,0,0) 100%);
}

/* 10·2 矮屏多给弹窗一点高度，少滚一点（82vh → 88vh） */
html[data-lay="narrow"] .modal { max-height:88vh; }

/* 10·3 ★ 商城网格：minmax 的最小值写死 16.5rem(=264px) 在 ≤264px 的屏上会撑破容器。
        改成「最多 16.5rem，但不许超过容器宽度」—— 极窄屏自动退成一列。
        ⚠ 同样是「先老写法兜底、后新写法」：老内核不认 min() 会丢掉第二条，
          退回原来的 16.5rem（在 360px 这类正常屏上本来就没事）。 */
.shopgrid { grid-template-columns:repeat(auto-fill,minmax(16.5rem,1fr)); }
.shopgrid { grid-template-columns:repeat(auto-fill,minmax(min(16.5rem,100%),1fr)); }

/* 11· 公式测试（①记住 / ②掌握 / ③会用）
    └── .fw-* 只有数学学科会渲染出来，英语/语文/计算机零节点、零像素影响。
   ★★ 长公式一律不许溢出：Qin3 上 CSS 视口只有 360px 宽，
      「cos30°=√3/2，cos45°=√2/2，cos60°=1/2」这种一行根本放不下，
      必须让它折行（word-break）而不是把卡片撑宽。 */
.fw-line { display:flex; align-items:center; gap:0.5rem; margin:0.4375rem 0; }
.fw-lb { flex:none; min-width:3.4rem; font-size:0.78rem; font-weight:800; color:var(--sub); }
.fw-num { flex:none; min-width:2.8rem; text-align:right; font-size:0.78rem; font-weight:800; color:var(--ink); }
.fw-row { display:flex; align-items:center; gap:0.5rem; padding:0.625rem 0; border-top:1px solid var(--line); }
.fw-row { cursor:pointer; }
.fw-n { flex:1 1 auto; min-width:0; }
.fw-name { font-size:0.86rem; font-weight:800; line-height:1.35; word-break:break-all; }
.fw-m { font-size:0.72rem; color:var(--sub); line-height:1.45; margin-top:0.125rem; word-break:break-all; }
.fw-tags { flex:none; display:flex; gap:0.1875rem; }
.fw-tag { font-size:0.66rem; font-weight:800; line-height:1.2; padding:0.1875rem 0.3125rem; border-radius:0.375rem; background:var(--bg); color:var(--sub); }
.fw-tag.on { background:var(--ok-soft); color:var(--ok); }
.fw-end { flex:none; color:var(--sub); font-size:1rem; }
.fw-expr { font-size:1.05rem; font-weight:800; line-height:1.75; color:var(--brand); text-align:center; padding:0.375rem 0; word-break:break-all; }
.fw-txt { font-size:0.85rem; line-height:1.75; color:var(--ink); word-break:break-all; }
.fw-ul { margin:0; padding-left:1.15rem; font-size:0.83rem; line-height:1.8; color:var(--sub); }
.fw-detail summary { font-size:0.82rem; font-weight:700; color:var(--brand); cursor:pointer; padding:0.375rem 0; }

/* ============ ⑫ 宠物院（2D 卡通伙伴） ============
   ★ 老内核纪律：新语法一律「先长写兜底、后简写」（本项目铁律）。
   ★ 宠物配色：只在这里按 data-pet 设 --pet-a/b/c 三个变量，
     SVG 那边不写死颜色 → 换色只改三行、加新宠物也只需加一条。
   ★ 眼睛颜色固定在 SVG 里（深墨）**不跟着主题变**，保证任何底色上都看得见。 */
.pgyard-card { padding:0.7rem; }
.pgyard-head { padding:0 0.3rem 0.5rem; }
.pgyard-head h2 { margin:0 0 0.2rem; font-size:1.05rem; }
.pgyard-head .sub { font-size:0.78rem; color:var(--sub); line-height:1.6; }

/* 院子：固定 16:11 比例，小屏也保持这个比例（宠物位置用 % 所以不会跑偏）
   ★★ overflow 必须 visible：宠物被点时的对话泡是往上弹的（bottom:100%），
      而站在第一排的宠物头顶就是院子顶边 —— 一旦 overflow:hidden，气泡会被**切掉半个**
      （实测「（它立刻趴下翻出了肚子）」只剩下半句看得见，_petyard 截图确认）。
      场景层（天空/草地/篱笆/太阳）自己带 border-radius，不需要靠父级裁切。 */
.pgyard {
  position:relative; width:100%; padding-bottom:70%;
  border-radius:0.85rem;
  border:1px solid var(--line); background:#bfe4ff;
  /* 白天/黑夜两套院子配色，由主题变量驱动 */
  --yard-sky:#bfe4ff; --yard-sky2:#e8f6ff; --yard-grass:#8ed36a; --yard-grass2:#6cbb4d;
  --yard-fence:#f0d9a8; --yard-cloud:#ffffff;
}
/* 场景层自己裁圆角（替代父级 overflow:hidden） */
.pgy-sky, .pgy-ground, .pgy-fence { overflow:hidden; }
.pgy-jard { isolation:isolate; }
body.theme-dark .pgyard {
  --yard-sky:#1b2440; --yard-sky2:#2a3457; --yard-grass:#2c5346; --yard-grass2:#20403a;
  --yard-fence:#4a4470; --yard-cloud:#5d6a99;
}
.pgy-sky {
  position:absolute; left:0; top:0; right:0; height:62%;
  border-radius:0.85rem 0.85rem 0 0;
  background:linear-gradient(to bottom, var(--yard-sky) 0%, var(--yard-sky2) 100%);
}
.pgy-sun {
  position:absolute; right:9%; top:9%; width:2.2rem; height:2.2rem;
  border-radius:50%; background:#ffe27a;
  box-shadow:0 0 1rem 0.4rem rgba(255,214,90,.55);
}
body.theme-dark .pgy-sun { background:#e8eaff; box-shadow:0 0 1rem 0.4rem rgba(200,210,255,.5); }
/* 云：两个椭圆拼一朵，用 translateX 缓慢飘（纯装饰） */
.pgy-cloud {
  position:absolute; height:1.1rem; border-radius:99px; background:var(--yard-cloud); opacity:.85;
}
.pgy-cloud::before {
  content:""; position:absolute; left:22%; top:-0.45rem;
  width:1.4rem; height:1.4rem; border-radius:50%; background:inherit;
}
.pgy-cloud.c1 { left:8%; top:16%; width:3.4rem; }
.pgy-cloud.c2 { left:48%; top:8%; width:2.6rem; }
/* 草地：下半部分 */
.pgy-ground {
  position:absolute; left:0; right:0; bottom:0; height:44%;
  border-radius:0 0 0.85rem 0.85rem;
  background:linear-gradient(to bottom, var(--yard-grass) 0%, var(--yard-grass2) 100%);
}
/* 篱笆：一排小竖条（用重复渐变做，比画 DOM 省） */
.pgy-fence {
  position:absolute; left:0; right:0; bottom:44%; height:0.55rem;
  background:var(--yard-fence);
  opacity:.9;
  /* 老写法兜底 */
  background-image:repeating-linear-gradient(to right, transparent 0, transparent 0.35rem, rgba(0,0,0,.12) 0.35rem, rgba(0,0,0,.12) 0.42rem);
  background-image:repeating-linear-gradient(90deg, transparent 0 0.35rem, rgba(0,0,0,.12) 0.35rem 0.42rem);
}

/* ---------- 单只宠物 ----------
   ★★ 宽度直接决定"会不会叠"：院子是 16:11 的框，横向 22% ≈ 竖直 22×1.45 ≈ 32%，
     而行距只有 26% → 必然上下咬住。实测 22% 时最紧一对 -17px 重叠（_petyard 抓到）。
     收到 17% 后竖直占用 ≈ 25% < 26% 行距，留出余量。改这个值要连着跑 _petyard。 */
.pg {
  position:absolute; width:17%; max-width:4.6rem;
  transform:translate(-50%,-50%) scale(var(--pg-scale,1));
  transform:translate(-50%,-50%) scale(var(--pg-scale,1));
  cursor:pointer;
  /* ★ 用 -webkit-tap-highlight-color 关掉安卓点击高亮，不然点宠物会出现灰框 */
  -webkit-tap-highlight-color:transparent;
  z-index:3;
}
/* ---------- 四层结构（改之前务必先看 js/views-petyard.js 顶上那段说明）----------
   .pg 站在哪 / .pg-move 在走 / .pg-flipr 朝哪边 / .pg-art 闲着干嘛
   ★★ 为什么非要分这么多层：**CSS animation 的 transform 会整条盖掉同元素上的
      普通 transform 规则**。把"定位的 translate(-50%,-50%)"和"走动的 translate"
      写在同一个元素上，动画一跑定位就没了，宠物会飞到院子外；
      把"翻面"和"待机动作"写在同一个元素上，待机一动宠物就翻回正面。
      每层只干一件事，四个 transform 互不干扰。 */
.pg-move {
  /* 名字牌是 inline-block，用 flex 列把它居中（否则会左对齐） */
  display:flex; flex-direction:column; align-items:center;
  position:relative;              /* 皇冠 / 心情角标靠它定位 */
  /* 行内 style 会按每只宠物覆盖 animation-delay / -duration（各走各的节奏） */
  animation:pg-walk-a 9s ease-in-out infinite;
}
.pg-flipr { display:block; line-height:0; transform:scaleX(var(--pg-flip,1)); }
.pg.size-0 { --pg-scale:0.92; }
.pg.size-1 { --pg-scale:1; }
.pg.size-2 { --pg-scale:1.06; }
.pg.cur { z-index:5; }
.pg-art { display:block; line-height:0; }
.pg-art .pg-svg { width:100%; height:auto; display:block; }

/* 宠物配色（--pet-a 主体 / --pet-b 暗部 / --pet-c 亮部肚皮） */
.pg-art[data-pet="cat"]     { --pet-a:#ffb04d; --pet-b:#e08a2e; --pet-c:#fff0d6; }
.pg-art[data-pet="dog"]     { --pet-a:#f0a35e; --pet-b:#c97b3f; --pet-c:#fff4e4; }
.pg-art[data-pet="penguin"] { --pet-a:#4a5578; --pet-b:#333d5c; --pet-c:#ffffff; }
.pg-art[data-pet="turtle"]  { --pet-a:#9ad07a; --pet-b:#5f9b46; --pet-c:#e8ffe0; }
.pg-art[data-pet="owl"]     { --pet-a:#a98bd6; --pet-b:#7a5cad; --pet-c:#f2ebff; }
.pg-art[data-pet="rabbit"]  { --pet-a:#f0eef8; --pet-b:#d2cee6; --pet-c:#ffffff; }
.pg-art[data-pet="fox"]     { --pet-a:#f0873f; --pet-b:#cc6524; --pet-c:#ffe9d6; }
.pg-art[data-pet="panda"]   { --pet-a:#f4f5f8; --pet-b:#2f3342; --pet-c:#ffffff; }
.pg-art[data-pet="unknown"] { --pet-a:#c9b7e8; --pet-b:#9b86c4; --pet-c:#f4f0ff; }
/* ⚠ 上面这五行只是「没传毛色时」的兜底：真正生效的永远是 <svg> 行内那三个变量
   （见 js/pet-skin.js）。改配色请改 pet-skin.js，别改这里 —— 改了也盖不住行内。 */

/* 👑 当前带着的那只的标记
   ★★ 位置要按"宠物框"算：.pg 是 flex 列（SVG 在上、名字牌在下），
      SVG 高 = .pg 宽（正方形），耳尖在 SVG 的 y≈17/100 处。
      所以要让皇冠压在耳尖上，top 得设成 **-.5rem 左右**（实测参考值）：
        0      → 飘在头顶上方一大截（截图见过，像悬空的小旗子）
        -0.9rem→ 还是偏高
        -0.5rem→ 正好落在耳尖/头顶交界
   ★ 横向 56% 偏右：左边那个位置留给对话泡的箭头。 */
.pg-crown {
  position:absolute; left:56%; top:-0.5rem;
  transform:rotate(-18deg);
  font-size:0.9rem; line-height:1;
  filter:drop-shadow(0 1px 2px rgba(0,0,0,.35));
  z-index:9; pointer-events:none;
}
/* 名字牌
   ★★ 不能跟着 .pg 的窄宽度走 —— .pg 只有 17% 宽，"单词猫 · Lv.1" 必然被截成"单词猫…"（截图确认）。
      它是标签、不是宠物身体的一部分，所以**允许溢出**宠物框：max-width 按视口给，
      横向居中挂在宠物下方，和别的宠物的名字也不会打架（行距够）。
   ★ 加一层半透明深色底：宠物站在"天空/草地交界"那条篱笆上时，
     纯白字 + 阴影在浅色篱笆上仍然糊，垫一层底就稳了。 */
.pg-plate {
  margin-top:-0.2rem; text-align:center; font-size:0.62rem; font-weight:700;
  color:#fff;
  background:rgba(20,28,48,.42);
  border-radius:99px; padding:0.08rem 0.34rem;
  white-space:nowrap;
  max-width:7.4rem;                     /* 够放"单词猫 · Lv.1" */
}
body.theme-dark .pg-plate { color:#eef1ff; background:rgba(8,12,26,.55); }
.pg-plate .pg-lv { color:#ffe27a; }
/* 对话泡：平时藏着，点它才浮出来
   ★★ z-index 必须够高：气泡往上弹，很容易压到**相邻宠物**或后排宠物的名字牌。
      提到 60（远高于 .pg 的 3~5）保证它永远在最上层，不会被别的宠物盖住。
   ★ 下沿留 0.35rem 缝隙，别贴着宠物头顶。 */
.pg-talk {
  position:absolute; left:50%; bottom:100%; transform:translate(-50%,-0.35rem);
  width:9.6rem; padding:0.4rem 0.5rem; border-radius:0.5rem;
  background:#fff; color:#26324a; font-size:0.68rem; line-height:1.5;
  box-shadow:0 3px 10px rgba(0,0,0,.18);
  opacity:0; pointer-events:none; transition:opacity .18s ease;
  word-break:break-word; z-index:60;
  white-space:normal;
}
body.theme-dark .pg-talk { background:#2b3350; color:#eef1ff; }
.pg.talk-on .pg-talk { opacity:1; }
/* 气泡小尖角（老内核不认识 ::after 也没关系，只是少个尖） */
.pg-talk::after {
  content:""; position:absolute; left:50%; bottom:-0.3rem; margin-left:-0.3rem;
  width:0; height:0; border:0.3rem solid transparent; border-top-color:#fff;
}
body.theme-dark .pg-talk::after { border-top-color:#2b3350; }

/* 点一下的心心（JS 动态插入，飘上去就自己删） */
.pg-heart {
  position:absolute; left:50%; top:-0.4rem; transform:translateX(-50%);
  font-size:0.8rem; line-height:1; pointer-events:none;
  animation:pg-float 1.05s ease-out forwards;
}
@keyframes pg-float {
  0%   { opacity:0; margin-top:0; }
  25%  { opacity:1; }
  100% { opacity:0; margin-top:-1.6rem; }
}

/* ---------- 宠物动作（纯 CSS，别用 JS 定时器） ---------- */
@keyframes pg-breathe {
  0%,100% { transform:translateY(0) scaleY(1); }
  50%     { transform:translateY(-1.6%) scaleY(1.02); }
}
@keyframes pg-ear-twitch {
  0%,86%,100% { transform:rotate(0deg); }
  90%         { transform:rotate(-8deg); }
  94%         { transform:rotate(5deg); }
}
@keyframes pg-tail-wag {
  0%,100% { transform:rotate(-4deg); }
  50%     { transform:rotate(7deg); }
}
@keyframes pg-wing-flap {
  0%,100% { transform:rotate(0deg); }
  50%     { transform:rotate(-14deg); }
}
@keyframes pg-blink {
  0%,92%,100% { transform:scaleY(1); }
  95%         { transform:scaleY(.1); }
}
@keyframes pg-wobble {          /* 被摸到时整只晃一下 */
  0%,100% { transform:translate(-50%,-50%) scale(var(--pg-scale,1)); }
  30%     { transform:translate(-50%,-54%) scale(var(--pg-scale,1)) rotate(-4deg); }
  60%     { transform:translate(-50%,-50%) scale(var(--pg-scale,1)) rotate(4deg); }
}

/* 整只：呼吸（所有 SVG 都在 <g class="pg-body"> 里，动它不影响定位） */
.pg-body { transform-origin:50% 78%; animation:pg-breathe 2.6s ease-in-out infinite; }
.pg-eye  { transform-origin:50% 50%; animation:pg-blink 4.2s ease-in-out infinite; }
.pg-ear  { transform-origin:80% 90%; animation:pg-ear-twitch 3.4s ease-in-out infinite; }
.pg-ear2 { transform-origin:20% 90%; animation:pg-ear-twitch 3.4s ease-in-out infinite .5s; }
.pg-tail { transform-origin:10% 80%; animation:pg-tail-wag 1.6s ease-in-out infinite; }
.pg-wing { transform-origin:90% 20%; animation:pg-wing-flap 2.2s ease-in-out infinite; }
.pg-wing2{ transform-origin:10% 20%; animation:pg-wing-flap 2.2s ease-in-out infinite .3s; }
.pg-head { transform-origin:50% 100%; animation:pg-breathe 3.2s ease-in-out infinite; }
/* ★ 每只宠物的动画节奏错开（用 nth-child 给不同 delay），否则一院子的宠物
   整整齐齐同时呼吸，看着像在列队做操，很假。 */
.pg:nth-child(2n) .pg-body  { animation-delay:-0.7s; animation-duration:2.9s; }
.pg:nth-child(3n) .pg-body  { animation-delay:-1.3s; animation-duration:3.2s; }
.pg:nth-child(2n) .pg-eye   { animation-delay:-1.1s; animation-duration:5.1s; }
.pg:nth-child(3n) .pg-eye   { animation-delay:-2.4s; animation-duration:3.6s; }
.pg:nth-child(2n) .pg-tail  { animation-delay:-0.4s; }
.pg:nth-child(3n) .pg-tail  { animation-delay:-0.9s; animation-duration:1.9s; }
/* ★ 翻面已经移到 .pg-flipr 那一层了（.pg-art 改挂待机动作，见下面） */
.pg.react { animation:pg-wobble .5s ease-in-out; }

/* 饿了的宠物：整只变灰 + 慢下来，一眼能看出"它不对劲" */
.pg.hung { filter:grayscale(.55) brightness(.92); }
.pg.hung .pg-body { animation-duration:4.5s; }

/* 底部两个按钮 */
.pgyard-foot {
  display:flex; gap:0.5rem; margin-top:0.7rem; flex-wrap:wrap;
}
.pgyard-foot .btn { flex:1 1 8rem; min-width:0; }

/* ★★ 低配/省电机型：关掉全部宠物动画（本机是 120Hz 但总有人用老机器）
   ⚠ 新增动画记得补进这张名单 —— 漏掉一条，开了"减少动态效果"的用户
      就还有一只在满院子跑，而这正是最需要被关掉的那种动画。 */
@media (prefers-reduced-motion: reduce) {
  .pg-body, .pg-eye, .pg-ear, .pg-ear2, .pg-tail, .pg-wing, .pg-wing2, .pg-head, .pg-heart,
  .pg-move, .pg.idle-hop .pg-art, .pg.idle-waddle .pg-art, .pg.idle-peek .pg-art {
    animation:none !important;
  }
}
/* ★ 手机竖屏（≤520）：院子里的宠物缩小，否则 5 只挤成一团
   （宽度同样受"行距 vs 竖直占用"约束，跟着 .pg 一起调） */
@media (max-width: 520px) {
  .pg { width:21%; max-width:4rem; }
  .pg-talk { width:7.2rem; font-size:0.64rem; }
  .pg-plate { font-size:0.58rem; }
}

/* ══════════ ⑫a 走动 / 待机动作 / 表情（v91 新增）═══════════════════════
   ★★ 这三条一起定义了"这院子是活的"：
      走动 = 它在逛；待机动作 = 它闲着也有自己的事；表情 = 它现在心情怎么样。
   ★ 全部是纯 CSS：院子常驻在页面上，用 JS 定时器会被后台节流、回前台时一次性
     补一堆突变（看着像抽搐）；CSS 动画由合成器驱动，切后台自动暂停，零成本。 */

/* 漫游：四套路径，每只按 id 哈希选一套，行内再给不同的 delay / duration
   ★★ 位移量上限必须**远小于站位间距**：最挤的 3 行布局纵向间距 24%，
      这里的纵向位移只到 ±5%（元素高）≈ 院子高的 ±1.5%，撞不上邻居。
   ⚠ translate 的百分比是相对**元素自身**：宠物块宽 ≈ 院子宽的 17%，
     所以想走院子宽的 ±2%，得写 ±12%。（这个换算改宽度时要重算。） */
@keyframes pg-walk-a {
  0%,100% { transform:translate(0,0); }
  22%     { transform:translate(11%,-4%); }
  46%     { transform:translate(4%,5%); }
  71%     { transform:translate(-9%,-2%); }
}
@keyframes pg-walk-b {
  0%,100% { transform:translate(0,0); }
  26%     { transform:translate(-10%,3%); }
  52%     { transform:translate(6%,-5%); }
  78%     { transform:translate(9%,2%); }
}
@keyframes pg-walk-c {
  0%,100% { transform:translate(0,0); }
  30%     { transform:translate(7%,5%); }
  58%     { transform:translate(-11%,-3%); }
  82%     { transform:translate(3%,-4%); }
}
@keyframes pg-walk-d {          /* 最"宅"的那只：几乎只在原地探头 */
  0%,100% { transform:translate(0,0); }
  35%     { transform:translate(-5%,-4%); }
  65%     { transform:translate(8%,3%); }
}
.pg-move.walk-b { animation-name:pg-walk-b; }
.pg-move.walk-c { animation-name:pg-walk-c; }
.pg-move.walk-d { animation-name:pg-walk-d; }

/* 待机动作：谁蹦、谁摇、谁探头（在 js/views-petyard.js 的 ACT 表里按宠物指定）
   ⚠ 挂在 .pg-art 上 —— 翻面已经移到 .pg-flipr 了，这里只能独占 transform。 */
.pg.idle-hop .pg-art    { animation:pg-hop 5.6s ease-in-out infinite; }
.pg.idle-waddle .pg-art { animation:pg-waddle 3.6s ease-in-out infinite; }
.pg.idle-peek .pg-art   { animation:pg-peek 7.2s ease-in-out infinite; }
@keyframes pg-hop {
  0%,86%,100% { transform:translateY(0); }
  90%         { transform:translateY(-9%); }
  95%         { transform:translateY(0); }
}
@keyframes pg-waddle {
  0%,100% { transform:rotate(-5deg); }
  50%     { transform:rotate(5deg); }
}
@keyframes pg-peek {
  0%,66%,100% { transform:translateY(0); }
  78%,88%     { transform:translateY(7%); }
}

/* ---------- 表情层（开心 ⌒⌒ / 困 ‿‿ / 饿 八字眉）----------
   做法：先在原眼睛上盖一块**和脸同色**的椭圆（.fx-p），再在补丁上画新表情。
   ⚠ fill / stroke 一律写在 CSS 里、不写 SVG presentation attribute ——
      老内核万一不认 var()，写在属性上就是一块黑饼，写在 CSS 里还能被按
      data-pet 的规则救回来（熊猫那两条就是这么救的）。 */
.pg-fx { display:none; }
.fx-p  { fill:var(--pet-a); display:none; }
.fx-e  { display:none; }
.pg.mood-happy  .pg-fx,
.pg.mood-sleepy .pg-fx,
.pg.mood-hungry .pg-fx { display:block; }
.pg.mood-happy  .fx-p, .pg.mood-happy  .fx-happy  { display:block; }
.pg.mood-sleepy .fx-p, .pg.mood-sleepy .fx-sleepy { display:block; }
.pg.mood-hungry .fx-hungry { display:block; }
/* 猫头鹰的眼睛长在 --pet-c 的浅色眼盘上，补丁必须跟着换成 c 色 */
.pg-art[data-pet="owl"] .fx-p { fill:var(--pet-c); }
/* 熊猫反过来：眼珠本来就是亮色（画在黑眼圈上），补丁用 b、线条用亮色 */
.pg-art[data-pet="panda"] .fx-p { fill:var(--pet-b); }
.pg-art[data-pet="panda"] .fx-e { stroke:#fdfdff; }

/* 心情角标：只在非"普通"时出现（饿了 🍖 / 困了 😪 / 开心 😊）
   ★ 放在左上角，和右上的 👑 错开；用 absolute 不占布局，不会影响行距。 */
.pg-mood {
  position:absolute; left:-0.2rem; top:-0.3rem;
  font-size:0.72rem; line-height:1;
  filter:drop-shadow(0 1px 2px rgba(0,0,0,.32));
  z-index:9; pointer-events:none;
}

/* ---------- 新伙伴的静态倾斜层 ----------
   ★★ 一律写在**外层 g** 上：内层元素挂着抖动/摇摆动画，
      CSS animation 的 transform 会整条盖掉同元素上的普通 transform，
      写在同一个元素上会"啪"地弹回原样再抖。 */
.pg-art[data-pet="rabbit"] .pg-tl { transform:rotate(-11deg); transform-origin:50% 100%; }
.pg-art[data-pet="rabbit"] .pg-tr { transform:rotate(11deg);  transform-origin:50% 100%; }
/* 狐尾：绕尾巴根部（bbox 左下）转 12°
   ⚠ 角度不能再大：viewBox 只有 0~100，转过头尾巴尖会被裁掉一截。 */
.pg-art[data-pet="fox"] .pg-tf { transform:rotate(12deg); transform-origin:32% 93%; }
/* 熊猫黑眼圈：椭圆绕自己中心歪一点，正圆的看着像戴了副眼镜 */
.pg-art[data-pet="panda"] .pg-ecl { transform:rotate(-14deg); transform-origin:50% 50%; }
.pg-art[data-pet="panda"] .pg-ecr { transform:rotate(14deg);  transform-origin:50% 50%; }

/* ---------- ⑫c 换毛色面板（js/views-petyard.js 的 PetYard.skinUI）---------- */
.skin-tabs { display:flex; gap:0.4rem; padding:0.15rem 0 0.55rem; overflow-x:auto; }
.skin-tab {
  flex:0 0 auto; width:3.5rem; padding:0.3rem 0.2rem;
  border:1px solid var(--line); border-radius:0.55rem; background:var(--card);
  display:flex; flex-direction:column; align-items:center; gap:0.15rem; cursor:pointer;
}
.skin-tab.on { border-color:var(--brand); background:var(--brand-soft); }
.skin-tab-ico { width:2rem; height:2rem; display:block; line-height:0; }
.skin-tab-ico .pg-svg { width:100%; height:100%; display:block; }
.skin-tab b {
  font-size:0.6rem; font-weight:700; max-width:100%;
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap;
}
.skin-grid { display:grid; grid-template-columns:repeat(auto-fill,minmax(min(4.6rem,100%),1fr)); gap:0.5rem; }
.skin-one {
  display:flex; flex-direction:column; align-items:center; gap:0.22rem;
  padding:0.45rem 0.2rem; border:1px solid var(--line); border-radius:0.6rem;
  background:var(--card); cursor:pointer;
}
.skin-one.on { border-color:var(--brand); background:var(--brand-soft); }
.skin-one.lock .sk-dot { opacity:.62; }
/* 毛色圆点：三段渐变把 a/b/c 三色同时露出来（比只给一个色更能看清这套配色） */
.sk-dot {
  width:2rem; height:2rem; border-radius:50%; display:block;
  border:1px solid rgba(0,0,0,.14);
}
.skin-one b { font-size:0.7rem; font-weight:700; }
.skin-one i { display:block; font-style:normal; font-size:0.6rem; color:var(--sub); line-height:1.4; }
.sk-on { color:var(--ok); font-weight:800; }
.sk-buy { color:var(--gold); font-weight:800; }

/* ---------- ⑫d 背包（js/views-bag.js）----------
   ★ 背包只显示"已经拥有的东西"，所以格子永远是满的，不需要空态样式。 */
.bag-card { padding:0.7rem; }
.bag-head h2 { margin:0 0 0.2rem; font-size:1.05rem; }
.bag-head .sub { font-size:0.78rem; color:var(--sub); line-height:1.6; }
.bag-sec { margin-top:0.9rem; }
.bag-sec h3 { margin:0 0 0.45rem; font-size:0.82rem; font-weight:800; display:flex; align-items:center; gap:0.32rem; }
.bs-n {
  font-size:0.64rem; font-weight:700; color:var(--sub);
  background:var(--bg); border-radius:99px; padding:0.05rem 0.36rem;
}
.bag-grid { display:grid; grid-template-columns:repeat(auto-fill,minmax(min(5.2rem,100%),1fr)); gap:0.45rem; }
.bag-cell {
  display:flex; flex-direction:column; align-items:center; gap:0.14rem;
  padding:0.5rem 0.25rem; border:1px solid var(--line); border-radius:0.6rem;
  background:var(--card); text-align:center;
}
.bag-cell.on { border-color:var(--brand); background:var(--brand-soft); }
.bc-ico {
  width:2.2rem; height:2.2rem; display:flex; align-items:center;
  justify-content:center; line-height:0; font-size:1.5rem;
}
.bc-ico .pg-svg { width:100%; height:100%; display:block; }
.bc-ico .sk-dot { width:1.9rem; height:1.9rem; }
.bag-cell b { font-size:0.7rem; font-weight:700; word-break:break-all; line-height:1.3; }
.bc-sub { font-size:0.6rem; color:var(--sub); line-height:1.45; }
.bc-n { font-size:0.68rem; font-weight:800; color:var(--brand); }
/* ---------- ⑫f 背包折算（js/views-bag.js 的 Bag.sell）----------
   ★ 折算按钮挂在格子右下角，平时是"低调的一行小字"，别抢了物品本身。
   ⚠ 老内核友好：这里全是基础属性（flex / border / border-radius），
      没有 gap 之外的现代语法；gap 在本项目里已大量使用，安全。 */
.bc-sell {
  display:flex; align-items:center; justify-content:center; gap:0.15rem;
  margin-top:auto; padding:0.12rem 0.4rem;
  border:1px solid var(--line); border-radius:0.5rem;
  background:var(--bg); color:var(--sub);
  font-size:0.62rem; font-weight:800; cursor:pointer;
}
.bc-sell:active { background:var(--brand-soft); color:var(--brand); border-color:var(--brand); }
.bc-sell .bs-ic { display:flex; align-items:center; line-height:0; }
/* ★ v116 扭蛋专属道具的「使用」按钮：和「折算」同一套尺寸，
   但用主色描边区分 —— 折算是"换成积分"，使用是"真的干一件事"，不能长得一样。 */
.bc-use {
  display:flex; align-items:center; justify-content:center;
  margin-top:auto; padding:0.12rem 0.5rem;
  border:1px solid var(--brand); border-radius:0.5rem;
  background:var(--brand-soft); color:var(--brand);
  font-size:0.62rem; font-weight:800; cursor:pointer;
}
.bc-use:active { background:var(--brand); color:#fff; }
/* ★ v126 外观的「换上 / 脱下」：同尺寸，但用**虚线描边**和「使用」区分开 ——
   「使用」是把一件消耗品真的用掉，「换上」只是换件衣服，随时能换回来。
   ⚠ 老内核规矩：border-style 单独写一条，别塞进 border 简写里。 */
.bc-cos {
  display:flex; align-items:center; justify-content:center;
  margin-top:auto; padding:0.12rem 0.5rem;
  border:1px solid var(--brand); border-style:dashed; border-radius:0.5rem;
  background:none; color:var(--brand);
  font-size:0.62rem; font-weight:800; cursor:pointer;
}
.bc-cos:active { background:var(--brand-soft); }
.bs-note { margin-top:0.4rem; font-size:0.72rem; }
.bl { color:var(--brand); font-weight:700; }
.bag-foot { display:flex; gap:0.5rem; margin-top:0.9rem; flex-wrap:wrap; }
.bag-foot .btn { flex:1 1 7rem; min-width:0; }

/* ---------- ⑫f2 背包 · 批量选择折算（2026-10-17「先选择再折算」）----------
   ⚠ 只加基础属性：flex / border / border-radius / position:sticky。
     老内核不认的属性会**整条丢弃**（不报错），所以这里一律不用 gap 之外的现代写法。 */
.bag-acts { display:flex; justify-content:flex-end; margin-top:0.5rem; }
/* 选中的格子：主色描边 + 浅底，一眼看出"这个要折掉" */
.bag-cell.picked { border-color:var(--brand); background:var(--brand-soft); }
/* 数量步进器：替代普通模式下的 ⭐折算按钮 */
.bc-step {
  display:flex; align-items:center; justify-content:center; gap:0.25rem;
  margin-top:auto; padding:0.1rem 0.2rem;
  border:1px solid var(--line); border-radius:0.5rem; background:var(--bg);
}
.bc-step.on { border-color:var(--brand); background:var(--brand-soft); }
.bc-step b { font-size:0.62rem; font-weight:800; color:var(--sub); min-width:2.1rem; }
.bc-step.on b { color:var(--brand); }
.bc-step button {
  width:1.15rem; height:1.15rem; flex:none;
  display:flex; align-items:center; justify-content:center;
  border:1px solid var(--line); border-radius:0.35rem;
  background:var(--card); color:var(--ink); font-size:0.7rem; font-weight:800; cursor:pointer;
}
.bc-step button:disabled { opacity:.4; cursor:default; }
/* 结算条：吸在背包卡底部，滚到哪都看得见选了多少、值多少分
   ⚠ 用 sticky 不用 fixed —— fixed 会压住底部导航栏 */
.bag-selbar {
  position:sticky; bottom:0; z-index:5;
  display:flex; align-items:center; gap:0.5rem; flex-wrap:wrap;
  margin-top:0.9rem; padding:0.55rem 0.65rem;
  border:1px solid var(--brand-line); border-radius:0.7rem;
  background:var(--card); box-shadow:0 -0.25rem 0.75rem rgba(0,0,0,.08);
}
.bag-selbar .sb-l { flex:1 1 8rem; min-width:0; font-size:0.78rem; color:var(--sub); }
.bag-selbar .sb-l b { color:var(--ink); }
.bag-selbar .sb-r { display:flex; gap:0.4rem; flex:none; }

/* ---------- ⑫g 折算弹窗（数量选择）---------- */
.sell-box {
  padding:0.6rem 0.7rem; border:1px solid var(--line); border-radius:0.6rem;
  background:var(--card); text-align:left;
}
.sell-hd { font-size:0.9rem; font-weight:800; margin-bottom:0.4rem; }
.sell-row { display:flex; justify-content:space-between; align-items:center; font-size:0.78rem; padding:0.12rem 0; }
.sell-row span { color:var(--sub); }
.sell-row b { font-weight:800; }
.sell-n { display:flex; align-items:center; justify-content:center; gap:0.5rem; margin-top:0.7rem; }
.sell-n > b { min-width:2rem; text-align:center; font-size:1.05rem; font-weight:800; }
.sn-b {
  min-width:2.2rem; padding:0.3rem 0.5rem;
  border:1px solid var(--line); border-radius:0.5rem;
  background:var(--card); color:var(--ink);
  font-size:0.9rem; font-weight:800; cursor:pointer;
}
.sn-b:active { background:var(--brand-soft); }
.sn-b.wide { min-width:3.4rem; font-size:0.78rem; }

/* ★★ v105：⑫e「换头像面板」的样式（.bag-avgrid / .bag-av / .av-svg / .av-def）
   整块删除 —— Bag.avatarUI() 已经删掉，这些类名没有任何生成者了。
   js/avatar-art.js 也随之不再加载（它才是 av-svg 的唯一来源）。 */

/* ---------- ⑫f 资料卡头像（★ v105：不再可点，就是一枚称号图标）---------- */
/* ⚠★ 这里**不能写 line-height:0**（踩过）：那是给 inline SVG 消底部空隙的惯用招，
   但没换过头像的老用户，框里放的还是 emoji 🥚 —— line-height:0 会把 emoji 压成
   0 高，头像和名字之间空出一大块，整个资料卡看着"散架"。
   正确做法：让框正常按字体撑高（emoji 与 SVG 等高），只对内部的 SVG 做 block 化。
   ⚠ v105 起头像不可点了 → **去掉 cursor:pointer**（看着能点却点不动，比没有提示更糟）。 */
.pf-av { display:inline-block; position:relative; }
.pf-av:active { opacity:.66; }
/* 右下角那支小铅笔：不给这个提示，大部分人不会知道自己的头像是能点的。
   ⚠ font-size 用 em —— 外层 .pf-av 的 3rem 是行内写死的，跟着它缩放才对得上。
   ⚠★ 别用 bottom:0 + right:-0.15rem（贴在圆内会压住脸蛋，看着像贴纸糊上去的）。
      挪到圆的**外沿右下角**：right/bottom 各 -0.22em，正好落在圆外那圈留白里。 */
.pf-av::after {
  content:"✏️"; position:absolute; right:-0.22em; bottom:-0.1em;
  font-size:0.30em; line-height:1;
  filter:drop-shadow(0 1px 2px rgba(0,0,0,.3));
  pointer-events:none;
}

/* ---------- ⑫b 首页伙伴条 / 「我的」页入口里的 2D 形象 ---------- */
/* 首页伙伴条左侧原来是 emoji（.pet-ico），换成 2D 形象后要自适应大小 */
.petbar .pet-ico .pg-svg { width:2.4rem; height:2.4rem; display:block; }
.petbar-svg { width:2.4rem; height:2.4rem; display:block; }
/* 首页伙伴条下方的「宠物院」按钮 */
.petbar-yard {
  margin:0.35rem 0 0; width:100%;
  background:var(--ok-soft); color:var(--ok); border-color:transparent;
}
/* 「我的」页的宠物院入口卡（和探险卡同一套骨架） */
.pgy-entry {
  margin:0.6rem 0; padding:0.65rem 0.8rem;
  border:1px solid var(--line); border-radius:0.75rem; background:var(--card);
}
.pgy-minirow {
  display:flex; align-items:flex-end; gap:0.15rem; margin:0.4rem 0 0.1rem;
  padding:0.35rem 0.5rem; border-radius:0.6rem;
  background:linear-gradient(to bottom, #bfe4ff 0%, #cdeaff 55%, #8ed36a 55%, #6cbb4d 100%);
  min-height:3.2rem;
}
body.theme-dark .pgy-minirow {
  background:linear-gradient(to bottom, #1b2440 0%, #2a3457 55%, #2c5346 55%, #20403a 100%);
}
.pgy-mini { display:block; width:2.4rem; height:2.4rem; line-height:0; }
.pgy-mini .pg-svg { width:100%; height:100%; display:block; }
.pgy-mini.cur { filter:drop-shadow(0 0 4px #ffd45e); }
.pgy-mini > i { font-size:1.2rem; font-style:normal; line-height:2.4rem; display:block; text-align:center; }
.pgy-more { font-size:0.72rem; font-weight:800; color:#fff; text-shadow:0 1px 3px rgba(0,0,0,.45); align-self:center; }

/* 前排宠物的对话泡：改从**下方**弹出。
   ★ 前排头顶就是后排宠物，气泡往上弹会压住后排的名字牌（截图见过）；
     改成往下弹，箭头也跟着翻到上方。 */
.pg.front .pg-talk {
  bottom:auto; top:100%; transform:translate(-50%,0.35rem);
}
.pg.front .pg-talk::after {
  bottom:auto; top:-0.3rem; border-top-color:transparent; border-bottom-color:#fff;
}
body.theme-dark .pg.front .pg-talk::after { border-bottom-color:#2b3350; }

/* ══════════ ⑬ 夜空：常驻星空 + 偶发流星（js/sky.js）═════════════════════
   ★ 整层 z-index:-1：html 没有背景色，body 的背景会传播成**画布背景**，
     而画布背景永远最先画 —— 所以这层正好落在「背景之上、内容之下」：
     卡片挡住的地方看不到星，露出来的空隙才是夜空，**绝不会盖到文字上**。
     （不依赖 mix-blend-mode，老内核一样稳。）
   ★ inset 按项目铁律先写四个方向长写兜底、再写 inset 简写。 */
.xy-sky {
  position:fixed; top:0; right:0; bottom:0; left:0; inset:0;
  z-index:-1; pointer-events:none; overflow:hidden;
}
/* 星点：只靠 CSS animation 闪（opacity + scale，走合成器），不用 JS 每帧算。
   ★ 基础 opacity 写在规则里 —— 像素回归会注入 animation:none，
     那时星星要停在静态亮度上，不能变成 opacity:0 整片消失。 */
.xy-sky .xy-star {
  position:absolute; border-radius:50%; background:#fdfdff; opacity:.72;
  box-shadow:0 0 5px 1.5px rgba(196,218,255,.7);
  animation:xy-twk 3.4s ease-in-out infinite;
}
.xy-sky .xy-star.big { box-shadow:0 0 10px 3px rgba(206,224,255,.85); }
@keyframes xy-twk {
  0%,100% { opacity:.34; transform:scale(.85); }
  50%     { opacity:1;   transform:scale(1.18); }
}

/* 流星层：**在内容之上**（45），但低于顶栏 50 / 底栏 60 / 弹窗 400 ——
   流星从"窗框下面"穿过，被顶栏底栏切掉是正常的。
   ★ 故意**不用** mix-blend-mode：一层常驻的全屏混合层会一直把整页拉进合成组，
     在这台 120Hz 的弱机上是白给的开销；而流星只在黑夜出现，底本来就是暗的，
     直接用亮色线条就已经"只提亮不压暗"了。（渐进增强不是必须。） */
.xy-meteor-layer {
  position:fixed; top:0; right:0; bottom:0; left:0; inset:0;
  z-index:45; pointer-events:none; overflow:hidden;
}
/* 尾巴 i 用 right:0 落在原点的**左侧**（= 飞行方向的后方），b 是亮核。
   位置/角度/长度/时长全由 js 写在行内，这里只管长相。 */
.xy-meteor-layer .xy-meteor { position:absolute; width:0; height:0; }
.xy-meteor-layer .xy-meteor i {
  position:absolute; right:0; top:-1.5px; height:3px; border-radius:99px;
  background:linear-gradient(to right, rgba(208,228,255,0) 0%, rgba(214,232,255,.78) 62%, #ffffff 100%);
  box-shadow:0 0 11px 2.5px rgba(160,198,255,.5);
}
.xy-meteor-layer .xy-meteor b {
  position:absolute; right:-2.5px; top:-3px; width:8px; height:8px; border-radius:50%;
  background:#fff; box-shadow:0 0 13px 4.5px rgba(170,205,255,.55);
}

/* 关掉动效时：星星静态挂着（不闪），流星本来就不会生成（js 里已拦）。 */
@media (prefers-reduced-motion: reduce) {
  .xy-sky .xy-star { animation:none; }
}

/* ============ 抽奖专属外观（v126，js/cosmetic.js 往 body 上打类）============
   ★ 为什么用 body 上的类 + CSS 覆盖，而不是在 JS 里改行内样式：
     ① 老内核稳 —— 换颜色这类事 CSS 最不容易出岔子；
     ② 不加 DOM、不加 JS 分支，流星/星星的生成逻辑一个字都不用改；
     ③ 关掉特效只要移除一个类名，不会有残留。
   ⚠ 选择器必须写成 `.xy-meteor-layer .xy-meteor i`（两层级），
     否则压不过上面那条同样两层的默认规则（specificity 平手时后写的赢，
     但万一以后有人调整顺序就会翻车 —— 层级写全最保险）。 */

/* ☄️ 金辉流星：暖金尾 + 金色亮核 */
body.cos-mt-gold .xy-meteor-layer .xy-meteor i {
  background:linear-gradient(to right, rgba(255,196,84,0) 0%, rgba(255,196,84,.82) 62%, #fff7df 100%);
  box-shadow:0 0 11px 2.5px rgba(255,178,48,.55);
}
body.cos-mt-gold .xy-meteor-layer .xy-meteor b {
  background:#fff6d8; box-shadow:0 0 13px 4.5px rgba(255,186,60,.6);
}
/* 🌈 彩虹流星：尾巴做成一整条彩虹（金档才抽得到，所以要够扎眼） */
body.cos-mt-rainbow .xy-meteor-layer .xy-meteor i {
  background:linear-gradient(to right, rgba(255,255,255,0) 0%, #ffd7ea 22%, #d9e6ff 44%, #d3ffe9 68%, #fff2c4 100%);
  box-shadow:0 0 12px 3px rgba(255,214,236,.55);
}
body.cos-mt-rainbow .xy-meteor-layer .xy-meteor b {
  background:#fff; box-shadow:0 0 14px 5px rgba(255,205,232,.6);
}
/* 🌌 极光夜空：星星染成极光的青紫两色，大星偏暖黄做点缀 */
body.cos-sky-aurora .xy-sky .xy-star {
  background:#b9ffe4; box-shadow:0 0 6px 2px rgba(110,255,205,.75);
}
body.cos-sky-aurora .xy-sky .xy-star.big {
  background:#e7d4ff; box-shadow:0 0 11px 3.5px rgba(170,130,255,.8);
}

/* ==================================================================
   v102 · 版权声明 / 反馈建议 / 站长收件箱
   ★ 老内核铁律：① 新语法先长写兜底、后简写；② 危险选择器不与普通选择器混写；
     ③ 一律 rem（--ui-scale 是唯一缩放入口）；④ 只认 --ink/--bg/--card/--sub/
     --line/--brand/--brand-soft/--gold/--gold-ink/--warn-soft/--ok/--bad。
   ================================================================== */

/* ---------- 版权声明 ---------- */
/* 去 AI 味：不铺渐变大块、不反白字。条款就是纸面正文，靠字号与留白分层。 */
.cr-lead {
  padding: 0.625rem 0.75rem;
  font-size: 0.82rem;
  line-height: 1.75;
  color: var(--ink);
  background: var(--warn-soft);
  border-left: 3px solid var(--warn);
  border-radius: 0.5rem;
}
.cr-sec { margin-top: 0.875rem; }
.cr-sec b { display: block; font-size: 0.86rem; font-weight: 800; color: var(--ink); margin-bottom: 0.25rem; }
.cr-sec p { margin: 0; font-size: 0.8rem; line-height: 1.8; color: var(--ink); }
.cr-sec ul { margin: 0; padding-left: 1.15rem; }
.cr-sec li { font-size: 0.8rem; line-height: 1.75; color: var(--ink); margin-bottom: 0.125rem; }
.cr-foot {
  margin-top: 0.875rem;
  padding-top: 0.625rem;
  border-top: 1px dashed var(--line);
  font-size: 0.72rem;
  line-height: 1.7;
  color: var(--sub);
  text-align: center;
}

/* ---------- 反馈：登录 ---------- */
.fb-tel {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  background: var(--bg);
  border: 1px solid var(--line);
  border-radius: 0.5625rem;
  padding: 0.25rem 0.5rem;
}
.fb-pre { flex: none; font-size: 0.82rem; font-weight: 700; color: var(--sub); }
.fb-tel input {
  flex: 1;
  min-width: 0;
  background: none;
  border: none;
  font-size: 0.95rem;
  font-weight: 700;
  letter-spacing: 0.04em;
  color: var(--ink);
  padding: 0.375rem 0;
}
.fb-code-row { display: flex; align-items: center; gap: 0.5rem; margin-top: 0.5rem; }
.fb-code-row input {
  flex: 1;
  min-width: 0;
  background: var(--bg);
  border: 1px solid var(--line);
  border-radius: 0.5625rem;
  padding: 0.4375rem 0.5625rem;
  font-size: 0.95rem;
  font-weight: 700;
  letter-spacing: 0.12em;
  color: var(--ink);
}
.fb-err { min-height: 1rem; font-size: 0.74rem; color: var(--bad); margin-top: 0.25rem; }
.fb-note { margin-top: 0.5rem; font-size: 0.72rem; line-height: 1.7; }

/* ---------- 反馈：表单 ---------- */
/* 未登录时盖在表单卡上的一层：说清"为什么不能用"，比一堆灰按钮强 */
.fb-lockmask {
  position: absolute;
  top: 0; right: 0; bottom: 0; left: 0;
  inset: 0;
  z-index: 5;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--card);
  border-radius: 0.75rem;
}
.fb-lock-in { display: flex; flex-direction: column; align-items: center; gap: 0.25rem; color: var(--sub); }
.fb-lock-in b { font-size: 0.88rem; color: var(--ink); }
.fb-lock-in span { font-size: 0.74rem; }

.fb-kind { margin-bottom: 0.625rem; }
.fb-text {
  width: 100%;
  box-sizing: border-box;
  background: var(--bg);
  border: 1px solid var(--line);
  border-radius: 0.5625rem;
  padding: 0.5rem 0.625rem;
  font-size: 0.84rem;
  line-height: 1.7;
  color: var(--ink);
  resize: vertical;
}
.fb-count { text-align: right; font-size: 0.68rem; color: var(--sub); margin-top: 0.125rem; }
.fb-contact {
  width: 100%;
  box-sizing: border-box;
  background: var(--bg);
  border: 1px solid var(--line);
  border-radius: 0.5625rem;
  padding: 0.4375rem 0.5625rem;
  font-size: 0.84rem;
  color: var(--ink);
  margin-top: 0.5rem;
}
.fb-pickrow { display: flex; align-items: center; gap: 0.5rem; margin-top: 0.625rem; flex-wrap: wrap; }
.fb-files { display: none; margin-top: 0.5rem; }
.fb-file {
  display: flex;
  align-items: center;
  gap: 0.4375rem;
  padding: 0.3125rem 0.125rem;
  border-bottom: 1px dashed var(--line);
}
.fb-file .ff-i { flex: none; font-size: 0.95rem; line-height: 1; }
.fb-file .ff-n { flex: 1; min-width: 0; font-size: 0.78rem; color: var(--ink); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.fb-file .ff-s { flex: none; font-size: 0.7rem; color: var(--sub); }
.fb-file .ff-x {
  flex: none;
  width: 1.375rem;
  height: 1.375rem;
  border-radius: 50%;
  background: var(--bg);
  border: none;
  color: var(--sub);
  font-size: 0.72rem;
  cursor: pointer;
}
.fb-foot { text-align: center; padding: 0.75rem 0 0.25rem; font-size: 0.72rem; }
.fb-admin { color: var(--sub); cursor: pointer; text-decoration: underline; }
.fb-cr, #fb-cr { color: var(--sub); cursor: pointer; text-decoration: underline; }
.fb-foot2 { margin-top: 0.25rem; font-size: 0.68rem; color: var(--sub); }

/* ---------- v127 公告 / 福利 / 更新说明 ----------
   ★ 三条纪律（去 AI 味那五条的延续）：
     ① 不用大块渐变、不反白字 —— 「为什么发」用一层极淡的底色 + 左侧 2px 主色竖条区分；
     ② 不卡片套卡片 —— 公告列表里的小块没有自己的边框和圆角；
     ③ 图标不带彩色底方块 —— 🎁 / ✨ 直接是文字颜色。 */
.gift-top { display: flex; align-items: center; gap: 0.5rem; }
.gift-top svg { flex: none; }
.gift-tt { font-size: 1rem; font-weight: 800; line-height: 1.45; color: var(--ink); }
/* 「为什么发」：这是整套功能里最要紧的一块 —— 用户凭它判断这笔分拿得踏不踏实。
   所以给它一个能认出来的形状（左侧竖条），但不做成醒目的警告色（不是坏事）。 */
.gift-why {
  margin-top: 0.625rem;
  padding: 0.5rem 0.625rem;
  padding-left: 0.75rem;
  border-left: 2px solid var(--brand);
  border-top-left-radius: 0;
  border-bottom-left-radius: 0;
  border-radius: 0.5rem;
  background: var(--brand-soft);
  font-size: 0.8rem;
  line-height: 1.75;
  color: var(--ink);
}
.gift-why b { display: block; margin-bottom: 0.125rem; font-size: 0.76rem; color: var(--brand); }
.gift-pts {
  margin-top: 0.625rem;
  font-size: 1.05rem;
  font-weight: 800;
  color: var(--gold-ink);
}
/* 更新说明：版本号一行 + 一条条说明。刻意不用时间轴样式（那是从别处抄来的模板感） */
.chg-ver { font-size: 0.78rem; font-weight: 800; color: var(--brand); margin-bottom: 0.5rem; }
.chg-item { padding: 0.4375rem 0; border-top: 1px dashed var(--line); }
.chg-item:first-of-type { border-top: 0; }
.chg-item b { display: block; font-size: 0.8rem; color: var(--ink); }
.chg-item div { margin-top: 0.125rem; font-size: 0.78rem; line-height: 1.7; color: var(--sub); }
/* ★ v129 更新说明里的两段「汇报」：反馈收件箱 + 本期补偿。
   ★ 去 AI 味：不套卡片、不用胶囊标签，只用一条细分割线 + 小标题（和上面 chg-item 同一族）。 */
.chg-sec { margin-top: 0.625rem; padding-top: 0.5rem; border-top: 1px solid var(--line); }
.chg-sec-hd { display: flex; align-items: center; gap: 0.25rem; font-size: 0.78rem; font-weight: 800; color: var(--ink); }
.chg-sec-hd svg { flex: none; }
.chg-sec-b { margin-top: 0.25rem; font-size: 0.78rem; line-height: 1.75; color: var(--sub); }
.chg-comp { margin-top: 0.375rem; padding-left: 0.5rem; border-left: 2px solid var(--gold-line); }
.chg-comp b { font-size: 0.78rem; color: var(--ink); }
.chg-comp-why { margin-top: 0.0625rem; font-size: 0.74rem; line-height: 1.7; color: var(--sub); }
/* 公告列表（「公告与消息」页 + 后台的已发布列表） */
.ann-item { padding: 0.5rem 0; border-top: 1px dashed var(--line); }
.ann-item:first-of-type { border-top: 0; }
.ann-hd { display: flex; align-items: center; gap: 0.375rem; flex-wrap: wrap; }
.ann-hd b { font-size: 0.9rem; color: var(--ink); }
.ann-ft { display: flex; align-items: center; gap: 0.5rem; flex-wrap: wrap; margin-top: 0.375rem; }
.ann-ft .sub { font-size: 0.72rem; }
.ann-list { margin-top: 0.75rem; }
.ann-row { padding: 0.5rem 0; border-top: 1px dashed var(--line); }
.ann-row:first-child { border-top: 0; }

/* ---------- 收件箱 ---------- */
.inb-item { padding-top: 0.625rem; }
.inb-item.mine { padding: 0.5rem 0.125rem; border-bottom: 1px dashed var(--line); }
.inb-hd { display: flex; align-items: center; gap: 0.375rem; flex-wrap: wrap; }
.inb-time { font-size: 0.7rem; color: var(--sub); }
.inb-who { font-size: 0.7rem; color: var(--sub); }
.inb-body { margin-top: 0.375rem; font-size: 0.84rem; line-height: 1.75; color: var(--ink); word-break: break-word; }
.inb-contact { margin-top: 0.25rem; font-size: 0.76rem; color: var(--brand); word-break: break-all; }
.inb-note {
  margin-top: 0.375rem;
  padding: 0.375rem 0.5rem;
  font-size: 0.76rem;
  line-height: 1.7;
  color: var(--ink);
  background: var(--brand-soft);
  border-radius: 0.5rem;
}
.inb-files { display: flex; gap: 0.375rem; flex-wrap: wrap; margin-top: 0.4375rem; }
.inb-f, .inb-fa {
  display: inline-block;
  font-size: 0.7rem;
  color: var(--brand);
  background: var(--bg);
  border-radius: 0.4375rem;
  padding: 0.1875rem 0.4375rem;
  text-decoration: none;
}
.inb-fa.img { padding: 0.125rem; line-height: 0; }
.inb-fa.img img { display: block; height: 3.75rem; width: auto; border-radius: 0.375rem; }
.inb-f.dead, .inb-fa.dead { color: var(--bad); }
.inb-ops { display: flex; gap: 0.375rem; flex-wrap: wrap; margin-top: 0.5rem; }
.inb-dev { margin-top: 0.375rem; font-size: 0.66rem; color: var(--sub); word-break: break-all; }


/* ---------- 全站登录门（v106） ----------
   ⚠ 老内核规矩：top/right/bottom/left 长写在前、inset 简写在后（照 #modal-root 的写法）。
   z-index 900 = 高于弹窗(400)与顶栏(50)，低于启动报错层(9999)。
   ★ 居中用 margin:auto 而不是 align-items:center —— 后者在内容比屏幕高时会裁掉顶部，
     小屏上手机号输入框就再也滚不到了。 */
#authgate {
  position: fixed;
  top: 0; right: 0; bottom: 0; left: 0;
  inset: 0;
  z-index: 900;
  display: none;
  padding: 1.25rem;
  background: var(--bg);
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
}
.ag-wrap { margin: auto; width: 100%; max-width: 25rem; }
/* ★ 登录门自带的昼夜开关（v115）：门是全屏 fixed，顶栏那个够不着。
   ⚠ 老内核不认简写的 flex，所以一律**先长写、后简写**：
      只写 `justify-content:flex-end` 而前一行没写 `display:flex` 的话整条会被丢掉。

   ★★ v121 用户要求：「放在右上角，不要太长」。
      ① 右上角 = 绝对定位到 **#authgate 的右上角**（#authgate 是 fixed，天然是包含块），
         而不是留在 .ag-wrap 的文档流里 —— 后者在宽屏上会被 25rem 的居中列带着走，
         看着像"挂在表单上方"，不在角上。
      ② 不要太长 = 9·6 那段已收窄成 `.topchips .dn`，这里恢复本体 3.25rem 胶囊；
         再钉一条 width，防止以后又冒出全局 `.dn{width:100%}`。 */
.ag-top {
  position:absolute; top:0.875rem; right:0.875rem;
  display:block; display:flex; align-items:center; justify-content:flex-end;
  margin:0; z-index:3;
}
#ag-dn { width:3.25rem; }
.ag-brand { text-align: center; margin-bottom: 1.5rem; }
.ag-logo { font-size: 1.75rem; line-height: 1.2; }
.ag-brand h1 { font-size: 1.375rem; font-weight: 800; margin-top: 0.375rem; margin-bottom: 0.25rem; color: var(--ink); letter-spacing: 0.02em; }
.ag-brand p { font-size: 0.78rem; color: var(--sub); }
.ag-card { padding: 1rem; }
.ag-tip {
  font-size: 0.76rem; line-height: 1.7; color: var(--sub);
  background: var(--bg); border-radius: 0.5rem;
  padding: 0.5rem 0.625rem; margin-bottom: 0.75rem;
}
.ag-tip.ok { color: var(--brand); }
.fld { margin-bottom: 0.75rem; }
.fld label { display: block; font-size: 0.76rem; font-weight: 700; color: var(--sub); margin-bottom: 0.3125rem; }
.fld input {
  width: 100%;
  background: var(--bg);
  border: 1px solid var(--line);
  border-radius: 0.5625rem;
  padding: 0.5rem 0.625rem;
  font-size: 0.95rem;
  color: var(--ink);
}
.fld input:focus { outline: none; border-color: var(--brand); }
.ag-inline { display: flex; align-items: center; }
.ag-inline input { flex: 1; min-width: 0; }
.ag-inline #ag-send { flex: none; white-space: nowrap; margin-left: 0.5rem; }
.ag-row { display: flex; align-items: center; justify-content: space-between; margin-bottom: 0.5rem; }
.ag-err { min-height: 1rem; font-size: 0.74rem; color: var(--bad); margin-top: 0.25rem; }
.ag-note { margin-top: 0.625rem; font-size: 0.72rem; line-height: 1.7; }
.ag-foot { margin-top: 1rem; text-align: center; font-size: 0.72rem; color: var(--sub); line-height: 1.7; }
/* 文字按钮：给「忘记密码」「用验证码登录」这类次要动作用，不带背景块 */
.btn.link {
  background: none; border: none; box-shadow: none;
  padding: 0; border-radius: 0; min-height: 0;
  line-height: inherit; color: var(--brand); font-weight: 700; font-size: inherit;
  cursor: pointer; text-decoration: underline;
}
.btn.link:disabled { color: var(--sub); cursor: default; text-decoration: none; }


.fb-who { display: flex; align-items: center; font-size: 0.74rem; line-height: 1.6; color: var(--sub); background: var(--bg); border-radius: 0.5rem; padding: 0.4375rem 0.625rem; margin-bottom: 0.625rem; }
.fb-who b { color: var(--ink); }
/* ⚠ 危险选择器不与普通选择器混写（老内核会整条丢），单独成一条 */
.fb-who span:first-child { margin-right: 0.375rem; }

/* ===== 知识点「图文」层（v131）=====
   ★ 起因：用户「或用些思维导图什么的，不能完全靠文字」。
   ★ 结构图是**内联 SVG**，viewBox 宽 360：窄屏按 1:1 画（字才不会缩成蚂蚁），
     宽屏由 max-width 整体放大 —— 矢量放大不糊，所以不用做两套图。
   ⚠ 图里的颜色全是 SVG 属性里的 var(--…)，主题切换自动跟随，这里不要再补一套色。 */
.mindbox { background:var(--card); border:1px solid var(--line); border-radius:var(--radius); box-shadow:var(--shadow); padding:0.875rem 1rem 1rem; margin-bottom:0.875rem; }
.mind-hd { font-size:0.95rem; font-weight:800; display:flex; align-items:center; gap:0.4375rem; margin-bottom:0.25rem; }
.mind-hd svg { flex:none; }
.mind-sub { font-size:0.76rem; line-height:1.7; color:var(--sub); margin-bottom:0.625rem; }
.mind-svg { display:block; width:100%; height:auto; margin:0 auto 0.625rem; max-width:32rem; }
.mind-svg text { font-family:inherit; }
/* 规则 / 例子分栏：把「例子：」之后的内容单独摆一块。
   混在一整段里，扫读的人只看到一堵字；分开之后「结论」和「例证」各归各位。
   ⚠ 长段落被切成多句之后，块与块之间要留白，否则又糊成一团。 */
.gp > p + .gp-eg, .gp > .gp-tb + .gp-tbnt { margin-top:0.5rem; }
.gp-eg { display:flex; align-items:flex-start; margin-top:0.5rem; font-size:0.8rem; line-height:1.75; color:var(--sub); background:var(--bg); border-radius:var(--radius-s); padding:0.5rem 0.625rem; }
.gp-eg-t { flex:none; margin-right:0.4375rem; margin-top:0.0625rem; font-size:0.68rem; font-weight:800; color:var(--brand); background:var(--brand-soft); border-radius:0.25rem; padding:0 0.3125rem; line-height:1.7; }

/* ---- 规则清单表（v132）：把「…：例词；…：例词」排成两列对照 ----
   ★ 用户原话：加 s / 加 es / 变 ves 这些规矩混在一段里，「段落不分明」。
     排成表后左列竖着读是规矩，右列竖着读是例词，眼睛不用来回跳。
   ⚠ 必须能塞进 19rem 的要点格子里：table-layout:fixed + 右列折行，绝不横向撑破。 */
.gp-tb { margin-top:0.5rem; border:1px solid var(--line); border-radius:var(--radius-s); overflow:hidden; }
.gp-tb table { width:100%; border-collapse:collapse; table-layout:fixed; font-size:0.8rem; line-height:1.65; }
.gp-tb col.tb-c1 { width:48%; }
.gp-tb th { font-size:0.68rem; font-weight:800; color:var(--sub); text-align:left; letter-spacing:.04em; background:var(--bg); padding:0.3125rem 0.5625rem; border-bottom:1px solid var(--line); }
.gp-tb td { padding:0.4375rem 0.5625rem; vertical-align:top; border-bottom:1px solid var(--line); }
.gp-tb th + th, .gp-tb td + td { border-left:1px solid var(--line); }
.gp-tb tbody tr:last-child td { border-bottom:0; }
.gp-tb td:first-child { font-weight:600; color:var(--ink); }
.gp-tb td.tb-eg { color:var(--brand); word-break:break-word; }
.gp-tb .tb-ar { font-weight:800; font-style:normal; color:var(--sub); }
.gp-tbnt { margin-top:0.4375rem; font-size:0.76rem; line-height:1.7; color:var(--sub); display:flex; align-items:flex-start; }
.gp-tbnt-t { flex:none; margin-right:0.375rem; font-size:0.66rem; font-weight:800; color:var(--warn); background:var(--warn-soft); border-radius:0.25rem; padding:0 0.25rem; line-height:1.7; }

/* ==================== v139 智能评判 ====================
   要点：
   ① 去 AI 味 —— 判定卡是一个「清单」而不是一块大色卡，用行内小勾叉不用胶囊；
   ② #view 是 flex:1，开 grid 一律带 align-content:start；
   ③ 代码区右侧横向滚动（C 代码行长），绝不做自动换行 —— 换行会把缩进折没。 */

/* 左右分栏：题目在左、写代码在右。
   ★ 屏够宽就分栏（wide 是笔记本 1100+，desk 是 1500+ 大屏）；
     窄屏竖排，否则代码区会被挤成一条缝。响应式靠 data-lay，不用 @media。 */
.cj-wrap { display:grid; grid-template-columns:minmax(0,1fr); gap:0.75rem; align-content:start; }
html[data-lay="wide"] .cj-wrap { grid-template-columns:minmax(0,1.02fr) minmax(0,1fr); gap:0.875rem; }
html[data-lay="desk"] .cj-wrap { grid-template-columns:minmax(0,1.02fr) minmax(0,1fr); gap:1rem; }
.cj-q { min-width:0; }
.cj-io { min-width:0; }

.cj-box { background:var(--card); border:1px solid var(--line); border-radius:var(--radius-s); padding:0.6875rem; }
.cj-hd { font-size:0.8rem; font-weight:700; color:var(--ink); margin-bottom:0.5rem; }
.cj-tip { margin-top:0.4375rem; font-size:0.72rem; line-height:1.6; color:var(--sub); }

/* ---- 编辑器 ---- */
.ced { display:flex; align-items:stretch; background:var(--bg); border:1px solid var(--line);
       border-radius:var(--radius-s); overflow:hidden; }
/* 行号列：与 textarea 共用行高，滚动时用 transform 跟随（见 codeed.js） */
.ced-gut { flex:none; width:2.4rem; padding:0.5rem 0.3125rem 0.5rem 0; text-align:right;
           background:var(--bg); color:var(--sub); font-size:0.7rem; line-height:1.6;
           font-family:Consolas, Monaco, "DejaVu Sans Mono", "Courier New", monospace;
           border-right:1px solid var(--line); overflow:hidden; user-select:none; }
.ced-gut span { display:block; }
.ced-ta { flex:1 1 auto; min-width:0; display:block; padding:0.5rem 0.625rem;
          border:0; outline:none; background:var(--card); color:var(--ink);
          font-size:0.78rem; line-height:1.6; resize:vertical;
          font-family:Consolas, Monaco, "DejaVu Sans Mono", "Courier New", monospace;
          white-space:pre; overflow-wrap:normal; overflow-x:auto; }
.ced.small .ced-ta { font-size:0.82rem; }
/* 手机上代码也要看得清：字号不能再小，行高略微放开便于点光标 */
html[data-lay="phone"] .ced-ta { font-size:0.8rem; line-height:1.7; }

/* ---- 填空 ---- */
.cj-blank { display:flex; align-items:center; gap:0.5rem; margin-bottom:0.375rem; }
.cj-bn { flex:none; width:1.9rem; font-size:0.75rem; font-weight:800; color:var(--brand); text-align:right; }
.cj-in { flex:1 1 auto; min-width:0; padding:0.4375rem 0.5625rem; font-size:0.8rem;
         border:1px solid var(--line); border-radius:0.5rem; background:var(--card); color:var(--ink); }

/* ---- 判定卡 ---- */
.cjv { padding:0.75rem 0.875rem; }
.cjv.right { background:var(--ok-soft); }
.cjv.wrong { background:var(--bad-soft); }
/* 部分正确：不套大色块，只给一条左边框 —— 去 AI 味第 1 条 */
.cjv:not(.right):not(.wrong) { background:var(--card); border-left:3px solid var(--warn); }
.cjv-h { display:flex; align-items:baseline; justify-content:space-between; gap:0.5rem; flex-wrap:wrap; }
.cjv-h b { font-size:0.95rem; font-weight:800; }
.cjv.right .cjv-h b { color:var(--ok); }
.cjv.wrong .cjv-h b { color:var(--bad); }
.cjv:not(.right):not(.wrong) .cjv-h b { color:var(--warn); }
.cjv-h span { font-size:0.72rem; color:var(--sub); }
/* 逐项清单：小勾叉 + 行内排版，不用胶囊标签 */
.cjv-rows { margin-top:0.5rem; }
.cjv-r { display:flex; align-items:flex-start; gap:0.4375rem; padding:0.1875rem 0; font-size:0.8rem; line-height:1.6; }
.cjv-r i { flex:none; width:0.95rem; font-style:normal; font-weight:800; text-align:center; }
.cjv-r b { flex:none; font-weight:700; color:var(--ink); }
.cjv-r span { min-width:0; color:var(--sub); }
.cjv-r.ok i { color:var(--ok); }
.cjv-r.bad i { color:var(--bad); }
.cjv-r.skip i { color:var(--sub); font-weight:400; }
.cjv-r.skip b, .cjv-r.skip span { color:var(--sub); }
.cjv-note { margin-top:0.5rem; font-size:0.72rem; line-height:1.6; color:var(--sub); }

/* 思路提示：序号列表，避免和分步详解看起来一样 */
.cjh { margin:0.375rem 0 0 1.125rem; }
.cjh li { font-size:0.81rem; line-height:1.75; margin:0.25rem 0; color:var(--ink); }
/* 提示区用品牌色左边框区分"这是思路、不是答案" */
.cj-box2 details.ri-details > .ri-body { border-left:3px solid var(--brand); margin-left:0.25rem; padding-left:0.625rem; }
