/* ============================================================
   css/panels/panels-vocab.css — 「外文 → 单词」分区（2028-09 第 2 窗口重做）
   ------------------------------------------------------------
   这一份只画单词分区自己的东西：首页那一屏、词卡（快速刷词/学习/复习）、
   没记住的那几个词、选词书的小抽屉、学习记录里的日历格子。
   公共零件一律不来这里重画：令牌在 panels-learning.css，目录行/按钮/三态/分段
   在 panels-learning.css + panels-ec-ui.css，返回头在 panels-ec.css。
   （旧的 panels-vocabulary.css 与整套 vocab-*/vbc-* 卡片体系已随本轮删除。）

   前缀 vb- 独占；零 emoji；禁系统默认控件；触摸目标 ≥44px；
   360~430 好看、<370 不破版不横向溢出；支持 prefers-reduced-motion。
   ============================================================ */

/* ===== 首页那三个一级入口（甲方 §A：视觉上只突出这三个）=====
   一张「纸卡片」一件事：英文花字在上、中文标题与一行说明在下、右边一个箭头。
   它不是 ec-li-row 堆出来的一行行 —— 那是甲方点名不要的观感。 */
/* 页边距跟全模块同一条（--ec-gutter：24 / 窄屏 14 / 宽屏 26）——
   这三张卡原来几乎顶到屏幕两边、边框压着屏幕边（2026-10-09 甲方第 7 条） */
