/* pages-wordlib.css —— 「我的词库」（#/wordlib）的页面样式。
 *
 * ★ 这是**页面层**，排在 theme → layout → components → 各 pages-* 之后：
 *   只补这一屏自己的东西，**不改共享令牌**（theme.css 由 Lead 独占）。
 * ★ 所有类名都带 `wl-` 前缀，和别的页面不会撞。
 * ★ 令牌一律用 theme.css :root 里已有的那几个（--c-* / --t-* / --fs-* / --r-*），
 *   不新造颜色 —— 造了新色，暗色主题一改这里就会变成一块补丁。
 *
 * 布局三块（从上到下）：① 进练习（引擎入口，不是练习界面）
 *                      ② 搜词加入（列表由 core/wordsearch.js 画，这里只摆位置）
 *                      ③ 已加入的词（词 / 中文 / 来源 / 加入时间 + 备注 + 删除）
 */

/* ============================ 页面骨架 ============================ */
.wl-page {
  padding-bottom: 40px;
}

.wl-sec {
  margin: 22px 0 26px;
}

/* ============================ ① 顶部：进练习 ============================ */
.wl-hero {
  display: flex;
  flex-wrap: wrap;
  gap: var(--gap);
  align-items: flex-start;
  justify-content: space-between;
  padding: 18px 18px 16px;
  background: var(--c-card);
  border: 1px solid var(--c-line-soft);
  border-radius: var(--r-md);
}

.wl-hero-l {
  flex: 1 1 300px;
  min-width: 260px;
}

.wl-hero-l h1 {
  margin: 0 0 6px;
  font-size: var(--fs-2xl);
  color: var(--t-bright);
}

.wl-sub {
  margin: 0 0 10px;
  color: var(--t-primary);
  font-size: var(--fs-md);
}

.wl-count {
  margin: 0;
  color: var(--t-muted);
  font-size: var(--fs-sm);
}

.wl-hero-r {
  flex: 0 1 420px;
  min-width: 260px;
}

.wl-modes-l {
  color: var(--t-muted);
  font-size: var(--fs-sm);
  margin-bottom: 6px;
}

