/* ==========================================================================
   「单词」主场 · /vocabulary
   规格真相源:docs/VOCABULARY_SYSTEM_DESIGN.md §4–§6 / §8 / §9
   (几何/字号/文案照抄,不自创;释义体例见 docs/VOCABULARY_GLOSS_PRESENTATION.md)

   颜色只用 design-tokens.css 的 --dl-*;唯一例外 = §4.4 单词本 5 色板(--wb-c1..5)
   与 §5.1 指定的遮罩值。**全文件不得出现 inset Npx 0 0 <色> 或 border-left: Npx solid <色>**
   —— §1.6 全面禁止标签左侧颜色竖条,选中态只用底色 + 词头字重。
   动效:悬停瞬时(--dl-t-hover = 0);列表/详情切换 120/80ms(§8);
   prefers-reduced-motion 下全部归零。
   ========================================================================== */

:root {
    /* §4.4 色板(唯一真相源,低饱和不艳丽);--wb-t* = 同色 8% 淡底,只用于选中 chip */
    --wb-c1: #4A6A8A;
    --wb-c2: #4F7561;
    --wb-c3: #A0755C;
    --wb-c4: #6E6A8C;
    --wb-c5: #94564E;
    --wb-t1: rgba(74, 106, 138, .08);
    --wb-t2: rgba(79, 117, 97, .08);
    --wb-t3: rgba(160, 117, 92, .08);
    --wb-t4: rgba(110, 106, 140, .08);
    --wb-t5: rgba(148, 86, 78, .08);
}

.vocab-c1 { --wb: var(--wb-c1); --wb-t: var(--wb-t1); }
.vocab-c2 { --wb: var(--wb-c2); --wb-t: var(--wb-t2); }
.vocab-c3 { --wb: var(--wb-c3); --wb-t: var(--wb-t3); }
.vocab-c4 { --wb: var(--wb-c4); --wb-t: var(--wb-t4); }
.vocab-c5 { --wb: var(--wb-c5); --wb-t: var(--wb-t5); }

/* style.css:494 给 <body> 加了 overflow-y: auto(注释写「防止滚动条导致的内容位移」,
   但 html 的 overflow-y: scroll 已经做到了这件事)。它让 body 成为滚动容器,
   页内一切 position: sticky; bottom: 0 都不再吸附(实测:资源库入口条掉到文末)。
   只在有本页时还原成默认值;:has 不支持的浏览器里入口条退化成列表末尾一行,不报错。 */
/* 页面底改浅灰(§18.6.1):区分靠「白面板浮起来」,不靠颜色。零新颜色,用既有令牌。
   底色挂在 body 上(而非 .vocab-page)才能铺满视口 gutter,否则灰只占内容宽度。
   主选择器 = 模板经 base.html 的 {% block body_class %} 挂上的类(确定性、无浏览器条件);
   :has() 那条只作兜底,不支持它的浏览器不会整页退回白底。 */
body.has-vocab-page,
body:has(.vocab-page) { overflow-y: visible; background: var(--dl-surface-2); }

body.vocab-locked { overflow: hidden; }

/* 分段面板显隐(§18.2.2):切换只换这两块,今日卡在两块之上不受影响 */
.vocab-seg-panel[hidden] { display: none; }

.vocab-page {
    /* 站点 .container 已给 12px 内边距;这里补 12 → 视口边距合计 24(规格值) */
    max-width: 1200px;
    margin: 0 auto;
    padding: 0 12px;
    font-family: var(--dl-font);
    /* 字母分组头与详情面板 sticky 的基准 = 站点顶栏高(.header-inner 60px) */
    --vocab-header-h: 60px;
    /* 单词本切换行 .vocab-books 吸顶后自己占掉的高,手量的估值,没有运行时测量。
       52 = 36 + 2×8:36 来自 .vocab-books-right 里的 .vocab-seg(height: var(--dl-ctl)),
       它比左边的 .vocab-books-chips(30 chip + 上下各 4 的环留白,被等量负外边距抵回 30)高,
       所以撑高这一行的是 .vocab-seg 而不是 chip;8 是 .vocab-books 自己的上下 padding。
       依赖它的有两处,都在 .vocab-detail-col 上:sticky 的 top 起点、以及内层 .vocab-detail 的
       max-height。改 .vocab-seg 的 --dl-ctl、.vocab-books 的 padding、或让 chip 高过 36 的任何
       改动,都必须同步把这个 52 重算,否则详情列会被切换行盖住 / 高度算错。 */
    --vocab-books-h: 52px;
}

/* ── 标题行 ───────────────────────────────────────────────────────── */

.vocab-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--dl-sp-16);
}

/* 分段切换器(§18.2.3):两文字项,选中 --dl-ink + 600 + 下方 2px 与文字对齐的实线;
   未选 --dl-ink-3 + 400,悬停 --dl-ink-2。留在灰底上,不做成面板。 */
.vocab-tabs {
    display: flex;
    align-items: baseline;
    gap: var(--dl-sp-24);
    flex: 1 1 auto;
    min-width: 0;
}

.vocab-tab {
    appearance: none;
    border: none;
    background: transparent;
    padding: 0 0 4px;
    font-family: var(--dl-font);
    font-size: var(--dl-fs-section);
    line-height: var(--dl-lh-section);
    font-weight: 400;
    color: var(--dl-ink-3);
    cursor: pointer;
    /* 下划线用 border-bottom(与文字左右对齐,不撑满);未选时透明占位,选中不跳行 */
    border-bottom: 2px solid transparent;
}

.vocab-tab[aria-selected="true"] {
    color: var(--dl-ink);
    font-weight: 600;
    border-bottom-color: var(--dl-ink);
}

@media (hover: hover) {
    .vocab-tab:not([aria-selected="true"]):hover { color: var(--dl-ink-2); }
}

/* ── 进度段(§18.5) ──────────────────────────────────────────────────
   区块次序 = §18.5.2 自上而下:概览条 / 接下来要复习的量 / 熟练度分布 / 不熟悉的词。
   日历热力图(第 5 区)已撤下;「每天做了多少」「真实保持率」(第 6/7 区)要复习流水表,
   本轮不出现 —— 见 ReviewService.get_progress。补的时候在这里各加一个 .vocab-prog-block。
   零新颜色:图表的四档与柱子全部用全站那套渐进色阶(--dl-seq-1 → -2 → -3 → -5,
   热力图、试卷难度同一套),深浅本身就是「越来越熟」,不另立一套语义色。 */

.vocab-seg-panel {
    margin-top: var(--dl-sp-24);
}

/* 未登录 / 零收藏 / 加载失败:留在灰底上,不做成面板(它不是内容,是一句交代) */
.vocab-prog-state {
    margin: var(--dl-sp-24) 0 0;
    padding: 0 var(--dl-sp-4);
    font-size: var(--dl-fs-body);
    line-height: var(--dl-lh-body);
    color: var(--dl-ink-2);
}

.vocab-prog-state[hidden] { display: none; }

/* 每个区块 = 白面板(§6.4:卡片间距 16、卡片内衬 24) */
.vocab-prog-block {
    padding: var(--dl-sp-24);
    background: var(--dl-surface);
    border-radius: var(--dl-r-panel);
    box-shadow: var(--dl-sh-1);
}

.vocab-prog-block + .vocab-prog-block { margin-top: var(--dl-sp-16); }

.vocab-prog-head {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: var(--dl-sp-8) var(--dl-sp-12);
    min-height: var(--dl-ctl);
}

/* §6.4:区块标题 16/600（原 20/28 与「大数」抢重量,数才是这一页的主角） */
.vocab-prog-title {
    margin: 0;
    font-size: var(--dl-fs-headword);
    line-height: var(--dl-lh-headword);
    font-weight: 600;
    color: var(--dl-ink);
}

/* 区块标题右侧的一句机器结论(如「最高的一天 12 个」);切换器占这个位置时它为空 */
.vocab-prog-note {
    margin-left: auto;
    font-size: var(--dl-fs-caption);
    line-height: var(--dl-lh-caption);
    color: var(--dl-ink-3);
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

/* 「按词 / 按真题」切换器:沿用页内既有的分段控件语言(.vocab-seg),不新造一种控件。
   .vocab-seg 是 inline-flex,不补这一条 [hidden] 收不住(空态时它不该出现)。 */
.vocab-prog-head .vocab-seg { margin-left: auto; }
.vocab-prog-head .vocab-seg[hidden] { display: none; }

/* 标题下的一行解释(门槛、口径)。串由后端拼,这里只管排。 */
.vocab-prog-cap {
    margin: var(--dl-sp-4) 0 0;
    font-size: var(--dl-fs-caption);
    line-height: var(--dl-lh-caption);
    color: var(--dl-ink-3);
}

/* 指标四格(§6.4 第 2 条):连续天数 · 收藏 · 长期记忆 · 距考研。标签 12 弱墨、数 24/600 */
.vocab-prog-overview {
    display: grid;
    grid-template-columns: repeat(4, minmax(0, 1fr));
    gap: 16px;
    margin: 0;
    font-size: var(--dl-fs-body);
    line-height: var(--dl-lh-body);
    color: var(--dl-ink);
    font-variant-numeric: tabular-nums;
}

.vocab-prog-metric {
    display: flex;
    flex-direction: column;
    gap: 6px;
    /* 入口格是 <button>、非入口格是 <span>:两者的盒子必须一模一样,
       否则四格的基线与左边缘要差出按钮自带的内边距那几像素。 */
    position: relative;
    appearance: none;
    margin: 0;
    padding: 0;
    border: 0;
    background: none;
    font: inherit;
    color: inherit;
    text-align: left;
}

/* 入口格(收藏 / 长期记忆 §14.6 第 3 条):点了去单词本。悬停只换底色、不位移(§1.2)。
   底色画在一层往外扩 6px 的伪元素上,不给格子加内边距 —— 加了内边距,标签的左缘就与
   下面「到期安排」标题错开 6px。z-index:-1 把它压到文字底下(格子自己没有背景,不会盖住)。 */
.vocab-prog-metric--link { cursor: pointer; }

.vocab-prog-metric--link::before {
    content: '';
    position: absolute;
    inset: -6px;
    z-index: -1;
    border-radius: var(--dl-r-item-lg);
}

@media (hover: hover) {
    .vocab-prog-metric--link:hover::before { background: var(--dl-hover); }
}

.vocab-prog-metric--link:focus-visible { outline: none; }
.vocab-prog-metric--link:focus-visible::before { box-shadow: var(--dl-focus-ring); }

.vocab-prog-metric-label { color: var(--dl-ink-3); font-size: var(--dl-fs-caption); }
.vocab-prog-metric-value { font-size: 24px; font-weight: 600; line-height: 1.3; }

/* ── 每天复习了多少(§18.5.2 第 5 区)────────────────────────────────────────
   一格一天、一列一周,**周一在最上面**(中国习惯,不是 GitHub 的周日起)。
   深浅只认当天的复习个数,收藏/浏览/答题不上色 —— 档与色由后端给的 level 决定,
   这里只有四条 background。零新颜色:空 --dl-surface-2(与熟练度条的槽底同一档)、
   1 档 --dl-seq-2、2 档 --dl-seq-3、3 档 --dl-seq-5,取全站渐进色阶的上三档
   (最浅的 --dl-seq-1 这一档为什么不能用,理由写在下面 .vocab-cal-l1 那里)。
   缺席的日子(今天之后、首条记录之前)后端不下发,前端也就不画 —— 不画空格,
   因为一个灰格子的意思是「这天你没学」,而那时还没有你。 */

.vocab-cal {
    /* 一格的边长与格间距:月份刻度、星期刻度全按它算,只有这一处真相源(§6.4 第 3 条:格 12、间距 3)。 */
    --vc-cell: 12px;
    --vc-gap: 3px;
}

/* 两行两列:[空][月份刻度] / [星期刻度][网格]。--vc-cols 由 JS 按后端列数写在行内。 */
.vocab-cal {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr);
    column-gap: var(--dl-sp-8);
    row-gap: var(--dl-sp-4);
    margin-top: var(--dl-sp-12);
}