.vb-entries { display: flex; flex-direction: column; gap: 12px; padding: 0 var(--ec-gutter, 24px); }
.vb-entry {
    display: flex; align-items: center; gap: 14px; width: 100%; box-sizing: border-box;
    min-height: 76px; padding: 16px 18px; text-align: left; cursor: pointer;
    border: 1px solid var(--ec-line-soft); border-radius: var(--ec-radius);
    background: var(--ec-surface); color: var(--ec-ink); box-shadow: var(--ec-shadow-1);
    font-family: var(--font-body);
    transition: box-shadow var(--ec-dur) var(--ec-ease), transform var(--ec-dur-fast) var(--ec-ease), border-color var(--ec-dur) var(--ec-ease);
}
.vb-entry:active { transform: scale(0.985); }
.vb-entry-en {
    flex: 0 0 auto; width: 52px;
    font-family: var(--font-display); font-style: italic; font-size: 15px;
    color: var(--ec-rose-ink); letter-spacing: 0.02em;
}
.vb-entry-main { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 4px; }
.vb-entry-title { font-size: 16px; line-height: 1.4; color: var(--ec-ink); }
.vb-entry-sub { font-size: 12px; line-height: 1.6; color: var(--ec-sub); }
.vb-entry-arrow { flex: 0 0 auto; display: inline-flex; color: var(--ec-faint); }
/* 三个入口各自一条**左侧书脊色**：一眼能分开，又不靠颜色说内容 */
.vb-entry-test   { box-shadow: var(--ec-shadow-1), 3px 0 0 0 var(--rose-light) inset; }
.vb-entry-new    { box-shadow: var(--ec-shadow-1), 3px 0 0 0 #c3d6c6 inset; }
.vb-entry-review { box-shadow: var(--ec-shadow-1), 3px 0 0 0 #c2d3e2 inset; }

/* ===== 书卡上的三个状态（未学 / 已学 / 待复习）—— 各自可点，各自一个词集 ===== */
.vb-book-chips { display: flex; gap: 8px; }
.vb-chip {
    flex: 1 1 0; min-width: 0; min-height: var(--ec-touch); box-sizing: border-box;
    display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 2px;
    padding: 6px 4px; border: 1px solid var(--ec-line-soft); border-radius: var(--ec-radius-s);
    background: none; color: var(--ec-sub); cursor: pointer;
    font-family: var(--font-body);
    transition: border-color var(--ec-dur) var(--ec-ease), transform var(--ec-dur-fast) var(--ec-ease), background var(--ec-dur) var(--ec-ease);
}
.vb-chip b { font-size: 16px; font-weight: 600; color: var(--ec-ink); font-variant-numeric: tabular-nums; }
.vb-chip span { font-size: 11px; line-height: 1.4; }
.vb-chip:active { transform: scale(0.96); }
.vb-chip:hover { border-color: rgba(201,168,168,0.45); }
.vb-chip.is-alert b { color: var(--ec-rose-ink); }
.vb-book-pct { font-size: 12.5px; line-height: 1.6; color: var(--ec-sub); font-variant-numeric: tabular-nums; }

/* ===== 3D 晨读阅读器（甲方 §B/§E：像一本漂亮的实体书，不做塑料科技球）=====
   构成很轻：一层 perspective + 一条书脊阴影 + 纸面色，翻页靠 transform。
   纸面用暖白（--ec-surface 已经带一点纸感），书页里侧一条渐变＝装订线。 */
.vb-book2 { position: relative; margin: 12px 14px 0; perspective: 1400px; }
.vb-book2-pages { position: absolute; inset: 0; pointer-events: none; }
.vb-book2-side {
    position: absolute; left: 0; top: 0; bottom: 0; width: 14px;
    border-radius: var(--ec-radius-s) 0 0 var(--ec-radius-s);
    background: linear-gradient(90deg, rgba(120,100,90,0.16), rgba(120,100,90,0.03) 60%, rgba(120,100,90,0));
}
.vb-book2-in {
    position: relative; box-sizing: border-box;
    padding: 18px 18px 20px 22px;
    border: 1px solid var(--ec-line-soft); border-radius: 6px 12px 12px 6px;
    background: var(--ec-surface);
    box-shadow: var(--ec-shadow-1), inset 14px 0 22px -18px rgba(90,70,60,0.55);
    transform-origin: left center;
    will-change: transform;
}
/* 翻到新的一页时轻轻「落下」一下（只做一次，不常驻动画类：见 DOM 防闪铁律）
   ★ W5（甲方 2028-09-28 第 7 条：「左右翻页不是平着翻的，页面会朝着下角挪动，很奇怪」）——
   真根因就是下面那个 `rotateY(-3deg)`：`.vb-book2` 上有 `perspective:1400px`，
   页面绕着**自己的中轴**转 3 度时，近端（右半边）被放大、远端（左半边）被缩小，
   看着就是「整张纸朝下角斜着挪」。翻页本来就该是**平的、左右滑**。
   现在：整块纸横着滑进来（12px）+ 一点淡入，中间那条装订线附近做出书脊的暗；
   `rotateY` 挪到**书页里面那一层**（`.vb-book2-in`，它自己有 `transform-origin:left center`），
   于是页还是平的，只有内页轻轻贴一下书脊 —— 而划出去那一下（`_vbCurlDone` 的 translateX）
   本来就只横着走，两步的方向是一套的，不再打架。 */
.vb-book2-in.vb-turn-in { animation: vbPageIn 0.24s var(--ec-ease); }
.vb-book2.vb-turn-in { animation: vbPageFlat 0.24s var(--ec-ease); }
.vb-book2 .vb-oneshot-list { margin: 8px 0 0; }
.vb-reader-hint { padding: 10px 24px 0; font-size: 11.5px; color: var(--ec-faint); text-align: center; }
@keyframes vbPageIn {
    0% { opacity: 0.6; filter: brightness(0.86); transform: rotateY(-3deg); }
    100% { opacity: 1; filter: brightness(1); transform: none; }
}
@keyframes vbPageFlat {
    0% { opacity: 0.62; transform: translateX(12px); }
    100% { opacity: 1; transform: none; }
}

/* ===== 阅读器里的状态筛选（全部 / 未学 / 已学 / 待复习）===== */
.vb-filter { display: flex; gap: 7px; padding: 12px 24px 0; flex-wrap: wrap; }
.vb-filter-i {
    flex: 1 1 0; min-width: 0; min-height: 36px;
    display: inline-flex; align-items: center; justify-content: center; gap: 5px;
    padding: 6px 8px; border: 1px solid var(--ec-line-soft); border-radius: 999px;
    background: none; color: var(--ec-sub); cursor: pointer;
    font-family: var(--font-body); font-size: 12.5px;
    transition: color var(--ec-dur) var(--ec-ease), border-color var(--ec-dur) var(--ec-ease), background var(--ec-dur) var(--ec-ease);
}
.vb-filter-i b { font-size: 12px; font-variant-numeric: tabular-nums; opacity: 0.8; }
.vb-filter-i.is-on { color: var(--ec-rose-ink); border-color: var(--rose); background: var(--rose-light); }
.vb-filter-i:active { transform: scale(0.97); }

/* ===== 「词书测试」那一屏（独立测试：填空 / 中译英 / 连线）===== */
.vb-test-page .ec-bar { margin: 6px 24px 0; }
.vb-test-card {
    margin: 16px 24px 0; padding: 20px 18px 18px; box-sizing: border-box;
    border: 1px solid var(--ec-line-soft); border-radius: var(--ec-radius);
    background: var(--ec-surface); box-shadow: var(--ec-shadow-1);
}
.vb-test-title { font-size: 12.5px; color: var(--ec-sub); }
.vb-test-sent {
    margin-top: 12px; font-family: var(--font-display); font-size: 17px; line-height: 1.9;
    color: var(--ec-ink); word-break: break-word;
}
.vb-test-zh { margin-top: 12px; font-size: 19px; line-height: 1.7; color: var(--ec-ink); }
.vb-test-opts { display: flex; flex-direction: column; gap: 8px; margin-top: 16px; }
.vb-test-opt {
    width: 100%; box-sizing: border-box; min-height: var(--ec-touch);
    padding: 12px 14px; text-align: left; cursor: pointer;
    border: 1px solid var(--ec-line); border-radius: var(--ec-radius-s);
    background: var(--ec-surface-2); color: var(--ec-ink);
    font-family: var(--font-body); font-size: 15px;
    transition: border-color var(--ec-dur) var(--ec-ease), transform var(--ec-dur-fast) var(--ec-ease), background var(--ec-dur) var(--ec-ease);
}
.vb-test-opt:active { transform: scale(0.99); }
.vb-test-opt.is-right { border-color: var(--sage); background: rgba(168,184,160,0.14); }
.vb-test-opt.is-wrong { border-color: #C08C8C; background: rgba(201,140,140,0.12); }
.vb-match { display: flex; gap: 10px; margin-top: 16px; }
.vb-match-col { flex: 1 1 0; min-width: 0; display: flex; flex-direction: column; gap: 8px; }
.vb-match-i {
    width: 100%; box-sizing: border-box; min-height: var(--ec-touch);
    padding: 10px 10px; text-align: left; cursor: pointer;
    border: 1px solid var(--ec-line); border-radius: var(--ec-radius-s);
    background: var(--ec-surface-2); color: var(--ec-ink);
    font-family: var(--font-body); font-size: 13px; line-height: 1.5;
    transition: border-color var(--ec-dur) var(--ec-ease), transform var(--ec-dur-fast) var(--ec-ease);
}
.vb-match-i.is-on { border-color: var(--rose); background: var(--rose-light); }
.vb-match-i:active { transform: scale(0.98); }
.vb-test-note { margin-top: 12px; font-size: 11.5px; color: var(--ec-faint); }
.vb-test-fb {
    margin: 14px 24px 0; padding: 10px 14px; border-radius: var(--ec-radius-s);
    font-size: 13px; line-height: 1.7;
}
.vb-test-fb.is-right { color: var(--ec-sage-ink); background: rgba(168,184,160,0.14); }
.vb-test-fb.is-wrong { color: var(--ec-rose-ink); background: rgba(201,140,140,0.12); }
.vb-test-done { margin: 10px 24px 0; text-align: center; }
.vb-test-done-n { font-family: var(--font-display); font-size: 40px; line-height: 1.2; color: var(--ec-ink); }
.vb-test-done-s { margin-top: 6px; font-size: 13px; color: var(--ec-sub); }
.vb-test-wrong { display: flex; flex-wrap: wrap; gap: 8px; justify-content: center; margin-top: 14px; }
.vb-test-done-hint { margin-top: 14px; font-size: 12px; line-height: 1.8; color: var(--ec-faint); }
.vb-test-done-hint b { color: var(--ec-sub); font-weight: 600; }

/* 窄屏（<370px）：入口卡、书页与测试页各收一档 */
@media (max-width: 369px) {
    .vb-entry { gap: 10px; padding: 13px 13px; min-height: 70px; }
    .vb-entry-en { width: 44px; font-size: 13.5px; }
    .vb-entry-title { font-size: 15px; }
    .vb-entry-sub { font-size: 11.5px; }
    .vb-book2 { margin: 10px 8px 0; }
    .vb-book2-in { padding: 14px 12px 16px 16px; }
    .vb-filter { padding: 10px 14px 0; gap: 5px; }
    .vb-filter-i { font-size: 11.5px; padding: 5px 6px; }
    .vb-reader-hint { padding: 8px 14px 0; }
    .vb-test-card { margin: 14px 14px 0; padding: 16px 13px 14px; }
    .vb-test-sent { font-size: 16px; }
    .vb-test-fb { margin: 12px 14px 0; }
    .vb-test-done { margin: 8px 14px 0; }
    .vb-test-done-n { font-size: 34px; }
    .vb-match { gap: 7px; }
    .vb-match-i { font-size: 12px; padding: 9px 8px; }
    .vb-unit-drill { font-size: 11px; padding: 6px 8px; }
    .vb-spell-row { gap: 6px; }
}
/* 减少动效：翻页与入场动画一并关掉（只留状态变化，不留位移） */
@media (prefers-reduced-motion: reduce) {
    .vb-book2-in, .vb-book2, .vb-entry, .vb-chip, .vb-filter-i, .vb-test-opt, .vb-match-i, .vb-unit-drill {
        animation: none !important;
        transition: none !important;
        transform: none !important;
    }
}

/* ===== 首页那一屏 ===== */
.ec-vocab .ec-page-head { padding-bottom: 4px; }
.ec-vocab .ec-metrics { margin-top: 18px; }
.ec-vocab .ec-sec:first-of-type { padding-top: 18px; }
/* 小节标题：中文正题 + 花字英文各占一处（不许两句话贴成一行，长期规则「层级靠字号字重颜色」） */
.ec-vocab .ec-sec-title { letter-spacing: 2px; }
.ec-vocab .ec-sec-head .ec-sec-en { margin-left: auto; text-align: right; }
/* 目录行的英文小字：与中文标签各占一行，标签一律 1.5 倍行距（紧挨着会看成一句话） */
.ec-vocab .ec-li-row-label { line-height: 1.5; }
.ec-vocab .ec-li-row-en { line-height: 1.45; }
/* 词书/单元那一行的中文名字（英文花字上面是书名，这里是中文名——用户自己起的话，不是装饰） */
.vb-bank-zh { display: block; font-size: 13.5px; color: var(--ec-ink); margin-top: 3px; line-height: 1.5; }

/* ===== W3 #8：单元那一行 ── 正式学习（整行可点）＋ 只读快速刷（右边一颗圆签）=====
   两个动作绝不能长得像同一件事：主行照旧是整行可点的正式学习；
   「快速刷这一组」是一颗安静的圆签，点进去只读练手（不写掌握度、不占额度）。 */
.vb-unit-row { display: flex; align-items: center; gap: 6px; border-bottom: 1px solid var(--ec-line); }
.vb-unit-row .ec-li-row { flex: 1 1 auto; min-width: 0; border-bottom: 0; }
.vb-unit-drill {
    flex: 0 0 auto; min-height: var(--ec-touch); padding: 6px 11px; box-sizing: border-box;
    border: 1px solid var(--rose); border-radius: 999px; background: var(--rose-light);
    color: var(--ec-rose-ink); font-family: var(--font-body); font-size: 11.5px; line-height: 1.35;
    white-space: nowrap; cursor: pointer; transition: transform var(--ec-dur-fast) var(--ec-ease);
}
.vb-unit-drill:active { transform: scale(0.95); }

/* ===== W3 #7：总览「今天」那一块的只读快速刷轻入口（不抢「继续学习」的主位）===== */
.vb-drill-today { min-height: var(--ec-touch); margin-top: 14px; }
.vb-drill-today em { font-style: normal; font-size: 11px; color: var(--ec-faint); }

/* ===== W3：拼写题（只读快速刷）—— 自己画的输入框那一行 + 「看一眼」===== */
.vb-spell-row { display: flex; align-items: center; gap: 8px; margin-top: 16px; }
.vb-spell-row .ec-input { flex: 1 1 auto; min-width: 0; box-sizing: border-box; }
.vb-spell-row .ec-btn { flex: 0 0 auto; }
.vb-spell-ans {
    margin-top: 14px; font-family: var(--font-display); font-size: 21px; line-height: 1.5;
    color: var(--ec-ink); word-break: break-word;
}
.vb-spell-you { margin-top: 6px; font-size: 12.5px; color: var(--ec-sub); word-break: break-word; }
.vb-spell-peek { display: flex; align-items: center; gap: 10px; margin-top: 12px; min-height: var(--ec-touch); }
/* 「看一眼」是文字钮（设计系统里本来就小）：这里只在本行内把它抬到 44 的触碰下限，不动全局那一条 */
.vb-spell-peek .ec-btn-text { min-height: var(--ec-touch); padding: 0 6px; display: inline-flex; align-items: center; }
.vb-spell-peek-note { font-size: 11px; color: var(--ec-faint); }

/* ===== 一头一尾的两行状态（第几个 / 这轮记住几个）===== */
.vb-progress {
    display: flex; align-items: baseline; justify-content: space-between; gap: 10px;
    padding: 14px 24px 6px;
}
.vb-progress-t { font-size: 12.5px; color: var(--ec-sub); font-variant-numeric: tabular-nums; }
.vb-progress-t b { font-size: 17px; font-weight: 600; color: var(--ec-ink); }
.vb-progress-m { font-size: 11.5px; color: var(--ec-sub); }
.vb-card-page .ec-bar { margin: 6px 24px 0; }

/* ===== W1 残项 1：「待复习」那一屏的今日账（共 / 已复习 / 还剩）=====
   它和上面那行「第 i / n 个」是两件事，所以视觉上也分开：
   这一块是**今天这一件活的完成度**（进度条走的也是它），上面那一行才是本轮位置。 */
.vb-review-today { margin: 14px 24px 0; padding: 12px 14px 10px; box-sizing: border-box;
    border: 1px solid var(--ec-line-soft); border-radius: var(--ec-radius-s); background: var(--ec-surface-2); }
.vb-review-today-head { display: flex; align-items: baseline; justify-content: space-between; gap: 10px;
    font-size: 12px; color: var(--ec-sub); }
.vb-review-today-n { font-variant-numeric: tabular-nums; color: var(--ec-sub); }
.vb-review-today-n b { font-size: 16px; font-weight: 600; color: var(--ec-ink); }
.vb-review-today .ec-bar { margin: 8px 0 0; }
.vb-review-today-foot { margin-top: 7px; font-size: 11.5px; color: var(--ec-sub); font-variant-numeric: tabular-nums; }

/* ===== 词卡 =====
   手册要求：触摸要有精致反馈、不做旋转木马式游戏卡。
   正面只有词形，点一下（或按空格）才把意思翻出来 —— 先自己回忆，再看答案。 */
.vb-card {
    position: relative; margin: 20px 24px 0; padding: 34px 22px 26px;
    min-height: 208px; box-sizing: border-box;
    border: 1px solid var(--ec-line); border-radius: var(--ec-radius);
    background: var(--ec-surface); box-shadow: var(--ec-shadow-1);
    text-align: center; cursor: pointer;
    transition: border-color var(--ec-dur) var(--ec-ease), box-shadow var(--ec-dur) var(--ec-ease), transform var(--ec-dur-fast) var(--ec-ease);
}
.vb-card:active { transform: scale(0.995); }
.vb-card-word {
    font-family: var(--font-display); font-size: 32px; line-height: 1.2;
    color: var(--ec-ink); word-break: break-word;
}
.vb-card-ph { font-family: var(--font-mono, monospace); font-size: 12.5px; color: var(--ec-sub); margin-top: 8px; letter-spacing: 0.4px; }
.vb-card-hint { font-size: 11.5px; color: var(--ec-faint); margin-top: 18px; }
.vb-card.is-flipped .vb-card-hint { display: none; }
.vb-card-back { display: none; }
.vb-card.is-flipped .vb-card-back { display: block; margin-top: 16px; padding-top: 16px; border-top: 1px solid var(--ec-line-soft); }
.vb-card-zh { font-size: 14.5px; line-height: 1.85; color: var(--ec-ink); }
.vb-card-ex { margin-top: 14px; text-align: left; }
.vb-ex-en { font-family: var(--font-display); font-size: 14px; line-height: 1.8; color: var(--ec-ink); }
.vb-ex-zh { font-size: 12px; line-height: 1.8; color: var(--ec-sub); margin-top: 4px; }
@media (prefers-reduced-motion: no-preference) {
    .vb-card.is-flipped .vb-card-back { animation: vbReveal 0.22s var(--ec-ease); }
}
@keyframes vbReveal { from { opacity: 0; transform: translateY(4px); } to { opacity: 1; transform: none; } }

/* 三档选择：没印象 / 想一想 / 知道（SM-2 五档由服务端换算，界面只给这三下） */
.vb-ans { display: flex; gap: 10px; padding: 16px 24px 0; }
.vb-ans-btn {
    flex: 1 1 0; min-width: 0; min-height: 58px; padding: 10px 6px;
    display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 3px;
    border: 1px solid var(--ec-line); border-radius: var(--ec-radius-s);
    background: var(--ec-surface); color: var(--ec-ink);
    font-family: var(--font-body); font-size: 14px; cursor: pointer;
    transition: transform var(--ec-dur-fast) var(--ec-ease), border-color var(--ec-dur) var(--ec-ease), background var(--ec-dur) var(--ec-ease), box-shadow var(--ec-dur) var(--ec-ease);
}
.vb-ans-btn i { font-style: normal; font-size: 10.5px; color: var(--ec-sub); }
.vb-ans-btn:active { transform: scale(0.95); }
.vb-ans-btn:disabled { cursor: default; }
.vb-ans-btn.q1 { color: #A5757A; }
.vb-ans-btn.q2 { color: var(--ec-gold-ink); }
.vb-ans-btn.q3 { color: var(--ec-sage-ink); }
.vb-ans-btn.is-picked { border-color: var(--rose); box-shadow: 0 0 0 1px var(--rose) inset; }
.vb-ans-btn.q3.is-picked { border-color: var(--sage); box-shadow: 0 0 0 1px var(--sage) inset; }
[data-theme-mode="dark"] .vb-ans-btn { background: var(--ec-surface-2); }

/* 卡上三个小动作 */
.vb-tools { display: flex; justify-content: center; gap: 10px; flex-wrap: wrap; padding: 16px 24px 0; }
.vb-mini {
    display: inline-flex; align-items: center; gap: 6px;
    min-height: var(--ec-touch); padding: 6px 12px; border-radius: 999px;
    border: 1px solid var(--ec-line-soft); background: none; color: var(--ec-sub);
    font-family: var(--font-body); font-size: 12.5px; cursor: pointer;
    transition: color var(--ec-dur) var(--ec-ease), border-color var(--ec-dur) var(--ec-ease), transform var(--ec-dur-fast) var(--ec-ease);
}
.vb-mini:active { transform: scale(0.94); }
.vb-mini:hover { color: var(--ec-rose-ink); border-color: rgba(201,168,168,0.35); }

/* 打分那一刻的即时回话（不是弹窗，压在卡上一条）
   ★ 第 11 窗口：底色改成**实心承托面**（原来 0.10~0.12 的透明色，底下的例句会透出来），
     并补上「没记住」那一档的真样式（.is-missed 过去只写在 JS 里、CSS 里没有 —— 长期规则 #194）。 */
.vb-feedback {
    position: absolute; left: 50%; bottom: 16px; transform: translate(-50%, 8px) scale(0.94);
    padding: 7px 16px; border-radius: 999px; white-space: nowrap;
    font-size: 12.5px; letter-spacing: 0.02em; opacity: 0;
    background: var(--ec-surface, #FFFDFB); color: var(--ec-ink);
    border: 1px solid var(--ec-line, rgba(180,160,140,0.22));
    box-shadow: var(--ec-shadow-2, 0 4px 16px rgba(60,50,45,0.10));
    transition: opacity var(--ec-dur) var(--ec-ease), transform var(--ec-dur) var(--ec-ease);
    pointer-events: none;
}
.vb-feedback.is-known { color: var(--ec-sage-ink); border-color: rgba(168,184,160,0.55); }
.vb-feedback.is-unsure { color: var(--ec-gold-ink); border-color: rgba(201,168,120,0.55); }
.vb-feedback.is-missed { color: var(--ec-rose-ink); border-color: rgba(201,140,140,0.5); }
.vb-feedback.show { opacity: 1; transform: translate(-50%, 0) scale(1); }
.vb-feedback.is-out { opacity: 0; transform: translate(-50%, -6px) scale(0.96); }
/* 卡里没地方再摆一条时（窄屏）：泡泡换成「贴在卡片下沿内侧」的一条，仍然实心、不压例句 */
@media (max-width: 369px) {
    .vb-feedback { font-size: 12px; padding: 6px 13px; bottom: 12px; }
}
.vb-card.is-known { border-color: rgba(168,184,160,0.6); }
.vb-card.is-missed { border-color: rgba(201,140,140,0.5); }

/* ===== 没记住的那几个词 ===== */
.vb-missed { display: flex; flex-wrap: wrap; gap: 8px; }
.vb-missed-i {
    padding: 5px 11px; border-radius: 999px; font-size: 12.5px;
    color: var(--ec-ink); background: var(--ec-fill); border: 1px solid var(--ec-line-soft);
}
/* ★ W5（甲方 2028-09-28 第 2 条：「那一行词和下面两颗按钮之间空得太大」）：
   收尾这一屏那一段（「这几个明天会先回来」+ 一句说明）与出口按钮本来是两块各自带 24px 上边距的
   段（上面那段自己的 24px ＋ 按钮那块再 24px ＋ 按钮行自己的 16px ＝ 空出 60px 上下），
   看着像两块不相干的东西。这里把它收回到一只手能连起来的距离：18px。
   （不用 :has()，也不用改全局的 .ec-sec / .ec-actions —— 全站别的块一个字都不动。） */
.vb-done-acts { padding-top: 18px; }
.vb-done-acts .ec-actions { margin-top: 0; }

/* ===== 选词书的小抽屉（自己画，禁原生 select）===== */
.vb-scrim {
    position: fixed; left: 0; right: 0; top: 0; bottom: 0; z-index: var(--ec-z-scrim);
    display: flex; align-items: flex-end; justify-content: center;
    background: rgba(40,34,30,0.28); opacity: 0;
    transition: opacity var(--ec-dur) var(--ec-ease);
}
.vb-scrim.show { opacity: 1; }
.vb-scrim-bd { position: absolute; left: 0; right: 0; top: 0; bottom: 0; }
.vb-sheet {
    position: relative; width: 100%; max-width: 480px; box-sizing: border-box;
    max-height: 72vh; overflow-y: auto; -webkit-overflow-scrolling: touch;
    padding: 6px 18px calc(18px + var(--safe-bottom, 0px));
    border-radius: var(--ec-radius) var(--ec-radius) 0 0;
    background: var(--ec-surface); box-shadow: var(--ec-shadow-3);
    transform: translateY(14px); opacity: 0;
    transition: transform var(--ec-dur) var(--ec-ease), opacity var(--ec-dur) var(--ec-ease);
}
.vb-scrim.show .vb-sheet { transform: none; opacity: 1; }
.vb-sheet-title { padding: 14px 2px 10px; font-size: 14.5px; font-weight: 600; color: var(--ec-ink); }
.vb-sheet-list { border-top: 1px solid var(--ec-line); }
.vb-sheet-foot { padding: 14px 0 2px; }
/* 桌面端：抽屉也跟着 480 限宽居中（禁铺满整屏） */
@media (min-width: 481px) {
    .vb-scrim { align-items: flex-end; }
    .vb-sheet { margin-bottom: 0; }
}

/* ===== 学习记录里的日历格子（一格一天）===== */
#vb-cal { margin-top: 4px; }

/* ===== 目标页里选中的那一本 ===== */
.ec-li-row.is-picked { background: var(--ec-tap); }
.ec-li-row.is-picked .ec-opt-mark { opacity: 1; color: var(--ec-rose-ink); }
.ec-opt-mark { opacity: 0; display: inline-flex; transition: opacity var(--ec-dur) var(--ec-ease); }

/* ===== W2-C｜「一口气整本」那一页 =====
   像翻一本书的一页：一页 12 个词，按书里的顺序；点住某一行就地看意思。
   它只读（不计入学习），所以视觉上刻意比词卡更「安静」：没有评分按钮、没有进度催促。 */
/* · 原文第 6 条重做：甲方要的是「像一本真实的书那样翻页」——
   「就像真正的那种单词词书，一页里边从上到下就有很多个单词」「真实一本纸质词书」。
   所以这一页不再是「每词一张厚圆角卡」（旧版 `border + radius` 就是那个样子，
   甲方原话「点开详情的时候特别不丝滑，也没有词性和翻译，东西全」），
   而是一条条**纸上的词条**：没有卡片边框，只有极细的分隔线 + 排版间距。
   仍然整行可点（点进那个词的详情），仍然满足触摸目标 44px。 */
.vb-oneshot-list { margin: 10px 24px 0; display: flex; flex-direction: column; }
/* ★ W1 残项 2：这一块要能**手指左右滑翻页**。
   只放行纵向（pan-y）：纵向是滚这一页，横向是翻到下一页 —— 互不抢；
   关掉选中，免得滑动时把字选蓝（一个词一张按钮，本来也没有要选的正文）。 */
.vb-oneshot-list { touch-action: pan-y; -webkit-user-select: none; user-select: none; }
.vb-oneshot-item {
    display: block; width: 100%; box-sizing: border-box; text-align: left;
    min-height: var(--ec-touch); padding: 11px 0 12px;
    border: 0; border-bottom: 1px solid var(--ec-line-soft);
    background: none; color: var(--ec-ink);
    font-family: var(--font-body); cursor: pointer;
    transition: background var(--ec-dur) var(--ec-ease);
}
.vb-oneshot-item:active { background: var(--ec-tap); }
.vb-oneshot-item:hover { background: rgba(201,168,168,0.04); }
/* 第一行：词形 + 音标（同一个基线，像词典那样挨着） */
.vb-oneshot-row1 { display: flex; align-items: baseline; gap: 9px; min-width: 0; }
/* 词形：衬线体（与词卡同一套字，句子与释义留给正文体） */
.vb-oneshot-word { font-family: var(--font-display); font-size: 17px; letter-spacing: 0.01em; }
.vb-oneshot-ph { font-size: 11.5px; color: var(--ec-sub); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* 词性：一枚很轻的小签，跟在词形/音标下面（**默认就在**，不再折在展开里）。
   2026-09-27 真截图复核了两处：① 原来只有 6px 内边距、行高 1.7，"n." 这种「一个字母 + 一个点」
   会被挤成两行（屏幕上看着像圆疙瘩加一个浮点）；② 它用的是展示体衬线，而 "n." 的点在衬线体里
   落得很低，缩到 10px 时点几乎看不见。所以：给足内边距 + nowrap + 行高 2.0 让点的落点有空间。 */
.vb-oneshot-pos {
    display: inline-block; margin: 3px 0 7px; padding: 1px 9px;
    border: 1px solid var(--ec-line); border-radius: 999px;
    font-family: var(--font-display); font-style: italic;
    font-size: 10.5px; line-height: 2.0; color: var(--ec-rose-ink);
    white-space: nowrap;
}
/* 中文释义：默认可见（原文第 6 条点名的「东西都不全」就是它被藏了） */
.vb-oneshot-zh { display: block; font-size: 13px; line-height: 1.7; color: var(--ec-ink); }
/* 例句：英 + 中，默认可见；中文那行比英文轻一档 */
.vb-oneshot-ex {
    display: block; margin-top: 5px; padding-left: 9px;
    border-left: 2px solid var(--ec-line);
    font-size: 11.5px; line-height: 1.7; color: var(--ec-sub);
}
.vb-oneshot-ex em { display: block; font-style: normal; color: var(--ec-faint); }
/* 上面每条已经有自己的分隔线了，不再需要额外的卡片间距 */
[data-theme-mode="dark"] .vb-oneshot-item { background: none; }
[data-theme-mode="dark"] .vb-oneshot-item:active { background: var(--ec-tap); }
/* 阅读器底下那颗「从第一页重新翻」：比上面两个大按钮安静一档，居中 */
.vb-mread-sub { margin-top: 6px; }

/* ===== W2-D｜「类名写了就必须有样式」收口 =====
   ★ 为什么现在补这一批：`tools/vocab-panel.test.js` 第一条判据就是「单词分区用到的类名样样都有规则」，
     而下面这些类名长期没有自己那条规则 —— 有的是靠**祖先选择器**间接定了观感（能看，但「到底谁负责它的
     外观」在 CSS 里查不到），有的是**真的一个字样式都没有**（最明显的是 `.vb-mread`：只读那几屏的
     「上一页 / 下一页」那一排，按钮会竖着堆起来、彼此贴住、上边紧贴卡片）。
     这条判据因此一直红着，而真问题就被埋在一堆假红里没人看。
     现在逐个补上**它自己那条规则**：既把没样式的补成真有样式，也让「谁负责它」一眼可查。 */

/* 「像一本书」的封面块：书脊 + 书名 + 进度 */
.vb-shelf { display: flex; flex-direction: column; gap: 14px; }
/* · 原文第 7 条：一张书卡 = 「书」+ 底下那个动作。两者是一段，不是一个按钮套一个按钮。 */
.vb-book-sec { display: flex; flex-direction: column; gap: 8px; }
.vb-book-use {
    width: 100%; box-sizing: border-box; min-height: var(--ec-touch);
    display: flex; align-items: center; justify-content: center;
    border: 1px solid var(--ec-line-strong); border-radius: var(--ec-radius-s);
    background: none; color: var(--ec-rose-ink); cursor: pointer;
    font-family: var(--font-body); font-size: 13px;
    transition: background var(--ec-dur) var(--ec-ease), border-color var(--ec-dur) var(--ec-ease), transform var(--ec-dur-fast) var(--ec-ease);
}
.vb-book-use:hover { border-color: rgba(201,168,168,0.5); }
.vb-book-use:active { transform: scale(0.985); }
/* 已经是当前那本：不给按钮（点它没有意义），只把状态说清楚 */
.vb-book-use.is-current {
    border-style: dashed; color: var(--ec-sub); cursor: default;
    font-size: 12px; min-height: 34px;
}
.vb-book-use.is-current:active { transform: none; }
/* ★ W1 残项 4：「读这本书」那一块的数据行（读到第几页）——
   替换掉原来那句说明性长句：只讲数，不讲道理。 */
.vb-read-pos { margin-top: 8px; font-size: 11.5px; color: var(--ec-sub); font-variant-numeric: tabular-nums; }
/* ★ §9 词书架：一本一张书卡，颜色档按这本书自己的 color 分开（书脊那一竖条就是它的「书脊」）。
   不做 3D、不做塑料圆球、不用 emoji —— 只靠书脊色 + 纸张底 + 衬线书名区分不同的书。 */
.vb-book-gold  .vb-book-spine { background: linear-gradient(180deg, #e6d3a8, var(--ec-surface-2)); }
.vb-book-sage  .vb-book-spine { background: linear-gradient(180deg, #c3d6c6, var(--ec-surface-2)); }
.vb-book-sky   .vb-book-spine { background: linear-gradient(180deg, #c2d3e2, var(--ec-surface-2)); }
.vb-book-lilac .vb-book-spine { background: linear-gradient(180deg, #d6cbe2, var(--ec-surface-2)); }
.vb-book-amber .vb-book-spine { background: linear-gradient(180deg, #e8d3b6, var(--ec-surface-2)); }
.vb-book-teal  .vb-book-spine { background: linear-gradient(180deg, #bed8d5, var(--ec-surface-2)); }
/* 「正在学」的那一本：书脊加宽 + 描边重一档 + 一枚明确的「正在学」小标。
   原文第 7 条要求「一眼看懂当前使用哪一本」—— 只靠描边宽度差 4px 是不合格的。 */
.vb-book.is-current { border-color: var(--rose); }
.vb-book.is-current .vb-book-spine { flex: 0 0 14px; }
.vb-book.is-current { box-shadow: var(--ec-shadow-1), 0 0 0 1px var(--rose-light) inset; }
.vb-book-top { display: flex; align-items: center; gap: 8px; min-width: 0; }
.vb-book-flag {
    flex: 0 0 auto; padding: 1px 7px; border-radius: 999px;
    background: var(--rose-light); color: var(--ec-rose-ink);
    font-size: 10.5px; line-height: 1.6; letter-spacing: 0.5px;
}
.vb-book {
    position: relative; display: flex; align-items: stretch; width: 100%; box-sizing: border-box;
    padding: 0; overflow: hidden; text-align: left; cursor: pointer;
    border: 1px solid var(--ec-line); border-radius: var(--ec-radius);
    background: var(--ec-surface); box-shadow: var(--ec-shadow-1); color: var(--ec-ink);
    font-family: var(--font-body);
    transition: box-shadow var(--ec-dur) var(--ec-ease), transform var(--ec-dur-fast) var(--ec-ease);
}
.vb-book:active { transform: scale(0.985); }
.vb-book-spine { flex: 0 0 10px; align-self: stretch; background: linear-gradient(180deg, var(--rose-light), var(--ec-surface-2)); }
.vb-book-body { flex: 1 1 auto; min-width: 0; padding: 14px 16px 16px; display: flex; flex-direction: column; gap: 3px; }
/* 书名不许被后面那些数字挤走：单行省略；数字各自一行，永远不折行 */
.vb-book-en { font-family: var(--font-display); font-size: 16px; line-height: 1.45; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.vb-book-zh { font-size: 13px; line-height: 1.5; color: var(--ec-ink); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.vb-book-line { font-size: 12.5px; line-height: 1.6; color: var(--ec-sub); font-variant-numeric: tabular-nums; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.vb-book-pos { font-size: 12px; line-height: 1.6; color: var(--ec-rose-ink); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.vb-book-bar { display: block; margin-top: 6px; }

/* 词卡正面的上下两行：第几个 / 共几个 + 这一张是「新词 / 复习 / 快速刷 / 整本」 */
.vb-page { display: block; box-sizing: border-box; }
.vb-page-in { display: block; }
.vb-page-top { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
.vb-page-no { font-size: 12.5px; color: var(--ec-sub); font-variant-numeric: tabular-nums; }
.vb-page-kind { font-size: 11.5px; letter-spacing: 0.06em; color: var(--ec-rose-ink); }
/* 难度（B2 / C1 这种）与「新词 / 复习」并排，单独一个小圆框（甲方第 3 条①）。
   空的时候整枚不占位（`_vbPageCard` 里给的是空字符串，资料后到才补上）。 */
.vb-page-right { display: inline-flex; align-items: center; gap: 8px; min-width: 0; }
.vb-page-diff {
    display: inline-flex; align-items: center; justify-content: center;
    box-sizing: border-box; min-width: 24px; height: 17px; padding: 0 6px;
    border: 1px solid rgba(201, 168, 168, 0.5); border-radius: 9px;
    background: rgba(201, 168, 168, 0.1);
    font-family: var(--font-display); font-size: 10px; line-height: 1; letter-spacing: 0.04em;
    color: var(--ec-rose-ink);
}
.vb-page-diff:empty { display: none; }
/* 情景那一句（甲方原话「红色那一句」）：从前挤在卡片最下面的灰字里，现在单独一行摆在
   词性 / 释义 / 例句**上面** —— 先说清这个词用在什么场景，再看它本身。 */
.vb-card-scene {
    margin: 0 0 12px; padding: 8px 10px; border-radius: 10px;
    background: rgba(201, 168, 168, 0.1);
    font-size: 12.5px; line-height: 1.7; color: var(--ec-rose-ink);
}
.vb-card-pos { font-size: 12px; color: var(--ec-sub); }

/* 只读那几屏（晨读 / 快速刷词 / 一口气）底下的「上一个 / 下一页」那一排。
   ★ 这一条以前**完全不存在** —— 按钮会一个叠一个竖着堆、彼此贴住、上边紧贴卡片。 */
.vb-mread { display: flex; gap: 10px; justify-content: center; margin-top: 16px; padding: 0 24px calc(8px + var(--safe-bottom, 0px)); flex-wrap: wrap; }
.vb-mread .ec-btn { flex: 1 1 auto; min-width: 120px; }

/* ===== 窄屏（<370px）===== */
@media (max-width: 369px) {
    .vb-progress { padding: 12px 14px 6px; }
    .vb-card-page .ec-bar { margin-left: 14px; margin-right: 14px; }
    .vb-card { margin: 16px 14px 0; padding: 28px 16px 22px; min-height: 190px; }
    .vb-card-word { font-size: 27px; }
    .vb-ans { padding: 14px 14px 0; gap: 7px; }
    .vb-ans-btn { min-height: var(--ec-touch); font-size: 13px; padding: 8px 4px; }
    .vb-ans-btn i { font-size: 10px; }
    .vb-tools { padding: 14px 14px 0; gap: 7px; }
    .vb-mini { padding: 6px 10px; }
    .vb-sheet { padding-left: 14px; padding-right: 14px; }
    .vb-oneshot-list { margin: 8px 14px 0; }
    .vb-oneshot-item { padding: 10px 0 11px; }
    .vb-oneshot-word { font-size: 16px; }
    .vb-mread { padding: 0 14px calc(6px + var(--safe-bottom, 0px)); gap: 7px; }
    .vb-mread .ec-btn { min-width: 0; font-size: 12.5px; padding: 9px 12px; }
    .vb-book-spine { flex-basis: 8px; }
    .vb-book-body { padding: 12px 12px 14px; }
    .vb-book-en { font-size: 15px; }
}
/* 大屏（400+）：卡片别被拉得太宽，也别矮下去 */
@media (min-width: 400px) {
    .vb-card { min-height: 226px; padding-top: 40px; }
}

/* ===== 减少动效 =====
   ★ 第 11 窗口：泡泡从这份「整片关掉过渡」的名单里拿了出来 ——
     它原来被 !important 压成 0.01s，等于她开了「少一点动效」就真的**一次都看不到动画**
     （那不是「少一点」，是没有）。现在它只留极短的一次淡入淡出，不加位移、不缩放。 */
@media (prefers-reduced-motion: reduce) {
    .vb-card, .vb-ans-btn, .vb-mini, .vb-scrim, .vb-sheet, .vb-card.is-flipped .vb-card-back,
    .vb-oneshot-item {
        transition: none !important;
        animation: none !important;
        transform: none !important;
    }
    .vb-card:active { transform: none; }
    .vb-feedback {
        transition: opacity 0.12s linear !important;
        transform: translate(-50%, 0) !important;
    }
    .vb-feedback.show { opacity: 1; }
    .vb-feedback.is-out { opacity: 0; }
}

/* ============================================================
   词书管理（2028-09 第 5 窗口）：小菜单 / 确认小窗 / 输入小窗 / 整理页
   ------------------------------------------------------------
   前缀：菜单与弹窗 vmenu* / vconfirm*（挂 #vocab-content 内，禁挂 body ——
        挂 body 在电脑端会撑满整屏）；整理页 vm-*（绝不占用 ec- 前缀）。
   动效：入场两拍（隐藏态插入 → 下一帧 .show），并给 reduced-motion 兜底。
   ============================================================ */

/* ---- 卡片右上角那个常驻的「⋯」（不会长按的人也能进整理）---- */
.vocab-bank-card { position: relative; }
.vocab-bank-card .vbc-more {
    position: absolute; top: 6px; right: 6px; z-index: 2;
    width: 24px; height: 24px; padding: 0; display: flex; align-items: center; justify-content: center;
    border: none; border-radius: 50%;
    background: rgba(255, 252, 249, 0.72); color: var(--text-secondary);
    -webkit-tap-highlight-color: transparent; touch-action: manipulation;
    opacity: 0.55; transition: opacity .18s ease, transform .18s ease, background .18s ease;
}
.vocab-bank-card .vbc-more:hover { opacity: 1; background: rgba(255, 252, 249, 0.94); color: var(--rose); }
.vocab-bank-card .vbc-more:active { transform: scale(0.9); }

/* ---- 小菜单 ---- */
/* 铺满视口的层用 position:fixed（与全站弹窗同一条口径，css/modals.css 的 .confirm-overlay）：
   挂 fixed 是「铺满屏幕的一层」，但**内容仍然限宽 480 并居中**，
   所以电脑端不会撑满整屏，手机端也不会跟着长页面的底部跑到屏幕外面去（第一版就是栽在这里）。 */
.vmenu {
    position: fixed; inset: 0; z-index: 60;
    display: flex; align-items: flex-end; justify-content: center;
    padding: 0 16px;
}
.vmenu-backdrop {
    position: absolute; inset: 0; background: rgba(30, 28, 26, 0.32);
    opacity: 0; transition: opacity .18s ease;
}
.vmenu.show .vmenu-backdrop { opacity: 1; }
.vmenu-panel {
    position: relative; width: 100%; max-width: 448px;
    margin-bottom: calc(14px + var(--safe-bottom, 0px));
    transform: translateY(12px);
    background: var(--surface-solid, #fff); border: 1px solid rgba(201, 168, 168, 0.22);
    border-radius: 18px; box-shadow: var(--shadow-lg, 0 12px 34px rgba(0,0,0,0.12));
    padding: 8px; opacity: 0; transition: opacity .2s ease, transform .22s cubic-bezier(.22,.61,.36,1);
}
.vmenu.show .vmenu-panel { opacity: 1; transform: translateY(0); }
.vmenu-title {
    font-family: var(--font-display); font-style: italic; font-size: 13px;
    color: var(--text-secondary); padding: 8px 12px 6px; text-align: center;
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.vmenu-item {
    display: flex; align-items: center; gap: 10px; width: 100%;
    padding: 12px; border: none; background: transparent; border-radius: 12px;
    font-family: var(--font-body); font-size: 14px; color: var(--text-primary);
    text-align: left; cursor: pointer; -webkit-tap-highlight-color: transparent;
    touch-action: manipulation; transition: background .16s ease, transform .1s ease;
}
.vmenu-item svg { flex-shrink: 0; color: var(--rose); }
.vmenu-item:hover { background: var(--rose-light, rgba(201,168,168,.12)); }
.vmenu-item:active { transform: scale(0.985); }
.vmenu-item.danger { color: #A8544C; }
.vmenu-item.danger svg { color: #A8544C; }
.vmenu-item.danger:hover { background: rgba(168, 84, 76, 0.08); }
.vmenu-item.cancel { justify-content: center; color: var(--text-secondary); margin-top: 4px; border-top: 1px solid rgba(0,0,0,0.05); border-radius: 0 0 12px 12px; }
.vmenu-item.cancel:hover { background: rgba(0,0,0,0.03); }

/* ---- 确认小窗 / 输入小窗 ---- */
/* 与全站弹窗同一条口径（fixed 铺满视口 + 内容限宽居中），手机与电脑都不破版 */
.vconfirm {
    position: fixed; inset: 0; z-index: 70;
    display: flex; align-items: center; justify-content: center;
    padding: 20px 16px calc(20px + var(--safe-bottom, 0px));
}
.vconfirm-backdrop {
    position: absolute; inset: 0; background: rgba(30, 28, 26, 0.32);
    opacity: 0; transition: opacity .18s ease;
}
.vconfirm.show .vconfirm-backdrop { opacity: 1; }
.vconfirm-panel {
    position: relative; width: 100%; max-width: 320px; max-height: calc(100vh - 40px);
    overflow-y: auto; -webkit-overflow-scrolling: touch;
    background: var(--surface-solid, #fff); border: 1px solid rgba(201, 168, 168, 0.22);
    border-radius: 20px; box-shadow: var(--shadow-lg, 0 14px 38px rgba(0,0,0,0.14));
    padding: 22px 20px 16px; opacity: 0; transform: translateY(10px) scale(0.98);
    transition: opacity .2s ease, transform .24s cubic-bezier(.22,.61,.36,1);
}
.vconfirm.show .vconfirm-panel { opacity: 1; transform: translateY(0) scale(1); }
.vconfirm-title {
    font-family: var(--font-body); font-size: 15.5px; font-weight: 600;
    color: var(--text-primary); text-align: center; margin-bottom: 12px; line-height: 1.5;
}
.vconfirm-line {
    font-family: var(--font-body); font-size: 12.5px; line-height: 1.75;
    color: var(--text-secondary); padding-left: 14px; position: relative; margin-bottom: 4px;
}
.vconfirm-line::before {
    content: ''; position: absolute; left: 2px; top: 8px; width: 4px; height: 4px;
    border-radius: 50%; background: var(--rose); opacity: 0.6;
}
.vconfirm-btns { display: flex; gap: 10px; margin-top: 18px; }
.vconfirm-btn {
    flex: 1; padding: 12px; border-radius: 14px; font-family: var(--font-body);
    font-size: 14px; cursor: pointer; -webkit-tap-highlight-color: transparent;
    touch-action: manipulation; transition: transform .1s ease, background .18s ease, border-color .18s ease;
}
.vconfirm-btn:active { transform: scale(0.97); }
.vconfirm-btn.cancel { background: transparent; border: 1px solid rgba(0,0,0,0.08); color: var(--text-secondary); }
.vconfirm-btn.cancel:hover { border-color: rgba(201,168,168,0.45); color: var(--rose); }
.vconfirm-btn.ok { background: var(--rose); border: 1px solid var(--rose); color: #fff; }
.vconfirm-btn.ok:hover { background: var(--rose-hover); border-color: var(--rose-hover); }
.vconfirm-btn.ok.danger { background: #A8544C; border-color: #A8544C; }
.vsheet-input {
    width: 100%; box-sizing: border-box; margin-top: 4px; padding: 13px 14px;
    border: 1px solid rgba(201, 168, 168, 0.3); border-radius: 14px;
    background: var(--bg-chat, #FCFAF6); color: var(--text-primary);
    font-family: var(--font-body); font-size: 15px; outline: none;
    transition: border-color .18s ease, box-shadow .18s ease;
}
.vsheet-input::placeholder { color: var(--text-muted); }
.vsheet-input:focus { border-color: var(--rose); box-shadow: 0 0 0 3px rgba(201, 168, 168, 0.14); }

/* ---- 整理页 ---- */
.vm-wrap { padding: 0 16px calc(28px + var(--safe-bottom, 0px)); }
.vm-card {
    background: var(--surface-solid, #fff); border: 1px solid rgba(201, 168, 168, 0.18);
    border-radius: 16px; padding: 14px 16px; box-shadow: var(--shadow-xs, 0 1px 3px rgba(0,0,0,0.04));
    margin-bottom: 18px;
}
.vm-card-row { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
.vm-card-name { font-family: var(--font-body); font-size: 16px; font-weight: 600; color: var(--text-primary); }
.vm-card-sub { font-family: var(--font-body); font-size: 11.5px; color: var(--text-muted); margin-top: 4px; }
.vm-sec-title { font-family: var(--font-display); font-size: 19px; color: var(--text-primary); margin: 4px 2px 2px; }
.vm-sec-sub { font-family: var(--font-body); font-size: 11.5px; color: var(--text-muted); margin: 0 2px 12px; line-height: 1.6; }
.vm-empty {
    font-family: var(--font-body); font-size: 12.5px; color: var(--text-secondary);
    background: rgba(201, 168, 168, 0.07); border-radius: 14px; padding: 16px; line-height: 1.8;
}
.vm-empty b { color: var(--rose); font-weight: 600; }
.vm-group {
    background: var(--surface-solid, #fff); border: 1px solid rgba(0,0,0,0.05);
    border-radius: 16px; margin-bottom: 8px; overflow: hidden;
    transition: border-color .2s ease, box-shadow .2s ease;
}
.vm-group.open { border-color: rgba(201, 168, 168, 0.32); box-shadow: var(--shadow-xs, 0 1px 3px rgba(0,0,0,0.04)); }
.vm-group-head { display: flex; align-items: center; gap: 12px; padding: 13px 12px; cursor: pointer; }
.vm-group-no {
    font-family: var(--font-display); font-style: italic; font-size: 13px;
    color: var(--rose); opacity: 0.75; min-width: 22px;
}
.vm-group-main { flex: 1; min-width: 0; }
.vm-group-name { font-family: var(--font-body); font-size: 14px; color: var(--text-primary); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.vm-group-sub { font-family: var(--font-body); font-size: 11px; color: var(--text-muted); margin-top: 3px; }
.vm-mini-btn {
    flex-shrink: 0; padding: 7px 12px; border-radius: 11px;
    border: 1px solid rgba(201, 168, 168, 0.3); background: transparent;
    font-family: var(--font-body); font-size: 11.5px; color: var(--rose);
    cursor: pointer; -webkit-tap-highlight-color: transparent;
    touch-action: manipulation; transition: background .16s ease, transform .1s ease, border-color .16s ease;
}
.vm-mini-btn:hover { background: var(--rose-light, rgba(201,168,168,.12)); }
.vm-mini-btn:active { transform: scale(0.96); }
.vm-mini-btn.danger { color: #A8544C; border-color: rgba(168, 84, 76, 0.28); }
.vm-mini-btn.danger:hover { background: rgba(168, 84, 76, 0.07); }
.vm-group-body { padding: 0 12px 12px; }
.vm-group-empty { font-family: var(--font-body); font-size: 12px; color: var(--text-muted); padding: 8px 2px 10px; }
.vm-loading-dots { font-family: var(--font-body); font-size: 12px; color: var(--text-muted); padding: 8px 2px 10px; }
.vm-words { display: flex; flex-direction: column; gap: 2px; margin-bottom: 10px; }
.vm-word {
    display: flex; align-items: center; gap: 10px; padding: 9px 6px;
    border-radius: 10px; cursor: pointer; transition: background .16s ease;
}
.vm-word:hover { background: rgba(201, 168, 168, 0.06); }
.vm-word input[type="checkbox"] {
    appearance: none; -webkit-appearance: none; flex-shrink: 0;
    width: 17px; height: 17px; margin: 0; border-radius: 5px;
    border: 1.5px solid rgba(201, 168, 168, 0.5); background: transparent;
    transition: background .16s ease, border-color .16s ease;
}
.vm-word input[type="checkbox"]:checked {
    background: var(--rose); border-color: var(--rose);
    background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='white' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='3.5 8.5 6.5 11.5 12.5 5'/%3E%3C/svg%3E");
    background-size: 13px 13px; background-position: center; background-repeat: no-repeat;
}
.vm-word-pick { cursor: pointer; }
.vm-word-txt { display: flex; align-items: baseline; gap: 8px; min-width: 0; }
.vm-word-en { font-family: var(--font-display); font-size: 14.5px; font-weight: 600; color: var(--text-primary); }
.vm-word-zh { font-family: var(--font-body); font-style: normal; font-size: 12px; color: var(--text-secondary); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.vm-group-acts { display: flex; flex-wrap: wrap; gap: 8px; padding-top: 4px; }
.vm-add-group {
    display: flex; align-items: center; justify-content: center; gap: 8px;
    width: 100%; padding: 14px; margin-top: 10px;
    border: 1px dashed rgba(201, 168, 168, 0.45); border-radius: 16px;
    background: transparent; color: var(--rose); font-family: var(--font-body); font-size: 13.5px;
    cursor: pointer; -webkit-tap-highlight-color: transparent; touch-action: manipulation;
    transition: background .18s ease, border-color .18s ease, transform .1s ease;
}
.vm-add-group:hover { background: rgba(201, 168, 168, 0.07); border-color: var(--rose); }
.vm-add-group:active { transform: scale(0.99); }

/* ===== 暗色模式（弹层与整理页跟着走，别只在浅色下好看）===== */
[data-theme-mode="dark"] .vmenu-panel,
[data-theme-mode="dark"] .vconfirm-panel { background: var(--surface-solid); border-color: rgba(255,255,255,0.06); }
[data-theme-mode="dark"] .vm-card,
[data-theme-mode="dark"] .vm-group { background: var(--surface-solid); border-color: rgba(255,255,255,0.05); }
[data-theme-mode="dark"] .vm-group.open { border-color: rgba(201,168,168,0.28); }
[data-theme-mode="dark"] .vm-empty { background: rgba(255,255,255,0.03); }
[data-theme-mode="dark"] .vsheet-input { background: rgba(255,255,255,0.04); border-color: rgba(255,255,255,0.08); }
[data-theme-mode="dark"] .vconfirm-btn.cancel { border-color: rgba(255,255,255,0.1); }
[data-theme-mode="dark"] .vmenu-item.cancel { border-top-color: rgba(255,255,255,0.06); }
[data-theme-mode="dark"] .vmenu-item.cancel:hover { background: rgba(255,255,255,0.04); }
[data-theme-mode="dark"] .vocab-bank-card .vbc-more { background: rgba(40,36,34,0.7); }

/* 窄屏（<370px）：字号与间距各收一档，绝不许横向溢出 */
@media (max-width: 369px) {
    .vmenu-panel { width: calc(100% - 24px); }
    .vconfirm-panel { width: calc(100% - 28px); padding: 18px 16px 14px; }
    .vm-wrap { padding: 0 12px calc(24px + var(--safe-bottom, 0px)); }
    .vm-card { padding: 12px; }
    .vm-group-head { padding: 11px 10px; gap: 10px; }
    .vm-group-name { font-size: 13.5px; }
    .vm-mini-btn { padding: 6px 10px; font-size: 11px; }
    .vm-word-en { font-size: 13.5px; }
    .vm-word-zh { font-size: 11.5px; }
    .vm-add-group { padding: 12px; font-size: 13px; }
    .vmenu-item { font-size: 13.5px; padding: 11px; }
}
/* 尊重「减少动态效果」：只留淡入，不要位移
   （这一段属于**整理页**那套弹层，必须留在这份样式里；它曾被搬样式时误删过一回） */
@media (prefers-reduced-motion: reduce) {
    .vmenu-panel, .vconfirm-panel { transform: none; transition: opacity .12s linear; }
    .vmenu.show .vmenu-panel, .vconfirm.show .vconfirm-panel { transform: none; }
    .vmenu-backdrop, .vconfirm-backdrop { transition: opacity .12s linear; }
    .vm-group, .vm-word, .vm-mini-btn, .vm-add-group, .vmenu-item { transition: none; }
}

/* ===== TASK-WORD-10ISSUES-W2（#2/#3/#5/#6）：词资料那一块 =====
   学习卡背面、阅读器词条、单词详情三处现在画的是**同一份**义项（senses），
   所以样式也只在这一份里定：一排词性小签 + 一块会随小签一起换的「释义 + 例句」。
   一个义项的词不摆签，读起来跟以前完全一样。 */

/* 一排词性小签（可点，当前那一档高亮） */
.vb-pos-row { display: flex; flex-wrap: wrap; gap: 6px; margin: 2px 0 10px; }
.vb-pos-chip {
    display: inline-block; margin: 0; padding: 2px 10px;
    border: 1px solid var(--ec-line); border-radius: 999px;
    background: none; color: var(--ec-sub);
    font-family: var(--font-display); font-style: italic;
    font-size: 10.5px; line-height: 1.9; white-space: nowrap;
    cursor: pointer; -webkit-tap-highlight-color: transparent;
    transition: color var(--ec-dur) var(--ec-ease), border-color var(--ec-dur) var(--ec-ease),
                background var(--ec-dur) var(--ec-ease), transform var(--ec-dur) var(--ec-ease);
}
.vb-pos-chip:active { transform: scale(0.94); }
.vb-pos-chip.is-on {
    color: var(--ec-rose-ink); border-color: rgba(201, 168, 168, 0.38);
    background: rgba(201, 168, 168, 0.10);
}
/* 切完那一小下（一次性 class：重画完给一点「换过了」的感觉，不常驻、不参与布局） */
.vb-sense-body.is-swap { animation: vbSenseSwap .26s var(--ec-ease) both; }
@keyframes vbSenseSwap {
    from { opacity: 0; transform: translateY(3px); }
    to { opacity: 1; transform: none; }
}
@media (prefers-reduced-motion: reduce) {
    .vb-sense-body.is-swap { animation: none; }
}

/* 义项里的释义与例句（与原来的 .vb-card-zh / .vb-card-ex 同一套排版，只是换了容器） */
.vb-sense-zh { font-size: 14.5px; line-height: 1.85; color: var(--ec-ink); }
.vb-oneshot-detail .vb-sense-zh { font-size: 13px; line-height: 1.7; }
.vb-sense-ex { margin-top: 10px; text-align: left; }
.vb-ex-row { position: relative; padding-right: 26px; }
.vb-oneshot-detail .vb-ex-row { padding-right: 22px; }
.vb-ex-row + .vb-ex-row { margin-top: 8px; }
.vb-ex-zh { font-size: 12px; line-height: 1.7; color: var(--ec-sub); margin-top: 2px; }
.vb-oneshot-detail .vb-ex-en { font-size: 12px; line-height: 1.75; color: var(--ec-sub); }
.vb-oneshot-detail .vb-ex-zh { font-size: 11px; color: var(--ec-faint); }
/* 例句里的词：点一下看那个词（**不是链接的样子**，只是一层淡淡的底，像指尖按过的痕） */
.vb-ex-word {
    border-radius: 3px; cursor: pointer;
    transition: background var(--ec-dur) var(--ec-ease), color var(--ec-dur) var(--ec-ease);
}
.vb-ex-word:active { background: rgba(201, 168, 168, 0.22); color: var(--ec-rose-ink); }
@media (hover: hover) { .vb-ex-word:hover { background: rgba(201, 168, 168, 0.12); } }
/* 念这一句：例句右边那枚很轻的小按钮（触控目标按 44px 的透明外圈给足） */
.vb-ex-play {
    position: absolute; right: -6px; top: -6px;
    width: 32px; height: 32px; padding: 0;
    display: inline-flex; align-items: center; justify-content: center;
    border: 0; background: none; color: var(--ec-faint); cursor: pointer;
    transition: color var(--ec-dur) var(--ec-ease), transform var(--ec-dur) var(--ec-ease);
}
.vb-ex-play:active { transform: scale(0.9); color: var(--ec-rose-ink); }
/* 厚资料那一行（英文释义 · 难度）：有就显示，没有就一个字都不加 */
.vb-card-rich { margin-top: 12px; }
.vb-rich-en { font-family: var(--font-display); font-size: 11.5px; line-height: 1.7; color: var(--ec-faint); }
/* 「短语常见搭配」直接摆在卡片背面（甲方第 4 条：卡展开就要看得见，不必再进详情页往下滑）。
   一行一条，**每一条自己一个小框**（甲方第 3 条(c)：原话「排版有点乱，希望给短语包个框」）：
   框里上面是搭配本身（点里面的词能看那个词），下面一行是**这个词组自己的中文意思**。 */
.vb-rich-colloc {
    display: flex; flex-direction: column; gap: 1px; margin-top: 6px;
    box-sizing: border-box; padding: 7px 9px; border-radius: 9px;
    /* ★ 2026-10-09 甲方第 3 条：这里从前写死 `background: rgba(255,255,255,0.5)`
       —— 浅色下是「比卡片更白的一小块」，暗色下就成了一块**白板**，配上面那些
       跟着主题变浅的文字（`--ec-ink` / `--ec-faint`）＝白字白底，整条看不清。
       改成认主题令牌：`--ec-fill` 浅色是米色薄底、暗色是暖米薄底（两套都在 panels-learning.css 里定过），
       边框同理走 `--ec-line`。同类盒子（.vb-… 那一批）本来就是这套令牌，这里漏了一处。 */
    border: 1px solid var(--ec-line); background: var(--ec-fill);
}
.vb-rich-colloc:first-child { margin-top: 0; }
.vb-rich-colloc-t { font-family: var(--font-display); font-size: 12.5px; line-height: 1.6; color: var(--ec-ink); }
.vb-rich-colloc-x { font-size: 11px; line-height: 1.6; color: var(--ec-faint); }
/* 阅读器里那一块（一屏十几个词）：框留、底去掉，免得一条条太抢眼 */
.vb-oneshot-detail .vb-rich-colloc { padding: 5px 8px; border-color: var(--ec-line); background: none; }
.vb-oneshot-detail .vb-card-rich { margin-top: 5px; }
.vb-oneshot-detail .vb-rich-en { font-size: 11px; }
.vb-oneshot-detail .vb-rich-colloc-t { font-size: 12px; }
/* 阅读器词条里那一块（词性签与例句都在这一层，跟着词形的排版走） */
.vb-oneshot-detail { display: block; }
.vb-oneshot-detail .vb-pos-row { margin: 3px 0 7px; }
/* 详情页里那一块（释义与例句跟着小签一起换） */
#vd-senses .vd-zh { font-size: 14.5px; line-height: 1.85; color: var(--ec-ink); }
#vd-senses .vb-pos-row { margin: 4px 0 12px; }
#vd-senses .vd-ex { margin-top: 10px; }
/* ===== 随手快刷题的「先选一轮」那屏（甲方第 8 条）=====
   范围三选一 + 出几道题 + 题型多选；选项一律 44px 起的触摸目标（窄屏也量得到）。 */
.vb-set { display: block; }
.vb-set-blk { margin-top: 18px; }
.vb-set-blk:first-child { margin-top: 6px; }
.vb-set-t { font-size: 13px; color: var(--ec-ink); margin-bottom: 8px; }
.vb-set-sub { margin-left: 8px; font-size: 11px; color: var(--ec-faint); }
.vb-set-row { display: flex; flex-wrap: wrap; gap: 8px; }
.vb-set-i {
    box-sizing: border-box; min-height: var(--ec-touch); padding: 0 14px;
    display: inline-flex; align-items: center; justify-content: center;
    cursor: pointer; border: 1px solid var(--ec-line); border-radius: var(--ec-radius-s);
    background: var(--ec-surface-2); color: var(--ec-ink);
    font-family: var(--font-body); font-size: 13.5px;
    transition: border-color var(--ec-dur) var(--ec-ease), background var(--ec-dur) var(--ec-ease), transform var(--ec-dur-fast) var(--ec-ease);
}
.vb-set-i.is-on { border-color: var(--rose); background: var(--rose-light); }
.vb-set-i:active { transform: scale(0.98); }
.vb-set-banks { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 8px; }
.vb-set-banks:empty { margin-top: 0; }
.vb-set-note { margin-top: 10px; font-size: 11.5px; line-height: 1.8; color: var(--ec-faint); }
/* 刷题过程中「换范围 / 题量 / 题型」那一条：低调，但整行都是可点的 */
.vb-drill-tools { padding: 0 24px; margin-top: 2px; }
.vb-drill-tools .ec-btn-text { min-height: var(--ec-touch); padding: 0 2px; font-size: 12.5px; color: var(--ec-faint); }
/* ===== 口语题（甲方第 6 条）===== */
.vb-say-note { margin-top: 10px; font-size: 12px; color: var(--ec-faint); }
.vb-say-heard {
    margin-top: 12px; padding: 10px 12px; border-radius: var(--ec-radius-s);
    background: var(--ec-surface-2); border: 1px solid var(--ec-line);
    font-size: 13px; line-height: 1.7; color: var(--ec-ink); word-break: break-word;
}
.vb-say-heard b { font-family: var(--font-display); font-weight: 400; }
.vb-say-empty { color: var(--ec-faint); }
.vb-say-row { display: flex; gap: 8px; margin-top: 12px; }
.vb-say-row .ec-btn { flex: 1 1 0; min-width: 0; }
.vb-say-ref { margin-top: 12px; font-size: 13px; line-height: 1.8; color: var(--ec-ink); word-break: break-word; }
.vb-say-selfnote { margin-top: 6px; font-size: 11.5px; color: var(--ec-faint); }
.vb-say-self { display: flex; gap: 8px; margin-top: 10px; }
.vb-say-self-i {
    flex: 1 1 0; min-width: 0; box-sizing: border-box; min-height: var(--ec-touch);
    cursor: pointer; border: 1px solid var(--ec-line); border-radius: var(--ec-radius-s);
    background: var(--ec-surface-2); color: var(--ec-ink);
    font-family: var(--font-body); font-size: 13px;
    transition: border-color var(--ec-dur) var(--ec-ease), background var(--ec-dur) var(--ec-ease), transform var(--ec-dur-fast) var(--ec-ease);
}
.vb-say-self-i.is-on { border-color: var(--rose); background: var(--rose-light); }
.vb-say-self-i:active { transform: scale(0.98); }
.vb-say-self-i[disabled] { opacity: 0.6; cursor: default; }
.vb-say-reply {
    margin-top: 12px; padding: 10px 12px; border-radius: var(--ec-radius-s);
    background: var(--rose-light); border: 1px solid var(--rose);
    font-size: 13px; line-height: 1.8; color: var(--ec-ink); word-break: break-word;
}
.vb-say-reply-t { font-size: 11px; color: var(--ec-faint); margin-bottom: 4px; }
.vb-say-wait { margin-top: 10px; font-size: 11.5px; color: var(--ec-faint); }