.wl-modes {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

.wl-mode {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 1px;
  min-width: 88px;
  min-height: var(--tap);
  padding: 7px 12px;
  background: var(--c-input);
  border: 1px solid var(--c-line);
  border-radius: var(--r-md);
  color: var(--t-primary);
  cursor: pointer;
  text-align: left;
}

.wl-mode:hover {
  background: var(--c-hover);
  border-color: var(--c-accent-dim);
}

.wl-mode.is-on {
  background: var(--c-accent-deep);
  border-color: var(--c-accent);
  color: var(--t-bright);
}

.wl-mode-t {
  font-size: var(--fs-lg);
  color: var(--t-bright);
}

.wl-mode-h {
  font-size: var(--fs-xs);
  color: var(--t-muted);
}

.wl-mode.is-on .wl-mode-h {
  color: var(--t-primary);
}

.wl-run {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
  margin-top: 10px;
}

/* 空库时按「开始」→ 这句话变色，同时给一条 toast —— 绝不白屏。 */
.wl-hint {
  margin: 10px 0 0;
  color: var(--t-muted);
  font-size: var(--fs-sm);
}

.wl-hint.is-warn {
  color: var(--c-gold);
}

/* ============================ ② 搜词加入 ============================ */
.wl-searchbar {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  align-items: center;
  margin: 10px 0 4px;
}

.wl-input {
  flex: 1 1 240px;
  min-width: 200px;
}

.wl-go {
  flex: 0 0 auto;
}

.wl-results {
  margin-top: 10px;
}

.wl-tip {
  color: var(--t-dim);
  font-size: var(--fs-sm);
  margin: 6px 0;
}

/* 每行结果下面那颗「加入我的词库」 */
.wl-pick {
  display: flex;
  justify-content: flex-end;
  margin-top: 8px;
}

.wl-add.is-in {
  background: var(--c-card-hi);
  color: var(--t-muted);
}

.wl-add.is-in:hover {
  background: var(--c-card-hi);
  color: var(--t-muted);
}

.wl-add[aria-busy="true"] {
  opacity: .6;
  cursor: progress;
}

/* ============================ ③ 已加入的词 ============================ */
.wl-rows {
  list-style: none;
  margin: 10px 0 0;
  padding: 0;
}

.wl-row {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  align-items: flex-start;
  padding: 12px 14px;
  margin-bottom: 10px;
  background: var(--c-card);
  border: 1px solid var(--c-line-soft);
  border-radius: var(--r-md);
}

.wl-row-main {
  flex: 1 1 320px;
  min-width: 240px;
}

.wl-wordline {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 8px;
}

.wl-word {
  font-size: var(--fs-xl);
  color: var(--t-bright);
  word-break: break-word;
}

.wl-phon {
  color: var(--t-dim);
  font-size: var(--fs-sm);
}

.wl-cn {
  color: var(--t-primary);
  margin-top: 2px;
}

.wl-cn.is-dim {
  color: var(--t-dim);
  font-size: var(--fs-sm);
}

.wl-meta {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  margin-top: 4px;
  color: var(--t-muted);
  font-size: var(--fs-sm);
}

.wl-src,
.wl-at {
  color: var(--t-muted);
}

/* 备注：就地改 */
.wl-note {
  flex: 1 1 240px;
  min-width: 200px;
  display: flex;
  gap: 8px;
  align-items: center;
}

.wl-note-in {
  flex: 1 1 auto;
  min-width: 120px;
}

.wl-note-save {
  flex: 0 0 auto;
}

.wl-note-save[aria-busy="true"] {
  opacity: .6;
  cursor: progress;
}

.wl-acts {
  display: flex;
  gap: 8px;
  align-items: center;
}

.wl-del.is-armed {
  background: var(--c-red-a);
  border-color: var(--c-red-b);
  color: var(--t-bright);
}

.wl-del.is-armed:hover {
  background: var(--c-red-b);
}

/* ============================ 空态 / 失败态 ============================ */
.wl-howto {
  margin-top: 12px;
  padding: 12px 14px;
  background: var(--c-input);
  border: 1px solid var(--c-line-soft);
  border-radius: var(--r-md);
}

.wl-howto-t {
  color: var(--t-bright);
  font-size: var(--fs-md);
  margin-bottom: 8px;
}

.wl-howto-i {
  display: flex;
  gap: 8px;
  align-items: flex-start;
  margin-bottom: 6px;
}

.wl-howto-i:last-child {
  margin-bottom: 0;
}

.wl-howto-n {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 18px;
  height: 18px;
  margin-top: 2px;
  border-radius: 50%;
  background: var(--c-accent-deep);
  color: var(--t-bright);
  font-size: var(--fs-xs);
}

.wl-howto-x {
  color: var(--t-muted);
  font-size: var(--fs-sm);
}

/* 「读不到词库」是**失败**，不是「词库是空的」—— 两件事长得很像，
   屏幕上必须长得不一样。 */
.wl-err {
  padding: 16px;
  background: var(--c-card);
  border: 1px solid var(--c-red-a);
  border-radius: var(--r-md);
}

.wl-err-t {
  color: var(--t-bright);
  font-size: var(--fs-lg);
  margin-bottom: 6px;
}

.wl-err-m {
  color: var(--t-primary);
  margin-bottom: 6px;
  word-break: break-word;
}

.wl-err-h {
  color: var(--t-muted);
  font-size: var(--fs-sm);
  margin: 0 0 10px;
}

.wl-retry,
.wl-reload {
  flex: 0 0 auto;
}

/* ============================ 窄屏 ============================ */
@media (max-width: 620px) {
  .wl-hero {
    padding: 14px 12px;
  }

  .wl-hero-r {
    flex-basis: 100%;
  }

  .wl-mode {
    flex: 1 1 30%;
    min-width: 0;
  }

  .wl-note {
    flex-basis: 100%;
  }

  .wl-acts {
    width: 100%;
    justify-content: flex-end;
  }
}

/* ===========================================================================
   已掌握的单词（老师 2026-10-01：放在**当前列表的最下面**）
   —— 与上面的「已加入的词」要像同一族，但**一眼能分清**：
      收藏是你主动挑的、掌握是你练出来的。所以这里更素：顶上加一条分隔线，
      行首用一条竖线，不用卡片描边（那会让两块看起来一样重）。
   =========================================================================== */
.wl-sec-mastered {
  margin-top: 30px;
  padding-top: 18px;
  border-top: 1px solid var(--c-line);
}

.wl-m-hint {
  color: var(--t-dim);
  font-size: var(--fs-sm);
  margin: 6px 0 12px;
}

/* ---------- 一排 8 个格子（老师 2026-10-01）----------
   ★ 晚 21:07 老师看完定稿：「一排10个的可视化不是很好，减少到8个」——
     也就是**先按 10 个做过一版，当天就改回 8 个**（10 列时每格太窄，
     词和中文都挤成一条）。以后要动列数，记得连着改 CSS 注释和
     `_selftest_mastered_dom.mjs` 里那条列数断言。
   为什么钉死列数而不是自适应：老师要的是"**一排 N 个**"这个确定的样子，
   自适应列数会随窗口宽度变成 7 个、9 个，那就不是他要的那个样子了。
   ★ 窄屏一定退回自适应 —— 8 列在手机上还是会挤成豆腐块（这条是
     pages-store.css 的 `.grid.is-row5` 立下的规矩，照它来）。 */
.wl-m-grid {
  display: grid;
  grid-template-columns: repeat(8, minmax(0, 1fr));
  gap: 8px;
}

@media (max-width: 1200px) {
  .wl-m-grid { grid-template-columns: repeat(6, minmax(0, 1fr)); }
}

@media (max-width: 900px) {
  /* 退回自适应：列宽不小于 92px，能塞几个塞几个 */
  .wl-m-grid { grid-template-columns: repeat(auto-fill, minmax(92px, 1fr)); }
}

/* 一格：词（一行，不折） + 中文（最多两行，超出省略） */
.wl-m-cell {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 3px;
  padding: 8px 9px;
  min-height: 58px;
  background: var(--c-card);
  border: 1px solid var(--c-line);
  border-radius: var(--r-sm);
  cursor: pointer;
  text-align: left;
  font-family: inherit;
  overflow: hidden;
}

.wl-m-cell:hover {
  background: var(--c-card-hi);
  border-color: var(--c-accent-dim);
}

.wl-m-cell:focus-visible {
  outline: 2px solid var(--c-accent);
  outline-offset: 1px;
}

.wl-m-w {
  font-size: var(--fs-sm);
  font-weight: 600;
  /* ★ 别用 --t-ink！它是 #0e1621（**最深的前景色/背景色**，与 --c-input 同值），
     在这个深色主题上写出来就是深底深字、几乎看不见（我第一版就栽在这）。
     深色底上的正文用 --t-primary（#c7d5e0）—— 与这一屏其他正文同一个令牌。 */
  color: var(--t-primary);
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* 中文释义：**和英文词一样大**（老师 2026-10-01：「中文释义字体太小了，
   尝试做成和英文原词差不多的大小」）。
   ★ 为什么敢一样大：英文词本来是 `--fs-sm`(12px)，中文之前是 `--fs-xs`(12px) ——
     这个主题里 `--fs-xs` 和 `--fs-sm` **恰好都是 12px**，所以视觉差不是字号造成的，
     而是**字重**（英文 600、中文 400）与**颜色**（英文 --t-primary 亮、中文 --t-dim 暗）。
     ⇒ 要"看起来差不多大"，得把这三样一起提上来，不是一个 font-size 的事。
   ★ 一排放不下怎么办：中文仍是**最多两行 + 省略**（`line-clamp: 2`），
     真的放不下时是**截断**而不是缩字号 —— 缩到 8px 那种字学生根本看不清；
     完整释义点开看弹窗（这一块的设计本来就是这样）。 */
.wl-m-c {
  font-size: var(--fs-sm);
  font-weight: 500;                /* 比正文略实一点，与英文词的 600 配得上 */
  color: var(--t-muted);           /* 比 --t-dim 亮一档，别让中文"退到背景里" */
  line-height: 1.4;
  display: -webkit-box;
  -webkit-line-clamp: 2;          /* 最多两行 */
  -webkit-box-orient: vertical;
  overflow: hidden;
  word-break: break-word;
}

/* 弹窗里的元信息行（来源 / 掌握日期 / 已在词库） */
.wl-m-modal-meta {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  align-items: baseline;
  margin: 0 0 14px;
}

/* ===========================================================================
   完整释义弹窗：**参考单词卡的比例**（老师 2026-10-01）
   「弹出的窗口可以参考单词卡的比例，我记得好像16：9？然后把英文和中文
     都置中放置，根据内容多少自动适配大小。」

   ★ 单词卡的正身规格在 pages-learn.css 的 `.ln-card-wrap`：
       width: min(680px, 100%) · aspect-ratio: 16/9 · min-height: 300px
     这里照抄同一套（宽 680 + 16:9 + 300 的安全网），两处看起来才是一家人。

   ★「根据内容多少自动适配大小」怎么落：
     · 宽度 = min(680px, 视口宽) —— 内容少也不会缩成一小条
     · 高度 = 宽度 ÷ 16×9（`height: auto` + aspect-ratio），**同时**受
       `max-height: calc(100vh - 96px)` 约束 —— 屏幕矮时宁可破比例也不溢出
     · 释义长时**卡片不长大**，正文自己滚（`overflow-y: auto`）——
       这样"窗口大小"只跟屏幕有关，不会因为一条长释义把弹窗顶到屏幕外

   ★★★ 2026-10-13（老师报了学习模式两处同族 bug 之后，顺手修的第三处）：
     这里抄的是 `.ln-card-wrap` 的**改动前**那一套 —— `min-height: 300px` 是个
     **与宽度无关**的数：视口窄到让 `min(680px, 100vw−32px) < 533px` 时，
     16:9 算出来的高不足 300，`min-height` 就**反过来压过 `aspect-ratio`**
     ⇒ 弹窗从横的 16:9 翻成**竖长条**（与单词卡那次一模一样的坏法）。
     ▍修法照上一轮的口径：给一个**绑在弹窗自己能拿到的宽**上的下限
       `min-height: min(300px, 56.25cqw)` —— 56.25cqw 就是 16:9 的高度，
       外面套一层 `min(300px, …)` ⇒ **数学上永远不超过比例高**，
       宽的时候仍然退回 300px（原来那条"别挤没了"的安全网一个字没丢）。
     ▍量尺（`container-type`）为什么挂在遮罩上：弹窗自己是查询不自己的。
       `.modal-mask` 的内容盒**就是**弹窗能拿到的宽度
       （`inset:0` + `padding:16px` ⇒ 100cqw = 视口宽 − 32px，
         而弹窗的宽 = min(680px, 100vw − 32px)）—— 两个数是同一个来源，
       所以这里的 cqw 不会像 vw 那样"算多"。
     ▍为什么只给**这个**遮罩挂量尺（`:has()`）：`container-type` 带
       `contain: style`（会重定 counters/quotes 的作用域），
       平台里所有弹窗共用 `.modal-mask` —— 不给别的弹窗平白加这层 containment。
       `:has()` 认不出来的引擎**直接忽略这一条**（退回"没有查询容器"，
       `cqw` 按规范落到视口单位）：弹窗顶多比 16:9 胖一点点，不会翻成竖条，
       也不会溢出 —— 与 `body.is-bare .wrap:has(...)` 那几处同一个口径：
       可选项，不当唯一依赖。
     ★ 弹窗的**内容与行为一个字没动**：这次只换了"高度下限怎么算"，
       DOM、文案、按钮、`max-height`、正文滚动全都照旧。 */
.modal-mask:has(.wl-m-modal) {
  container-type: inline-size;
}

.modal.modal-detail.wl-m-modal {
  width: min(680px, calc(100vw - 32px));
  max-width: 680px;
  aspect-ratio: 16 / 9;
  min-height: 300px;                 /* 兜底：认不出 cqw 的引擎照旧（与改动前一致） */
  /* 与 `.ln-card-wrap` 同一条安全网，但**绑在弹窗自己拿到的宽上**：
     `min(300px, 比例高)` —— 窄屏退回比例高，宽屏退回 300px，永不越权。 */
  min-height: min(300px, calc(56.25cqw));
  max-height: calc(100vh - 96px);
  height: auto;
  /* ★ 居中**必须**写 `margin:auto`（别再省掉）——
     2026-10-03 起 `.modal-mask` 的 `align-items` 是 `flex-start`
     （为了让超高弹窗能从头滚到底，见 components.css 那段），
     所以"竖直居中"改由这里 + 基础 `.modal` 的 `margin:auto` 承担。
     ★ `auto` 在内容比容器高时会**塌成 0**、从顶部开始 ——
       这正是我们要的：滚到底就摸得到最下面那颗按钮（iPad 上曾卡死过）。 */
  margin: auto;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  gap: 10px;
  padding: 22px 30px;
}

/* 弹窗里的词：字号跟单词卡正面同一量级（那边是 clamp(38px,7vw,68px)），
   但弹窗更窄，所以压一档；颜色用 --t-bright（与单词卡同一个令牌）。 */
.modal.wl-m-modal h3 {
  font-size: clamp(26px, 4.4vw, 44px);
  font-weight: 700;
  color: var(--t-bright);
  text-align: center;
  margin: 0;
  max-width: 100%;
  word-break: break-word;
}

.wl-m-modal-meta {
  justify-content: center;           /* 元信息也居中 */
  margin: 0;
}

/* 释义正文：居中 + 长了自己滚，**不把弹窗撑大** */
.modal.wl-m-modal .modal-detail-body {
  width: 100%;
  flex: 0 1 auto;
  min-height: 0;                     /* flex 子项要能收缩才会出滚动条 */
  max-height: 100%;
  overflow-y: auto;
  /* ★ 这里**居中**（老师要"英文和中文都置中"）——
     `components.css` 的 `.modal-detail-body` 默认是左对齐的，这里覆盖掉。 */
  text-align: center;
  font-size: clamp(12px, 1.15vw, 14px);
  line-height: 1.7;
}

/* 关闭按钮放正下方居中（原来靠右，在 16:9 的卡里看着是歪的） */
.modal.wl-m-modal .modal-actions {
  justify-content: center;
  margin: 0;
  flex: none;
}

.wl-m-src,
.wl-m-at {
  color: var(--t-dim);
  font-size: var(--fs-sm);
  white-space: nowrap;
}

.wl-m-at {
  font-variant-numeric: tabular-nums;   /* 日期对齐，扫起来快 */
}

/* 「已在词库」= 这个词你既收藏了又掌握了（老师同意不去重，所以标一下） */
.wl-m-in {
  color: var(--t-dim);
  font-size: var(--fs-sm);
  border: 1px solid var(--c-line);
  border-radius: 999px;
  padding: 1px 7px;
  white-space: nowrap;
}

.wl-m-more-bar {
  display: flex;
  justify-content: center;
  margin-top: 12px;
}

.wl-m-empty,
.wl-m-fail {
  color: var(--t-dim);
  font-size: var(--fs-sm);
  margin: 10px 0;
}

/* 失败要看得出来是失败 —— 不能跟"空态"长一个样 */
.wl-m-fail {
  color: var(--c-red-a);
}