.vocab-cal-months,
.vocab-cal-grid {
    grid-column: 2;
    display: grid;
    /* 列宽写 1fr + max-width 封顶,不直接写 --vc-cell:26 列 × 17px = 439px,
       手机 390 宽下装不进面板(内容宽只剩 334)。装得下时 max-width 生效 = 正正方方的
       14px 格、左对齐不拉伸;装不下时列等比收窄、格子靠 aspect-ratio 保持正方,
       **不出横向滚动条**。两处用同一个 max-width 与同一套列轨,月份刻度才对得上列。 */
    grid-template-columns: repeat(var(--vc-cols), minmax(0, 1fr));
    column-gap: var(--vc-gap);
    max-width: calc(var(--vc-cols) * (var(--vc-cell) + var(--vc-gap)) - var(--vc-gap));
}

.vocab-cal-months { grid-row: 1; }

.vocab-cal-week {
    grid-column: 1;
    grid-row: 2;
    display: grid;
    /* 七行等分 + 同一个行距 → 与右边网格的七行逐行对齐(行高由格子的 aspect-ratio 定,
       这里跟着拉伸,不写死高度) */
    grid-template-rows: repeat(7, 1fr);
    row-gap: var(--vc-gap);
}

.vocab-cal-grid {
    grid-row: 2;
    /* 行也写死七行:格子由 JS 显式定位(gridRow/gridColumn),缺席的日子没有元素,
       靠隐式行会让后面的格子递补到空位、整张图错位一格 */
    grid-template-rows: repeat(7, auto);
    row-gap: var(--vc-gap);
}

.vocab-cal-cell {
    display: block;
    appearance: none;
    min-width: 0;
    min-height: 0;
    width: 100%;
    padding: 0;
    border: 0;
    aspect-ratio: 1;
    border-radius: 2px;
    background: var(--dl-surface-2);
    cursor: pointer;
    -webkit-user-select: none;
    user-select: none;
}

.vocab-cal-cell:focus-visible {
    outline: none;
    box-shadow: var(--dl-focus-ring);
}

/* 今日格:1px 墨色描边(§6.4 第 3 条)。用 inset 阴影不用 border —— 格子的边长由
   aspect-ratio 与列宽定,border 会把它撑成 14px、整行错位。 */
.vocab-cal-cell.is-today { box-shadow: inset 0 0 0 1px var(--dl-ink); }

/* 进度段唯一的气泡(§14.6 第 1 条:热力图格、指标四格、到期柱、记忆分布四段与图例共用一件)。
   材质沿用难度气泡；固定定位不挤动图表，也不受卡片裁切。 */
.vocab-hint {
    position: fixed;
    box-sizing: border-box;
    width: max-content;
    max-width: min(240px, calc(100vw - 32px));
    padding: 5px 8px;
    border-radius: var(--dl-r-item);
    background: var(--dl-surface);
    color: var(--dl-ink);
    box-shadow: var(--dl-sh-menu);
    font-size: var(--dl-fs-caption);
    line-height: var(--dl-lh-caption);
    overflow-wrap: anywhere;
    pointer-events: none;
    z-index: var(--dl-z-account-menu);
    opacity: 0;
    transition: opacity var(--dl-t-state) ease;
}

.vocab-hint.is-visible { opacity: 1; }
.vocab-hint[hidden] { display: none; }

@media (prefers-reduced-motion: reduce) {
    .vocab-hint { transition: none; }
}

/* 阶梯整条上移一档,从 --dl-seq-2 起步:色阶最浅的 --dl-seq-1 贴在空格 --dl-surface-2
   旁边分不开,于是一个真复习了 4 个词的日子看着像没学 —— 这一格恰恰是最该被看见的那种
   (刚开始学、量还小)。熟练度分布条那边最浅档留得住 --dl-seq-1,是因为它有槽底和发丝环
   把整条框成一个物件;日历没有框,只能靠格子自己。 */
.vocab-cal-l1 { background: var(--dl-seq-2); }
.vocab-cal-l2 { background: var(--dl-seq-3); }
.vocab-cal-l3 { background: var(--dl-seq-5); }

/* 刻度:12px 弱墨(§6.4 第 3 条月份标签 12px;周标签同一条规则,同值)。
   行高写 1 而不是 --dl-lh-caption(16px) —— 星期刻度要挤进 12px(手机 10px)的一行里,
   16px 的行盒会把七行撑高、与右边网格错位。 */
.vocab-cal-month,
.vocab-cal-day {
    font-size: var(--dl-fs-caption);
    line-height: 1;
    color: var(--dl-ink-3);
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

/* 月份刻度落在该月第一列上(列号由 JS 写);标签比一列宽,溢到右边相邻列上不裁 */
.vocab-cal-month { grid-row: 1; }

.vocab-cal-day { align-self: center; }

/* 到期安排:30 根柱子 + 每七天一个刻度。柱高按窗口内最高的一天归一化。 */
.vocab-prog-chart {
    margin-top: var(--dl-sp-12);
    /* 给刻度标签留出的行高:标签是绝对定位挂在柱子底下的,不占流 */
    padding-bottom: 18px;
}

.vocab-prog-bars {
    display: flex;
    align-items: flex-end;
    gap: 2px;
    height: 72px;
    border-bottom: 1px solid var(--dl-line);
}

.vocab-prog-col {
    position: relative;
    flex: 1 1 0;
    min-width: 0;
    height: 100%;
    display: flex;
    align-items: flex-end;
}

.vocab-prog-col-fill {
    display: block;
    width: 100%;
    border-radius: 1px 1px 0 0;
    background: var(--dl-seq-3);
}

/* 今天那一根加深:图里唯一需要一眼找到的位置 */
.vocab-prog-col.is-today .vocab-prog-col-fill { background: var(--dl-ink); }

.vocab-prog-tick {
    position: absolute;
    top: 100%;
    left: 0;
    margin-top: var(--dl-sp-4);
    font-size: var(--dl-fs-micro);
    line-height: var(--dl-lh-micro);
    color: var(--dl-ink-3);
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

/* 熟练度分布:一条横向分段条。段宽按计数分(flex-grow 由 JS 写),四段正好铺满。
   四档走全站那套渐进色阶 --dl-seq-1 / -2 / -3 / -5(热力图、试卷难度同一套),
   越熟越深 —— 深浅本身就是「越来越熟」的语义梯度,四档的相对次序不能动。
   槽底 --dl-surface-2(页面底色那一档)留着:段间 2px 的缝从白色变成浅灰,
   四段的分节在白面板上才读得出来。深色下 surface-2(#0F172A)比面板 surface(#1E293B)
   更深,同样是一条凹槽,两套主题都成立。 */
.vocab-prog-mbar {
    position: relative;
    display: flex;
    gap: 2px;
    height: 8px;
    margin-top: var(--dl-sp-12);
    background: var(--dl-surface-2);
    border-radius: 2px;
}

/* 发丝环:把整条框成一个物件,最浅那档于是落在框内被读到,而不是化进白面板。
   ① 画在覆盖层上,不画在 .vocab-prog-mbar 自己身上 —— inset 阴影属于元素的背景层,
      而四段用 flex-grow **铺满整个盒子**、且默认 stretch 到满高,会把那圈环整个盖住
      (只剩 2px 段缝里露一点)。绝对定位的伪元素在段之后绘制,压在段上面才看得见。
   ② 用 inset box-shadow 不用 border:环画在盒内,8px 的条高一像素不变(border 会撑成 10px)。
   ③ pointer-events:none —— 段自带 title 悬停提示,覆盖层不许把它挡掉。 */
.vocab-prog-mbar::after {
    content: '';
    position: absolute;
    inset: 0;
    border-radius: 2px;
    box-shadow: inset 0 0 0 1px var(--dl-line);
    pointer-events: none;
}

/* 四段各是一个入口(§14.6 第 3 条):点了跳到单词本、筛这一档,所以是 <button> 不是 <span>。
   焦点环用 outline + 2px offset:段只有 8px 高,画在盒内的环会被上面那层发丝环覆盖层盖掉。 */
.vocab-prog-seg {
    display: block;
    min-width: 0;
    padding: 0;
    border: 0;
    appearance: none;
    border-radius: 2px;
    cursor: pointer;
}

.vocab-prog-seg:focus-visible {
    outline: none;
    box-shadow: var(--dl-focus-ring);
}

.vocab-prog-seg--1, .vocab-prog-dot--1 { background: var(--dl-seq-1); }
.vocab-prog-seg--2, .vocab-prog-dot--2 { background: var(--dl-seq-2); }
.vocab-prog-seg--3, .vocab-prog-dot--3 { background: var(--dl-seq-3); }
.vocab-prog-seg--4, .vocab-prog-dot--4 { background: var(--dl-seq-5); }

.vocab-prog-legend {
    list-style: none;
    margin: var(--dl-sp-12) 0 0;
    padding: 0;
    display: flex;
    flex-wrap: wrap;
    gap: var(--dl-sp-8) var(--dl-sp-16);
}

.vocab-prog-legend-item {
    display: flex;
    align-items: center;
    gap: var(--dl-sp-8);
    font-size: var(--dl-fs-caption);
    line-height: var(--dl-lh-caption);
}

.vocab-prog-dot {
    width: 8px;
    height: 8px;
    border-radius: var(--dl-r-pill);
    flex: 0 0 auto;
}

.vocab-prog-legend-label { color: var(--dl-ink-2); }

.vocab-prog-legend-n {
    color: var(--dl-ink);
    font-variant-numeric: tabular-nums;
}

/* 空态与说明行:空态解释的是「什么样的词会来这里」,不是「暂无数据」(§18.13) */
.vocab-prog-empty,
.vocab-prog-note-line {
    margin: var(--dl-sp-12) 0 0;
    font-size: var(--dl-fs-caption);
    line-height: var(--dl-lh-caption);
    color: var(--dl-ink-3);
}

/* 不熟悉的词:两个视图共用 §4.5 那套行组件,只多一条出处行 */
.vocab-prog-list { margin-top: var(--dl-sp-8); }

.vocab-prog-list[hidden] { display: none; }

.vocab-prog-group + .vocab-prog-group { margin-top: var(--dl-sp-16); }

/* 组标题是陈述式(「这些词出现在 X」),不是名次条 —— 分组只是排布,不是判断(§18.13) */
.vocab-prog-group-head {
    appearance: none;
    border: none;
    background: transparent;
    width: 100%;
    display: flex;
    align-items: baseline;
    gap: var(--dl-sp-8);
    margin-top: var(--dl-sp-12);
    padding: var(--dl-sp-8) var(--dl-sp-12);
    border-radius: var(--dl-r-item-lg);
    font-family: var(--dl-font);
    text-align: left;
    cursor: pointer;
}

@media (hover: hover) {
    .vocab-prog-group-head:hover { background: var(--dl-hover); }
}

.vocab-prog-group-title {
    font-size: var(--dl-fs-body);
    line-height: var(--dl-lh-body);
    font-weight: 500;
    color: var(--dl-ink);
}

.vocab-prog-group-n {
    margin-left: auto;
    font-size: var(--dl-fs-caption);
    line-height: var(--dl-lh-caption);
    color: var(--dl-ink-3);
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

/* 就地展开的详情:不另开第二套详情宿主,renderDetail 直接渲进行里。
   展开的那一行只用词头字重标出(与 .is-selected 同一个语言),底色不动 ——
   否则整块详情会连着被 :hover 的灰底染一遍。 */
.vocab-prog-list .vocab-row.is-open .vocab-row-w { font-weight: 600; }
.vocab-prog-list .vocab-row.is-open:hover { background: transparent; }

.vocab-prog-detail {
    margin-top: var(--dl-sp-8);
    padding-top: var(--dl-sp-8);
    border-top: 1px solid var(--dl-line);
}

.vocab-search-wrap {
    position: relative;
    width: 280px;
    flex: 0 0 auto;
}

.vocab-search-icon {
    position: absolute;
    left: 10px;
    top: 50%;
    margin-top: -8px;
    width: var(--dl-icon);
    height: var(--dl-icon);
    color: var(--dl-ink-3);
    pointer-events: none;
}

.vocab-search {
    width: 100%;
    height: var(--dl-ctl);
    box-sizing: border-box;
    padding: 0 10px 0 34px;
    border: 1px solid var(--dl-line);
    border-radius: 8px;
    background: var(--dl-surface);
    color: var(--dl-ink);
    font-family: var(--dl-font);
    font-size: var(--dl-fs-body);
    appearance: none;
}

/* 触屏上查词框要够点（本轮全站触摸目标走查）：它是 <input>，替换元素不渲染伪元素，
   没法像别的控件那样用透明扩区把命中区顶到 48，只能改自身高度。36 → 48，
   是这一轮唯一一处视觉尺寸跟着变大的控件。 */
@media (pointer: coarse) {
    .vocab-search {
        height: 48px;
    }
}

.vocab-search::placeholder { color: var(--dl-ink-3); }
.vocab-search::-webkit-search-cancel-button { appearance: none; }

/* ── 查词下拉(Edge 材质由 .dl-mat-edge 提供) ───────────────────────── */

/* 搜索框贴着页面右缘,下拉的 ≥320 只能往左长,故锚右边 */
.vocab-suggest {
    position: absolute;
    top: calc(100% + var(--dl-gap-anchor));
    right: 0;
    min-width: 320px;
    width: 100%;
    box-sizing: border-box;
    padding: var(--dl-pad-panel);
    z-index: 200;
}

.vocab-suggest[hidden] { display: none; }

.vocab-suggest-item {
    display: flex;
    align-items: center;
    gap: var(--dl-sp-8);
    height: var(--dl-row);
    padding: 0 10px 0 12px;
    border-radius: var(--dl-r-item);
    cursor: pointer;
}

.vocab-suggest-item.is-active { background: var(--dl-surface-2); }

@media (hover: hover) {
    .vocab-suggest-item:hover { background: var(--dl-surface-2); }
}

.vocab-suggest-w {
    font-size: var(--dl-fs-body);
    font-weight: 500;
    color: var(--dl-ink);
    flex: 0 0 auto;
}

.vocab-suggest-g {
    font-size: var(--dl-fs-caption);
    color: var(--dl-ink-3);
    flex: 1 1 auto;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    text-align: right;
}

.vocab-suggest-empty {
    height: var(--dl-row);
    display: flex;
    align-items: center;
    padding: 0 12px;
    font-size: var(--dl-fs-caption);
    color: var(--dl-ink-3);
}

/* ── 今日卡(§18.6.5:白面板 + 进度条 + 底行) ─────────────────────── */

/* 常驻在两个分段之上。白面板浮在灰底上,不再用上下 1px 分隔线区分。 */
.vocab-today {
    /* 面板之间恒 24(§18.6.1);今日卡与上方标题行同样是面板间距 */
    margin-top: var(--dl-sp-24);
    padding: var(--dl-sp-16);
    background: var(--dl-surface);
    border-radius: var(--dl-r-panel);
    box-shadow: var(--dl-sh-1);
}

.vocab-today[hidden] { display: none; }

.vocab-today-head {
    display: flex;
    align-items: center;
    gap: var(--dl-sp-16);
}

.vocab-today-text {
    display: flex;
    align-items: baseline;
    gap: var(--dl-sp-12);
    min-width: 0;
}

.vocab-today-title {
    font-size: var(--dl-fs-headword);
    font-weight: 600;
    color: var(--dl-ink);
    white-space: nowrap;
}

/* 还要复习多少个:整张卡唯一的大数(§6.4 第 1 条 28/600) */
.vocab-today-count {
    font-size: var(--dl-fs-word-md);
    line-height: var(--dl-lh-word-md);
    font-weight: 600;
    color: var(--dl-ink);
    font-variant-numeric: tabular-nums;
}

.vocab-today-sub {
    font-size: var(--dl-fs-caption);
    color: var(--dl-ink-3);
    white-space: nowrap;
}

/* 全页唯一的实心按钮 */
.vocab-today-btn {
    margin-left: auto;
    flex: 0 0 auto;
    height: var(--dl-ctl);
    display: inline-flex;
    align-items: center;
    padding: 0 var(--dl-sp-16);
    border-radius: 8px;
    background: var(--dl-ink);
    color: var(--dl-surface);
    font-size: var(--dl-fs-body);
    font-weight: 500;
    text-decoration: none;
    transition: background-color var(--dl-t-state) ease;
}

@media (hover: hover) {
    .vocab-today-btn:hover {
        background: color-mix(in srgb, var(--dl-ink) 84%, #FFFFFF);
        color: var(--dl-surface);
    }
}

.vocab-today-btn:active {
    background: color-mix(in srgb, var(--dl-ink) 92%, #FFFFFF);
}

.vocab-today-btn[hidden] { display: none; }

/* 「今天做完」态的次级链接:纯文字,墨色次级,不与实心按钮同时出现。
   悬停按 §18.6.4 只上背景(原来是改前景色 + 下划线) */
.vocab-today-more {
    margin-left: auto;
    flex: 0 0 auto;
    appearance: none;
    border: none;
    background: transparent;
    height: var(--dl-ctl);
    padding: 0 var(--dl-sp-8);
    border-radius: 8px;
    font-family: var(--dl-font);
    font-size: var(--dl-fs-body);
    color: var(--dl-ink-2);
    cursor: pointer;
}

.vocab-today-more[hidden] { display: none; }

@media (hover: hover) {
    .vocab-today-more:hover { background: var(--dl-hover); }
}

/* 压力刹车态第二行小字(§18.3.2):非刹车态整行不显示,不出现任何欠债数字 */
.vocab-today-brake {
    margin: var(--dl-sp-8) 0 0;
    font-size: var(--dl-fs-caption);
    color: var(--dl-ink-3);
}

.vocab-today-brake[hidden] { display: none; }

/* 进度条(§18.6.5):4px 高,--dl-ink 填充。分母 = 今天的计划量,不是队列总长。 */
.vocab-today-progress {
    display: flex;
    align-items: center;
    gap: var(--dl-sp-12);
    margin-top: var(--dl-sp-12);
}

.vocab-today-progress[hidden] { display: none; }

.vocab-today-bar {
    flex: 1 1 auto;
    height: 4px;
    border-radius: 2px;
    background: var(--dl-line);
    overflow: hidden;
}

.vocab-today-bar-fill {
    display: block;
    height: 100%;
    border-radius: 2px;
    background: var(--dl-ink);
    transition: width var(--dl-t-state) ease;
}

.vocab-today-progress-text {
    flex: 0 0 auto;
    font-size: var(--dl-fs-caption);
    color: var(--dl-ink-3);
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

/* ── 单词本切换行(§4.3) ───────────────────────────────────────────── */

.vocab-books {
    display: flex;
    align-items: center;
    gap: var(--dl-sp-12);
    /* 原 margin-top 12 拆成 margin 4 + padding 8:吸顶后上下各有 8 的白,视觉总距不变 */
    margin-top: var(--dl-sp-4);
    padding: var(--dl-sp-8) 0;
    min-width: 0;
    /* 列表可以长到几百行,「现在看的是哪一本、按什么排、掌握多少」不该随滚动消失 */
    position: sticky;
    top: var(--vocab-header-h);
    z-index: 6;
    /* 页面底改灰后,这条切换行留在灰底上(不做成面板),吸顶背景须与页底同色,
       否则滚动时露出白边(§18.6.1 连带必改) */
    background: var(--dl-surface-2);
}

.vocab-books[hidden] { display: none; }

.vocab-books-chips {
    display: flex;
    align-items: center;
    gap: 6px;
    min-width: 0;
    overflow-x: auto;
    scrollbar-width: none;
    /* 「负外边距 + 等量内边距」:chip 的位置与右侧间距一个像素不变(负边距正好抵掉内边距),
       但横滚盒四周留出 4 —— chip 的焦点环向外 4px,原来的 2px 留白会把它裁掉一半 */
    padding: 4px;
    margin: -4px;
}

.vocab-books-chips::-webkit-scrollbar { display: none; }

.vocab-books-right {
    display: flex;
    align-items: center;
    gap: var(--dl-sp-12);
    margin-left: auto;
    flex: 0 0 auto;
}

/* chip = 外壳(画底色圆角)+ 内部主体按钮(+ 选中态的 ⋯)。
   ⋯ 必须落在同一块圆角底色里,所以它不能是 chip 的兄弟节点;
   而 <button> 里不许再套 <button>,故外壳降级成 div。 */
.vocab-chip {
    height: 30px;
    display: inline-flex;
    align-items: center;
    border-radius: var(--dl-r-pill);
    color: var(--dl-ink-2);
    white-space: nowrap;
    flex: 0 0 auto;
}

/* 刚建出来的那一本淡入一次(§6.5)。只在这一次重绘时挂上,不参与后续任何重绘 */
@keyframes vocabChipIn { from { opacity: 0; } to { opacity: 1; } }
.vocab-chip.is-fresh { animation: vocabChipIn var(--dl-t-state) ease both; }

.vocab-chip-main {
    appearance: none;
    border: none;
    background: transparent;
    height: 100%;
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 0 12px;
    border-radius: inherit;
    font-family: var(--dl-font);
    font-size: var(--dl-fs-body);
    color: inherit;
    white-space: nowrap;
    cursor: pointer;
}

/* 选中 = 该本颜色 8% 淡底 + 同色 1px 实色描边 + 墨色文字。永不用竖条。
   描边是页面底色改灰(§18.6.1)后补的:8% 淡底原来靠白底衬出来,落到灰底上区分度掉了一档。
   `inset 0 0 0 1px` 是整圈发丝环、不是文件头禁止的 `inset Npx 0 0`(左侧色条),
   也不占布局盒。「全部」chip 没有本色(不带 .vocab-cN),退到中性 --dl-line,零新颜色。 */
.vocab-chip.is-on {
    background: var(--wb-t);
    box-shadow: inset 0 0 0 1px var(--wb, var(--dl-line));
    color: var(--dl-ink);
}

/* 「全部」没有本色,原来借页面白底的 --dl-surface-2 当淡底;页面底改灰后它与底同色,
   选中态直接看不见(§18.6.1 连带必改)。改成白面板色 —— 与分段控件的选中 pill 同一套
   「灰底上浮一块白」,零新颜色。 */
.vocab-chip--all.is-on { background: var(--dl-surface); }

/* §18.6.4 全站规则:悬停只动背景,前景色一律不动。
   只给未选中的 chip 上底色 —— 选中的那颗已经有本色淡底 + 描边,再叠一层灰会把它的本色搅浑;
   而且旧行为下选中 chip 的文字本就是 --dl-ink,悬停从来也没有可见变化,不算功能回退。 */
@media (hover: hover) {
    .vocab-chip:not(.is-on):hover { background: var(--dl-hover); }
}

.vocab-chip-n {
    color: var(--dl-ink-3);
    font-variant-numeric: tabular-nums;
}

.vocab-chip.is-on .vocab-chip-n { color: var(--dl-ink-2); }

.vocab-dot {
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: var(--wb);
    flex: 0 0 auto;
}

/* §4.3:选中态 chip 右侧多一个 ⋯——它是 chip 的一部分,紧贴计数、共用同一块底色,
   chip 因此比未选中时宽一截(主体右内边距让到 6,加 ⋯ 20 + 右侧 6)。 */
.vocab-chip-main:not(:only-child) { padding-right: 6px; }

.vocab-chip-more {
    appearance: none;
    border: none;
    background: transparent;
    width: 20px;
    height: 100%;
    margin-right: 6px;
    padding: 0;
    border-radius: var(--dl-r-item);
    font-size: var(--dl-fs-caption);
    line-height: 1;
    color: var(--dl-ink-3);
    cursor: pointer;
    flex: 0 0 auto;
}

/* §18.6.4:只动背景 */
@media (hover: hover) {
    .vocab-chip-more:hover { background: var(--dl-hover); }
}

.vocab-chip-add {
    appearance: none;
    border: none;
    background: transparent;
    width: 26px;
    height: 26px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border-radius: 8px;
    color: var(--dl-ink-3);
    cursor: pointer;
    padding: 0;
    flex: 0 0 auto;
}

.vocab-chip-add svg { width: var(--dl-icon); height: var(--dl-icon); }

/* 悬停底色原为 --dl-surface-2,与灰页底同色 = 毫无反馈;--dl-hover 是半透明叠加,
   落在灰底上就是更深一档的灰(§18.6.1 连带必改,零新颜色)。前景色按 §18.6.4 不动。 */
@media (hover: hover) {
    .vocab-chip-add:hover { background: var(--dl-hover); }
}

/* ── 分段控件 ─────────────────────────────────────────────────────── */

/* 槽底 --dl-surface-2 在灰页底上与底同色,整个槽的外框消失、只剩选中的白 pill 悬空
   (§18.6.1 连带必改)。补一圈 --dl-line 发丝内描边把槽找回来:不占布局盒、
   在白底(资源库层)与灰底(单词本切换行)上都成立,零新颜色。 */
.vocab-seg {
    display: inline-flex;
    align-items: center;
    height: var(--dl-ctl);
    padding: 3px;
    box-sizing: border-box;
    background: var(--dl-surface-2);
    box-shadow: inset 0 0 0 1px var(--dl-line);
    border-radius: 8px;
    gap: 2px;
    flex: 0 0 auto;
}

.vocab-seg-btn {
    appearance: none;
    border: none;
    background: transparent;
    height: 30px;
    padding: 0 14px;
    border-radius: 6px;
    font-family: var(--dl-font);
    font-size: var(--dl-fs-body);
    color: var(--dl-ink-2);
    cursor: pointer;
    transition: none;
    white-space: nowrap;
}

.vocab-seg-btn[aria-pressed="true"] {
    background: var(--dl-surface);
    color: var(--dl-ink);
    box-shadow: var(--dl-sh-1);
}

/* §18.6.4:只动背景。选中的那格是白 pill,再叠半透明灰会让底下的槽色透出来,所以排除它;
   旧行为下它的文字本就是 --dl-ink,悬停也没有可见变化。 */
@media (hover: hover) {
    .vocab-seg-btn:not([aria-pressed="true"]):hover { background: var(--dl-hover); }
}

.vocab-volume {
    height: var(--dl-ctl);
    box-sizing: border-box;
    padding: 0 8px;
    max-width: 220px;
    border: 1px solid var(--dl-line);
    border-radius: 8px;
    background: var(--dl-surface);
    color: var(--dl-ink);
    font-family: var(--dl-font);
    font-size: var(--dl-fs-body);
    cursor: pointer;
    flex: 0 0 auto;
}

.vocab-volume[hidden] { display: none; }

.vocab-count {
    font-size: var(--dl-fs-caption);
    color: var(--dl-ink-3);
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

/* ── 双栏骨架 ─────────────────────────────────────────────────────── */

.vocab-body {
    display: grid;
    grid-template-columns: 420px minmax(0, 1fr);
    /* 两列之间 = 面板间距(§18.6.1) */
    gap: var(--dl-sp-24);
    margin-top: var(--dl-sp-24);
    align-items: start;
}

.vocab-body[hidden] { display: none; }

/* 左列 = 白面板 + 它下面那条留在灰底上的入口条。栅格列只认这一个子项,
   面板与入口条的层级关系才不会被 grid 自动排布拆到两行去。 */
.vocab-list-side { min-width: 0; }

.vocab-list-col {
    min-width: 0;
    /* 白面板浮在灰底上(§18.6.1):圆角 16 + 发丝环 + 柔投影 + 16 内边距 */
    background: var(--dl-surface);
    border-radius: var(--dl-r-panel);
    box-shadow: var(--dl-sh-1);
    padding: var(--dl-sp-16);
    /* 反馈浮层在右下角:列表底部留位(叠加面板内边距) */
    padding-bottom: 80px;
}

/* ── 列表 ─────────────────────────────────────────────────────────── */

.vocab-list,
.vocab-skeleton {
    list-style: none;
    margin: 0;
    padding: 0;
}

.vocab-skeleton li {
    height: 56px;
    margin-bottom: 2px;
    border-radius: var(--dl-r-item-lg);
    background: var(--dl-surface-2);
}

.vocab-skeleton[hidden] { display: none; }

.vocab-group {
    position: sticky;
    top: var(--vocab-header-h);
    z-index: 2;
    padding: 16px 12px 6px;
    font-size: var(--dl-fs-caption);
    font-weight: 600;
    line-height: var(--dl-lh-caption);
    color: var(--dl-ink-3);
    background: var(--dl-surface);
}

.vocab-row {
    position: relative;
    padding: 10px 12px;
    border-radius: var(--dl-r-item-lg);
    cursor: pointer;
}

@media (hover: hover) {
    .vocab-row:hover { background: var(--dl-surface-2); }
}

/* 选中态 = 底色 + 词头字重(禁色条) */
.vocab-row.is-selected { background: var(--dl-surface-2); }
.vocab-row.is-selected .vocab-row-w { font-weight: 600; }

/* 已掌握(mastery_level ≥ 3):整体降一档,不加任何徽标/圆点/对勾 */
.vocab-row.is-mastered .vocab-row-w,
.vocab-row.is-mastered .vocab-row-g { color: var(--dl-ink-2); }

.vocab-row-main {
    appearance: none;
    border: none;
    background: transparent;
    padding: 0;
    margin: 0;
    width: 100%;
    display: block;
    text-align: left;
    font: inherit;
    color: inherit;
    cursor: pointer;
}

.vocab-row-top {
    display: flex;
    align-items: baseline;
    /* 右端 28 的 ☆ 恒占位,收藏态切换时次数不位移 */
    padding-right: 32px;
    min-width: 0;
}

.vocab-row-w {
    font-family: var(--dl-font-serif);
    font-size: var(--dl-fs-headword);
    font-weight: 500;
    line-height: var(--dl-lh-headword);
    color: var(--dl-ink);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.vocab-row-ph {
    font-family: var(--dl-font-serif);
    font-size: var(--dl-fs-caption);
    font-style: italic;
    color: var(--dl-ink-3);
    margin-left: var(--dl-sp-8);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.vocab-row-n {
    margin-left: auto;
    padding-left: var(--dl-sp-8);
    font-size: var(--dl-fs-caption);
    color: var(--dl-ink-3);
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
    flex: 0 0 auto;
}

.vocab-row-g {
    margin-top: 2px;
    font-size: var(--dl-fs-body);
    line-height: var(--dl-lh-body);
    color: var(--dl-ink-2);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* 行的第三行 = 出处(公理一)。只有进度段的「不熟悉的词」给 origin,其余两处列表不渲染它。 */
.vocab-row-src {
    margin-top: 2px;
    font-size: var(--dl-fs-micro);
    line-height: var(--dl-lh-micro);
    color: var(--dl-ink-3);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.vocab-pos {
    font-size: var(--dl-fs-caption);
    font-style: italic;
    color: var(--dl-ink-3);
    margin-right: 4px;
}

.vocab-star {
    appearance: none;
    border: none;
    background: transparent;
    position: absolute;
    top: 10px;
    right: 12px;
    width: var(--dl-ctl-sm);
    height: var(--dl-ctl-sm);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border-radius: 8px;
    color: var(--dl-ink-3);
    cursor: pointer;
    padding: 0;
    opacity: 0;
}

.vocab-star svg {
    width: var(--dl-icon);
    height: var(--dl-icon);
    display: block;
}

.vocab-row:hover .vocab-star,
.vocab-row.is-selected .vocab-star,
.vocab-star:focus-visible,
.vocab-star.is-on { opacity: 1; }

/* 收藏是「状态」,不是「选中」也不是「下一步」——按设计语言 §2 不占用强调蓝。
   墨色实心 ↔ 灰色空心 的对比已经够,且与全页唯一实心按钮(墨色)同族。 */
.vocab-star.is-on { color: var(--dl-ink); }
.vocab-star.is-on svg { fill: var(--dl-ink); }

/* 「我的」态:每个词按定义都已收藏,恒亮的实心星既不传达信息、又在列表右侧连成一竖排。
   这里的星只有「移除」一个语义,故只在悬停/键盘聚焦时露面(资源库层里星有信息量,不动)。 */
#vocab-list .vocab-star.is-on { opacity: 0; }

#vocab-list .vocab-row:hover .vocab-star,
#vocab-list .vocab-star:focus-visible { opacity: 1; }

@media (hover: hover) {
    .vocab-star:hover { background: var(--dl-surface-2); }
}

/* 未登录点 ☆:☆ 旁多出一行文字链,不弹模态 */
.vocab-login-hint {
    display: block;
    margin-top: 4px;
    font-size: var(--dl-fs-caption);
    color: var(--dl-accent);
    text-decoration: none;
}

.vocab-sentinel { height: 1px; }

.vocab-list-state {
    padding: var(--dl-sp-24) 12px;
    font-size: var(--dl-fs-body);
    color: var(--dl-ink-3);
}

/* 筛空了的一行(「还没有长期记忆的词」§14.6 第 4 条):次要一档,不占加载失败那么重的字号。
   12px 而不是规格上写的 13 —— 单词子系统的字号阶梯只有 11/12/14/15/16/20/28/36 八档。 */
.vocab-list-state--caption {
    font-size: var(--dl-fs-caption);
    line-height: var(--dl-lh-caption);
}

/* 记忆阶段筛选 chip(§14.6 第 4 条):从进度页两个入口进来才出现的一枚可移除标签。
   本体就是全站的次钮小号(.btn.btn-secondary.btn-sm,28 高),这里只管它在列表上方的位置。 */
.vocab-stage-filter {
    display: flex;
    padding: 0 12px var(--dl-sp-12);
}

.vocab-stage-filter[hidden] { display: none; }

.vocab-stage-chip { gap: var(--dl-sp-8); }

/* × 是文字(§14.6 第 4 条),弱一档墨色:它是这枚 chip 的动作,不该比标签本身还响 */
.vocab-stage-chip-x {
    color: var(--dl-ink-3);
    line-height: 1;
}

@media (hover: hover) {
    .vocab-stage-chip:hover .vocab-stage-chip-x { color: var(--dl-ink); }
}

/* 真题词汇表入口(§5.3 入口不变,形态改自 §12.1-1):列表最后一行的去处链接,
   不再 sticky 吸底 —— 吸底时它压在列表中间,读起来像「我的词」下面又接了一份全表。
   现在它跟着列表末行走,滚到底才出现,一屏里永远只有一份列表。
   12/40 + --dl-ink-3:与行内次要文字同一档,左内边距对齐词行(.vocab-row 的 12)。 */
.vocab-lib-entry {
    appearance: none;
    border: none;
    background: none;
    display: block;
    width: 100%;
    height: 40px;
    line-height: 40px;
    padding: 0 12px;
    text-align: left;
    font-family: var(--dl-font);
    font-size: var(--dl-fs-caption);
    color: var(--dl-ink-3);
    cursor: pointer;
}

.vocab-lib-entry[hidden] { display: none; }

/* 面板白底上的一行链接:悬停只提一档墨色(零新颜色),不铺底色 —— 铺底色会把它读回按钮 */
@media (hover: hover) {
    .vocab-lib-entry:hover { color: var(--dl-ink-2); }
}

/* ── 空态(§4.8) ──────────────────────────────────────────────────── */

/* 空态是整页唯一的内容。96px 定值把它钉在上四分之一、下半屏全空;
   改成视口比例,落在略高于视觉中心的位置(光学居中)。 */
.vocab-empty {
    margin: 0 auto;
    padding: 26vh 24px 12vh;
    max-width: 480px;
    text-align: center;
}

.vocab-empty[hidden] { display: none; }

.vocab-empty-title {
    font-size: var(--dl-fs-headword);
    font-weight: 600;
    color: var(--dl-ink);
    margin: 0 0 var(--dl-sp-16);
}

.vocab-empty-sub {
    font-size: var(--dl-fs-body);
    line-height: var(--dl-lh-body);
    color: var(--dl-ink-2);
    margin: 0;
}

.vocab-empty-btn {
    appearance: none;
    border: none;
    display: inline-flex;
    align-items: center;
    height: var(--dl-ctl);
    margin-top: var(--dl-sp-24);
    padding: 0 var(--dl-sp-20);
    border-radius: 8px;
    background: var(--dl-ink);
    color: var(--dl-surface);
    font-family: var(--dl-font);
    font-size: var(--dl-fs-body);
    font-weight: 500;
    text-decoration: none;
    transition: background-color var(--dl-t-state) ease;
    cursor: pointer;
}

@media (hover: hover) {
    .vocab-empty-btn:hover {
        background: color-mix(in srgb, var(--dl-ink) 84%, #FFFFFF);
        color: var(--dl-surface);
    }
}

.vocab-empty-btn:active {
    background: color-mix(in srgb, var(--dl-ink) 92%, #FFFFFF);
}

/* 未登录时「打开真题词汇表」是次要动作,让位给「登录」 */
.vocab-empty-btn--ghost {
    background: transparent;
    color: var(--dl-ink-2);
    box-shadow: inset 0 0 0 1px var(--dl-line);
    margin-top: var(--dl-sp-12);
}

.vocab-empty-note {
    margin: var(--dl-sp-12) 0 0;
    font-size: var(--dl-fs-caption);
    color: var(--dl-ink-3);
}

/* ── 详情面板 ─────────────────────────────────────────────────────── */

/* §18.17 四:这一层**只当白面板**——保住 --dl-sh-1,不再滚动。
   mask 按 border-box 裁剪、会把画在盒外的阴影一起裁掉,所以滚动 + 底部渐隐全部下放到内层。 */
.vocab-detail-col {
    position: sticky;
    /* 让开吸顶的单词本切换行:只写 header 高会让词头躲到那条白底后面 */
    top: calc(var(--vocab-header-h) + var(--vocab-books-h) + 8px);
    min-width: 0;
    /* 白面板浮在灰底上(§18.6.1) */
    background: var(--dl-surface);
    border-radius: var(--dl-r-panel);
    box-shadow: var(--dl-sh-1);
    padding: var(--dl-sp-16);
}

/* 面板已提供 16 内边距,内层 .vocab-detail 不再另加(手机层/资源库层各自的 padding 保留)。
   max-height 从面板搬到这里,再减掉面板上下各 16 的内边距,面板总高与原来一模一样;
   滚到底时末行被硬切成半个字读起来像「坏了」,底部 20px 渐隐说明「还有下文」(§17.5)。 */
.vocab-detail-col .vocab-detail {
    /* 「负外边距 + 等量内边距」把滚动盒向左右各撑开 8:内容左右位置一个像素不动,
       但滚动盒不再贴着内容裁剪 —— 例句块的焦点环向外 4px,否则会被整条裁掉 */
    padding: 0 8px;
    margin: 0 -8px;
    max-height: calc(100vh - var(--vocab-header-h) - var(--vocab-books-h) - 8px - 16px - var(--dl-sp-32));
    overflow: auto;
    scrollbar-gutter: stable;
}

.vocab-detail { padding: 8px 8px 32px; }

.vocab-d-head {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: var(--dl-sp-8);
}

.vocab-d-w {
    font-family: var(--dl-font-serif);
    font-size: var(--dl-fs-word-md);
    font-weight: 600;
    line-height: var(--dl-lh-word-md);
    color: var(--dl-ink);
    margin: 0;
    word-break: break-word;
}

.vocab-d-star {
    appearance: none;
    border: none;
    background: transparent;
    width: var(--dl-ctl);
    height: var(--dl-ctl);
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border-radius: 8px;
    color: var(--dl-ink-3);
    cursor: pointer;
    padding: 0;
}

.vocab-d-star svg {
    width: var(--dl-icon-lg);
    height: var(--dl-icon-lg);
    display: block;
}

.vocab-d-star.is-on { color: var(--dl-ink); }
.vocab-d-star.is-on svg { fill: var(--dl-ink); }

@media (hover: hover) {
    .vocab-d-star:hover { background: var(--dl-surface-2); }
}

.vocab-d-ph {
    appearance: none;
    border: none;
    background: transparent;
    padding: 0;
    margin: 4px 0 0;
    display: flex;
    align-items: center;
    gap: 6px;
    font-family: var(--dl-font-serif);
    font-size: var(--dl-fs-translation);
    font-style: italic;
    color: var(--dl-ink-2);
    cursor: pointer;
    text-align: left;
}

.vocab-d-ph svg {
    width: var(--dl-icon);
    height: var(--dl-icon);
    color: var(--dl-ink-3);
    flex: 0 0 auto;
}

.vocab-d-meta {
    margin-top: 4px;
    font-size: var(--dl-fs-caption);
    color: var(--dl-ink-3);
    font-variant-numeric: tabular-nums;
}

.vocab-d-sec + .vocab-d-sec { border-top: 1px solid var(--dl-line); }

.vocab-d-sec-title {
    font-size: var(--dl-fs-caption);
    font-weight: 600;
    line-height: var(--dl-lh-caption);
    color: var(--dl-ink-3);
    margin: 20px 0 8px;
}

/* 释义与例句两块没有分区标题(§9),自己补上距 */
.vocab-d-sec--senses { margin-top: var(--dl-sp-16); }
.vocab-d-sec--ex { padding-top: var(--dl-sp-16); }

/* 释义 */
.vocab-d-sense {
    display: grid;
    grid-template-columns: 36px 1fr auto;
    align-items: baseline;
    gap: 0 var(--dl-sp-8);
    padding: 4px 0;
}

.vocab-d-sense-pos {
    font-size: var(--dl-fs-caption);
    font-style: italic;
    color: var(--dl-ink-3);
}

/* 行高走令牌:主场页原先硬编码 22、复习卡用 --dl-lh-translation,两页不是一把尺(§18.17 三) */
.vocab-d-sense-g {
    font-size: var(--dl-fs-translation);
    line-height: var(--dl-lh-translation);
    font-weight: 400;
    color: var(--dl-ink-2);
}

.vocab-d-sense-g.is-strong {
    font-weight: 600;
    color: var(--dl-ink);
}

.vocab-d-sense-n {
    font-size: var(--dl-fs-caption);
    color: var(--dl-ink-3);
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

.vocab-d-empty {
    font-size: var(--dl-fs-body);
    color: var(--dl-ink-3);
    margin: 0;
}

/* 词形:分区标题与内容同一行 */
.vocab-d-sec--forms {
    display: flex;
    align-items: baseline;
    gap: var(--dl-sp-8);
    padding-top: 20px;
}

.vocab-d-sec--forms .vocab-d-sec-title {
    margin: 0;
    flex: 0 0 auto;
}

.vocab-d-forms-body {
    font-size: var(--dl-fs-caption);
    line-height: var(--dl-lh-body);
    color: var(--dl-ink-2);
    min-width: 0;
}

/* 一项 = 标签 + 形态,整体不可断行;换行只发生在「·」分隔符处 */
.vocab-d-form {
    display: inline-block;
    white-space: nowrap;
}

.vocab-d-form-label { color: var(--dl-ink-3); }

/* 固定搭配 */
.vocab-d-phrase {
    display: grid;
    grid-template-columns: 1fr auto;
    align-items: baseline;
    gap: 0 var(--dl-sp-8);
    padding: 4px 0;
}

.vocab-d-phrase-w {
    font-size: var(--dl-fs-translation);
    line-height: var(--dl-lh-translation);
    color: var(--dl-ink);
}

.vocab-d-phrase-w.is-strong { font-weight: 600; }

/* 加粗只落在短语原形上,释义跟着 600 会把整行读成一块 */
.vocab-d-phrase-g {
    font-size: var(--dl-fs-body);
    font-weight: 400;
    color: var(--dl-ink-2);
    margin-left: var(--dl-sp-8);
}

.vocab-d-phrase-n {
    font-size: var(--dl-fs-caption);
    color: var(--dl-ink-3);
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

/* 「负外边距 + 等量内边距」:文字位置一个像素不动,但悬停底色与焦点环有 8 的落脚处 */
.vocab-d-more {
    appearance: none;
    border: none;
    background: transparent;
    padding: 0 8px;
    margin-left: -8px;
    height: 28px;
    border-radius: var(--dl-r-item);
    font-family: var(--dl-font);
    font-size: var(--dl-fs-body);
    color: var(--dl-ink-2);
    cursor: pointer;
}

/* §18.6.4:只动背景(原来是改前景色 + 下划线) */
@media (hover: hover) {
    .vocab-d-more:hover { background: var(--dl-hover); }
}

/* 真题例句(§4.7):整块 tabIndex=0 可聚焦(键盘走到这里才浮出两个动作)。
   焦点样式见文件末尾「焦点环」一节,这里只给它圆角(环按元素自己的圆角画)。 */
.vocab-d-ex {
    border-radius: var(--dl-r-item-lg);
}

/* 每条例句是 2~4 行的中英混排块;12 小于行距的 1.5 倍,三条会粘成一片。 */
.vocab-d-ex + .vocab-d-ex { margin-top: var(--dl-sp-20); }

.vocab-d-ex-src {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--dl-sp-8);
    /* 动作从两个变三个(看上下文 / 在试卷中打开 / 问华生,§18.8.2)后，窄详情列与手机上
       出处 + 动作可能一行放不下。放不下时动作整条落到第二行(gap 已给 8 的行距)，
       宁可换行也不截掉出处 —— 公理一要求词永远带着它的出处。放得下时一行,几何不变。 */
    flex-wrap: wrap;
    font-size: var(--dl-fs-caption);
    color: var(--dl-ink-3);
}

/* 两个动作:悬停/键盘聚焦才出现,用 opacity 不占位(display 会让整块跳动) */
.vocab-d-ex-acts {
    display: flex;
    align-items: baseline;
    gap: var(--dl-sp-12);
    flex: 0 0 auto;
    opacity: 0;
    transition: opacity var(--dl-t-hover) linear;
}

.vocab-d-ex:hover .vocab-d-ex-acts,
.vocab-d-ex:focus .vocab-d-ex-acts,
.vocab-d-ex:focus-within .vocab-d-ex-acts { opacity: 1; }

/* 悬停才浮出的次要动作不该是全页最跳的颜色:墨色次级。
   「负外边距 + 等量内边距」:文字与动作之间的间距一个像素不动,但悬停底色与焦点环有落脚处。
   显式写 line-height:「在试卷中打开」是 <a>(新标签页)、另两个是 <button>,
   button 的 UA 行高是 normal 而 a 继承容器行高,不钉死这一条两者盒高就不等、把出处行撑高。
   下划线与链接色不必在这里关:style.css:897 的全站 `a` 已经是 color:inherit + 无下划线。 */
.vocab-d-ex-act {
    appearance: none;
    border: none;
    background: transparent;
    padding: 2px 6px;
    margin: -2px -6px;
    border-radius: var(--dl-r-item);
    font-family: var(--dl-font);
    font-size: var(--dl-fs-caption);
    line-height: var(--dl-lh-caption);
    color: var(--dl-ink-2);
    white-space: nowrap;
    cursor: pointer;
}

/* §18.6.4:只动背景(原来是改前景色 + 下划线) */
@media (hover: hover) {
    .vocab-d-ex-act:hover { background: var(--dl-hover); }
}

.vocab-d-ex-text {
    margin-top: 4px;
    /* 例句英文改 serif(§18.6.3):例句即真题原文,与 PDF 及复习页统一到 serif */
    font-family: var(--dl-font-serif);
    font-size: var(--dl-fs-body);
    /* 八档表「正文 14 / 20」(§18.6.2):原 1.6 = 22.4px,不在尺上 */
    line-height: var(--dl-lh-body);
    color: var(--dl-ink);
}

/* 例句里目标词:serif 600(沿用现值);字体已由 .vocab-d-ex-text 继承 serif */
.vocab-d-ex-text b { font-weight: 600; }

.vocab-d-ex-tr {
    margin-top: 2px;
    /* 中译一律 sans(§18.6.3):Times New Roman 无中文字形,继承会 fallback 到雅黑而基线不齐 */
    font-family: var(--dl-font);
    font-size: var(--dl-fs-body);
    line-height: var(--dl-lh-body);
    color: var(--dl-ink-2);
}

/* 就地上下文(§18.8.2 一):前后邻句随例句 payload 一起下发,展开只切 hidden、不发请求。
   邻句复用 .vocab-d-ex-text / .vocab-d-ex-tr 的字体、行高**与常态墨色**——用户点开上下文
   就是为了读这两句,压暗等于削弱他此刻要读的东西;标记目标句一处就够,不与底色叠加。
   收起态是 [hidden] → display:none,这里的外边距一并不生效,所以收起时这两块不多占任何留白。 */
.vocab-d-ex-ctx { margin: var(--dl-sp-8) 0; }

/* 目标句 = 「就是这一句」。这一处底色用 --dl-hover 而不是 --dl-tint-sentence（§15.1.3-4，
   用户点名「单词页例句底色改灰，其他地方保持不变」）—— 这是一色一义的一处记名例外：
   在这一处 --dl-hover 的含义是「例句目标句底色」。
   阅读器的整句高亮(style.css:1685)与复习卡目标句(review.html:300-304 .rv-context-target)
   仍是 --dl-tint-sentence，不动。
   收起态同样带底色(定案:一直带) —— 展开/收起不产生颜色跳变,合公理三。
   底色落在**行内 span** 而不是那个 div:行内元素的上下内边距不撑行高,所以「留出呼吸」与
   「收起态几何一个像素不动」这两件事同时成立,数值也与复习卡逐字相同。 */
.vocab-d-ex-mark {
    background: var(--dl-hover);
    border-radius: var(--dl-r-item);
    padding: 1px 3px;
}

/* 展开后鼠标移开,「收起」不该跟着隐掉(动作条平时靠 opacity 藏)。只动 opacity,不改几何。 */
.vocab-d-ex.is-ctx-open .vocab-d-ex-acts { opacity: 1; }

/* ── 手机全屏详情层 ───────────────────────────────────────────────── */

.vocab-sheet {
    position: fixed;
    inset: 0;
    background: var(--dl-surface);
    z-index: 1250;
    display: flex;
    flex-direction: column;
}

.vocab-sheet[hidden] { display: none; }

.vocab-sheet-bar {
    height: 48px;
    flex: 0 0 auto;
    display: flex;
    align-items: center;
    gap: var(--dl-sp-8);
    padding: 0 var(--dl-sp-8);
    border-bottom: 1px solid var(--dl-line);
}

.vocab-sheet-back {
    appearance: none;
    border: none;
    background: transparent;
    height: var(--dl-ctl);
    padding: 0 8px;
    border-radius: 8px;
    font-family: var(--dl-font);
    font-size: var(--dl-fs-body);
    color: var(--dl-ink-2);
    cursor: pointer;
}

.vocab-sheet-word {
    font-family: var(--dl-font-serif);
    font-size: var(--dl-fs-headword);
    font-weight: 500;
    color: var(--dl-ink);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.vocab-sheet-body {
    flex: 1 1 auto;
    overflow: auto;
    padding: 8px 8px 32px;
    -webkit-overflow-scrolling: touch;
}

/* ── 资源库层(§5) ────────────────────────────────────────────────── */

/* html 恒开 overflow-y: scroll(style.css),固定定位的包含块因此比视口窄一条滚动条
   (实测 1440 视口 → 1430)。那一条里遮罩盖不到、底层页面原色透出,面板的
   calc((100vw - …) / 2) 居中也随之偏 5px。所以层根显式取 100vw,与面板算式同一把尺。
   固定定位盒不计入文档可滚动溢出,不会因此多出横向滚动条。 */
.vocab-lib {
    position: fixed;
    inset: 0;
    width: 100vw;
    z-index: 1200;
}

.vocab-lib[hidden] { display: none; }

.vocab-lib-mask {
    position: absolute;
    inset: 0;
    background: rgba(16, 20, 26, .32);
    opacity: 0;
    transition: opacity 140ms var(--dl-ease-out);
}

.vocab-lib.is-open .vocab-lib-mask { opacity: 1; }

.vocab-lib-panel {
    position: absolute;
    left: 50%;
    top: 50%;
    width: min(1200px, 92vw);
    height: min(860px, 88vh);
    box-sizing: border-box;
    display: flex;
    flex-direction: column;
    background: var(--dl-surface);
    border-radius: var(--dl-r-panel);
    box-shadow: var(--dl-sh-menu);
    opacity: 0;
    transform: translate(-50%, -50%) translateY(8px);
    transition: opacity 140ms var(--dl-ease-out), transform 140ms var(--dl-ease-out);
    overflow: hidden;
}

.vocab-lib.is-open .vocab-lib-panel {
    opacity: 1;
    transform: translate(-50%, -50%);
}

/* 资源库层面板在开层时接收初始焦点(tabindex="-1",永不进 Tab 序)。
   它是对话框容器不是控件,本身已有可见边界 + aria-label,不画环;
   这是全页唯一保留 outline:none 而不给 --dl-focus-ring 替代的地方,原因就是这一条。 */
.vocab-lib-panel:focus { outline: none; }

.vocab-lib-head {
    display: flex;
    align-items: flex-start;
    gap: var(--dl-sp-16);
    padding: var(--dl-sp-20) var(--dl-sp-20) 0;
    flex: 0 0 auto;
}

.vocab-lib-heading { min-width: 0; margin-right: auto; }

.vocab-lib-title {
    font-size: var(--dl-fs-section);
    font-weight: 600;
    line-height: var(--dl-lh-section);
    color: var(--dl-ink);
    margin: 0;
}

/* 资源库的价值陈述,保留(§5.2) */
.vocab-lib-sub {
    margin: 2px 0 0;
    font-size: var(--dl-fs-caption);
    color: var(--dl-ink-3);
}

.vocab-search-wrap--lib { width: 240px; }

.vocab-lib-close { flex: 0 0 auto; cursor: pointer; }

.vocab-lib-tabs {
    display: flex;
    align-items: center;
    gap: var(--dl-sp-12);
    padding: var(--dl-sp-16) var(--dl-sp-20) var(--dl-sp-12);
    flex: 0 0 auto;
}

.vocab-lib-target {
    margin-left: auto;
    display: flex;
    align-items: center;
    gap: 6px;
    font-size: var(--dl-fs-caption);
    color: var(--dl-ink-3);
    white-space: nowrap;
}

.vocab-lib-target-still,
.vocab-lib-target-btn {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    color: var(--dl-ink-2);
}

.vocab-lib-target-btn {
    appearance: none;
    border: none;
    background: transparent;
    height: 28px;
    padding: 0 8px;
    border-radius: 8px;
    font-family: var(--dl-font);
    font-size: var(--dl-fs-caption);
    cursor: pointer;
}

@media (hover: hover) {
    .vocab-lib-target-btn:hover { background: var(--dl-surface-2); }
}

.vocab-caret { color: var(--dl-ink-3); }

.vocab-lib-body {
    flex: 1 1 auto;
    min-height: 0;
    display: grid;
    grid-template-columns: 420px auto minmax(0, 1fr);
    gap: 0 var(--dl-sp-24);
    padding: 0 var(--dl-sp-20) var(--dl-sp-20);
}

.vocab-lib-list-col {
    min-width: 0;
    overflow: auto;
    padding-right: 4px;
}

.vocab-lib-list-col .vocab-group { top: 0; }

.vocab-lib-detail-col {
    min-width: 0;
    overflow: auto;
    padding-right: 4px;
}

.vocab-lib-detail-col .vocab-detail { padding: 0 8px 24px; }

/* A–Z 跳转条:给一层淡底把 26 个字母收成一个控件(原来是散落的字符),
   并与列表首行对齐(原来在整列里垂直居中,和列表错开一大截)。 */
.vocab-lib-letters {
    display: flex;
    flex-direction: column;
    justify-content: flex-start;
    align-self: start;
    gap: 2px;
    padding: 4px 2px;
    border-radius: var(--dl-r-item-lg);
    background: var(--dl-surface-2);
}

.vocab-lib-letters[hidden] { display: none; }

.vocab-letter {
    appearance: none;
    border: none;
    background: transparent;
    width: 20px;
    height: 20px;
    padding: 0;
    border-radius: 4px;
    font-family: var(--dl-font);
    font-size: var(--dl-fs-micro);
    line-height: 1;
    color: var(--dl-ink-2);
    cursor: pointer;
}

.vocab-letter:disabled { color: var(--dl-ink-disabled); cursor: default; }
/* 淡底之上,选中/悬停要比底更亮才看得见 */
.vocab-letter.is-on { color: var(--dl-ink); background: var(--dl-surface); }

@media (hover: hover) {
    .vocab-letter:not(:disabled):hover { background: var(--dl-surface); }
}

/* 滚到底时末行被容器硬切成半个字,读起来像「坏了」而不是「还有下文」。
   底部 20px 渐隐;内容不足以滚动时渐隐落在空白上,看不见。
   资源库层这两列不是白面板(叠层里不靠阴影浮起),按 §17.5 原样保留;
   主场页详情列的同一效果已按 §18.17 四 下放到内层 .vocab-detail,见上文。 */
.vocab-lib-list-col,
.vocab-lib-detail-col {
    scrollbar-gutter: stable;
}

/* ── 单词本浮层(§4.4;材质由 .dl-mat-edge 提供) ─────────────────── */

.vocab-pop {
    position: fixed;
    z-index: 1500;
    width: 320px;
    box-sizing: border-box;
    padding: var(--dl-sp-16);
    font-family: var(--dl-font);
}

.vocab-pop[hidden] { display: none; }

.vocab-pop--menu {
    width: 180px;
    padding: var(--dl-pad-panel);
}

.vocab-pop--menu .dl-menu__item { cursor: pointer; }

.vocab-pop-title {
    font-size: var(--dl-fs-body);
    font-weight: 600;
    color: var(--dl-ink);
    margin-bottom: var(--dl-sp-12);
}

/* 与 .dl-field 同一组值（§1.3）：边框 --dl-line-pop、圆角 8、高 40、内衬 0 12 */
.vocab-pop-input {
    width: 100%;
    height: 40px;
    box-sizing: border-box;
    padding: 0 12px;
    border: 1px solid var(--dl-line-pop);
    border-radius: 8px;
    background: var(--dl-surface);
    color: var(--dl-ink);
    font-family: var(--dl-font);
    font-size: var(--dl-fs-body);
    line-height: var(--dl-lh-body);
    outline: none;
    transition: border-color var(--dl-t-state) ease;
}

.vocab-pop-input::placeholder {
    color: var(--dl-ink-3);
    font-size: var(--dl-fs-body);
    opacity: 1;
}

.vocab-pop-input:focus {
    border-color: var(--dl-ink);
}

.vocab-pop-colors {
    display: flex;
    gap: var(--dl-sp-12);
    margin-top: var(--dl-sp-16);
}

.vocab-color {
    appearance: none;
    border: none;
    width: 16px;
    height: 16px;
    padding: 0;
    border-radius: 50%;
    background: var(--wb);
    cursor: pointer;
}

/* 选中 = 2px 面色内圈 + 1px 同色外圈 */
.vocab-color.is-on {
    box-shadow: inset 0 0 0 2px var(--dl-surface), 0 0 0 1px var(--wb);
}

.vocab-pop-text {
    margin: 0;
    font-size: var(--dl-fs-body);
    line-height: var(--dl-lh-body);
    color: var(--dl-ink-2);
}

/* ── 新建 / 重命名单词本浮层(§6.5)──────────────────────────────────
   材质、定位、开合、焦点全在浮层基件(.dl-dialog + floating-dialog.js),
   这里只补两件基件不管的:锚定形态的宽度、以及色点的选中环。 */
.vocab-book-dialog {
    /* §1.4 锚定浮层宽 300–360;取 320:5 个色点 + 16 内衬在这个宽里正好居中不挤 */
    width: min(320px, calc(100vw - 32px));
}

.vocab-book-dialog .vocab-pop-colors { margin-top: var(--dl-sp-12); }

/* 选中 = 全站唯一那一种环(§6.5);原来的「面色内圈 + 同色外圈」是本页私有的第二种选中态 */
.vocab-book-dialog .vocab-color.is-on { box-shadow: var(--dl-focus-ring); }

/* 提示行常驻占位 16px（§1.3）：错误出现与消失都不推动下面的按钮行 */
.vocab-pop-error {
    margin: var(--dl-sp-12) 0 0;
    min-height: var(--dl-lh-caption);
    font-size: var(--dl-fs-caption);
    line-height: var(--dl-lh-caption);
    color: var(--dl-err-ink);
}

.vocab-pop-actions {
    display: flex;
    justify-content: flex-end;
    gap: var(--dl-sp-8);
    margin-top: var(--dl-sp-16);
}

.vocab-pop-btn {
    appearance: none;
    border: none;
    background: transparent;
    height: var(--dl-ctl-sm);
    padding: 0 var(--dl-sp-12);
    border-radius: 8px;
    font-family: var(--dl-font);
    font-size: var(--dl-fs-body);
    color: var(--dl-ink-2);
    cursor: pointer;
}

@media (hover: hover) {
    .vocab-pop-btn:hover { background: var(--dl-surface-2); }
}

/* 主钮 = 实底墨钮（§1.2），与全站主钮同一组令牌；次钮仍是文字型 */
.vocab-pop-btn--primary {
    background: var(--btn-primary-bg);
    color: var(--btn-primary-fg);
    font-weight: 500;
    transition: background-color var(--dl-t-state) ease, color var(--dl-t-state) ease;
}

@media (hover: hover) {
    .vocab-pop-btn--primary:hover { background: var(--btn-primary-bg-hover); }
}

.vocab-pop-btn--primary:active { background: var(--btn-primary-bg-active); }

.vocab-pop-btn--primary.is-danger { background: var(--dl-err-ink); color: #FFFFFF; }

@media (hover: hover) {
    .vocab-pop-btn--primary.is-danger:hover {
        background: color-mix(in srgb, var(--dl-err-ink) 88%, #000);
    }
}

.vocab-pop-book { cursor: pointer; }
.vocab-pop-book .dl-menu__label { grid-column: 3; }
.vocab-pop-book .vocab-dot { grid-column: 1; justify-self: center; }

/* ── 焦点环 ───────────────────────────────────────────────────────────
   全页(含手机层 / 资源库层 / 单词本浮层)的键盘焦点只有这一套:
   `--dl-focus-ring`。原先四套并存 —— 令牌环 / 浏览器默认 / 写死 outline:none 无替代 /
   输入框改边框色 —— 现在全部收到这里。
   两条纪律:① 环用 box-shadow 画,按元素自己的 border-radius 走,不占布局盒、不撑动几何;
   ② 只认 :focus-visible,鼠标点击不出环(与浏览器原生行为一致)。
   本节必须留在文件靠后位置:它要盖过 [aria-pressed] / .is-on 一类同权重的状态规则。
   唯一例外 = 对话框容器 .vocab-lib-panel:focus,见那一条的注释。 */

.vocab-tab:focus-visible,
.vocab-search:focus-visible,
.vocab-chip-main:focus-visible,
.vocab-chip-more:focus-visible,
.vocab-chip-add:focus-visible,
.vocab-seg-btn:focus-visible,
.vocab-volume:focus-visible,
.vocab-today-btn:focus-visible,
.vocab-today-more:focus-visible,
.vocab-row-main:focus-visible,
.vocab-prog-group-head:focus-visible,
.vocab-star:focus-visible,
.vocab-lib-entry:focus-visible,
.vocab-empty-btn:focus-visible,
.vocab-d-star:focus-visible,
.vocab-d-ph:focus-visible,
.vocab-d-more:focus-visible,
.vocab-d-ex:focus-visible,
.vocab-d-ex-act:focus-visible,
.vocab-sheet-back:focus-visible,
.vocab-lib-close:focus-visible,
.vocab-lib-target-btn:focus-visible,
.vocab-letter:focus-visible,
.vocab-color:focus-visible,
.vocab-pop-input:focus-visible,
.vocab-pop-btn:focus-visible {
    outline: none;
    box-shadow: var(--dl-focus-ring);
}

/* 三个自身没有圆角、环会画成直角的:补上与邻近控件同族的圆角。
   .vocab-tab 的 2px 只够把环的四角磨掉一点,不改下划线那条 border-bottom 的观感。 */
.vocab-tab:focus-visible { border-radius: 2px; }
.vocab-row-main:focus-visible { border-radius: var(--dl-r-item); }
.vocab-d-ph:focus-visible { border-radius: var(--dl-r-item); }

/* 两个「本来就带 box-shadow 表达状态」的:环要叠在原状态之上,不能把状态挤掉。
   影子按书写顺序从前往后画,所以状态层写在前、环写在后。 */
.vocab-empty-btn--ghost:focus-visible {
    box-shadow: inset 0 0 0 1px var(--dl-line), var(--dl-focus-ring);
}

.vocab-color.is-on:focus-visible {
    box-shadow: inset 0 0 0 2px var(--dl-surface), 0 0 0 1px var(--wb), var(--dl-focus-ring);
}

/* ── 触屏 ─────────────────────────────────────────────────────────── */

/* style.css 在 @media (pointer: coarse) 下把所有 button/select 顶到 48×48(Material
   触摸目标);本页几何由规格定死(控件 36、行内 ☆ 28),两者冲突按规格。
   触摸目标不丢:行内 ☆ 用透明 ::after 把命中区扩到 48×48,视觉一个像素不动。 */
@media (pointer: coarse) {
    .vocab-page button,
    .vocab-page select,
    .vocab-sheet button,
    .vocab-lib button,
    .vocab-lib select,
    .vocab-pop button {
        min-height: 0;
        min-width: 0;
    }

    .vocab-star::after {
        content: '';
        position: absolute;
        inset: -10px;
    }
}

/* ── 断点 ─────────────────────────────────────────────────────────── */

/* ≥1280:列表列 460 */
@media (min-width: 1280px) {
    .vocab-body { grid-template-columns: 460px minmax(0, 1fr); }
    .vocab-lib-body { grid-template-columns: 460px auto minmax(0, 1fr); }
}

/* 769–1023:仍双栏,列表列 340 */
@media (min-width: 769px) and (max-width: 1023px) {
    .vocab-body { grid-template-columns: 340px minmax(0, 1fr); }
    .vocab-lib-body { grid-template-columns: 340px auto minmax(0, 1fr); }
}

/* ≤768:单栏 + 全屏详情;站点顶栏在手机隐藏 → sticky 基准归零 */
@media (max-width: 768px) {
    .vocab-page {
        padding: 0;
        --vocab-header-h: 0px;
    }

    .vocab-head { display: block; }

    /* 分段切换器实际高 34(28 行高 + 4 下内边距 + 2 下划线),触摸目标不够 44;
       上面那条 @media (pointer: coarse) 又把 style.css 的 min-height 归零了,所以补内边距。
       只补上方:下内边距一动,2px 下划线就被推离文字,§18.2.3 的「与文字对齐」当场失效。
       10 + 28 + 4 + 2 = 44。 */
    .vocab-tab { padding-top: 10px; }

    .vocab-search-wrap {
        width: 100%;
        margin-top: var(--dl-sp-12);
    }

    .vocab-suggest { min-width: 0; }

    .vocab-books {
        display: block;
        overflow: hidden;
        /* 窄屏上这一行有两排高,吸顶会吃掉列表的可视高度 */
        position: static;
        padding: 0;
        margin-top: var(--dl-sp-12);
    }

    /* 本切换行横向可滚:不换行、不压叠。
       撤掉桌面那套「负外边距 + 等量内边距」:这里 .vocab-books 是 overflow:hidden 的块盒,
       负边距既撑不出焦点环的位置(照样被裁),又会和下面那行的上边距折叠掉 4px */
    .vocab-books-chips {
        flex-wrap: nowrap;
        padding: 2px 0;
        margin: 0;
    }

    /* 这一行现在只剩排序分段控件(「掌握 N%」已移到今日卡底行),整行让它占满、左对齐 */
    .vocab-books-right {
        margin-left: 0;
        margin-top: var(--dl-sp-8);
        width: 100%;
    }

    .vocab-body { display: block; }

    .vocab-detail-col { display: none; }

    /* 底部标签栏 = 56px + 安全区,列表末行不能被它压住 */
    .vocab-list-col {
        padding-bottom: calc(80px + 56px + env(safe-area-inset-bottom, 0px));
    }

    /* 资源库层的 ☆ 手机上常显:那里的星有信息量(这个词收没收过) */
    #vocab-lib-list .vocab-star { opacity: 1; }

    /* 「我的」列表的 ☆ 手机上不出:每个词按定义都已收藏,一竖排恒亮的蓝星不传达任何信息,
       在 390 宽的屏上尤其扎眼。移除入口交给点进去的全屏详情层那颗星(语义本就是「点击移除」),
       多一次点击可接受——移除是低频动作,这一列蓝点却是每次打开都要看的。 */
    #vocab-list .vocab-star { display: none; }

    /* 星不出了,给它恒占的 32px 也一并收回,次数贴回右边 */
    #vocab-list .vocab-row-top { padding-right: 0; }

    /* 例句两个动作在手机常显 */
    .vocab-d-ex-acts { opacity: 1; }

    .vocab-empty { padding: 18vh 16px 12vh; }

    /* 资源库层在手机 = 全屏单栏 */
    .vocab-lib-panel {
        inset: 0;
        left: 0;
        top: 0;
        width: 100%;
        height: 100%;
        max-height: none;
        border-radius: 0;
        transform: none;
    }

    .vocab-lib.is-open .vocab-lib-panel { transform: none; }

    .vocab-lib-head {
        flex-wrap: wrap;
        padding: var(--dl-sp-12) var(--dl-sp-12) 0;
    }

    .vocab-search-wrap--lib { width: 100%; order: 3; }

    .vocab-lib-tabs {
        flex-wrap: wrap;
        padding: var(--dl-sp-12);
    }

    .vocab-lib-target { margin-left: 0; width: 100%; }

    .vocab-lib-body {
        display: block;
        overflow: auto;
        padding: 0 var(--dl-sp-12) var(--dl-sp-12);
    }

    .vocab-lib-list-col { overflow: visible; }

    .vocab-lib-letters,
    .vocab-lib-detail-col { display: none; }

    .vocab-pop {
        left: 12px !important;
        right: 12px;
        width: auto;
    }
}

/* ≤640:日历格子 12 → 10。手机上 26 列 × 15px 早就超出面板,收到 10 还是会靠
   .vocab-cal-grid 的 1fr 再等比收窄一点 —— 但 10 让「装得下的列数」多出四五列,
   多数用户(窗口不满半年)在手机上拿到的就是正正方方的 10px 格。 */
@media (max-width: 640px) {
    .vocab-cal { --vc-cell: 10px; }
}

/* ── 减弱动效:§8 全部过渡时长归零 ───────────────────────────────── */

@media (prefers-reduced-motion: reduce) {
    .vocab-lib-mask,
    .vocab-lib-panel,
    .vocab-list,
    .vocab-detail {
        transition: none !important;
    }
}
