/* ==========================================================================
   聊天室（逐字稿）页面 —— 同时也是「目录页通用件」的所在地
   目录页 /chat  →  年 · 月 · 日 三级
   阅读页 /chat/:id  →  左侧等宽时间栏 + 右侧正文

   ⚠️ `.chat-nav` / `.chat-chip` / `.chat-list` / `.chat-item` / `.chat-adjacent`
   这五个类**不止聊天室在用**：经典讲义目录页 /classics 也复用它们（同一种「顶部 chip 行
   + 分块条目列表 + 上一篇/下一篇」结构）。所以改这几个类要同时想着经典页；
   经典自己的正文样式在 lecture.css。
   名字里的 chat- 前缀是历史遗留，真要改名的话得连模板字符串一起动。

   时间栏宽度不是拍脑袋定的：全库时间戳恰好 8 字符（HH:MM:SS），
   等宽字体 advance ≈ 0.6em ⇒ 12px 时 8 字符 ≈ 57.6px，故手机端给 62px。
   ========================================================================== */

/* ---------------- 目录页：年月导航 ---------------- */

/* 筛选区：**一个白底外框装所有 chip 排，整框吸顶**（用户口径：
   「年和月标签用一个框吧，都吸顶，吸顶时高度最小」）。

   两条 CSS 硬约束决定了"只能是**一个**框、且吸顶的必须是**框自己**"：
   ① sticky 元素被限制在它的**粘性容器（＝父元素）**里：某一排 chip 若是
      `.chat-nav` 的子元素，它只能在 .chat-nav 的高度内"粘"，滚过就跟着走
      —— 等于没吸顶。所以吸顶的不能是框里的某一排。
   ② 带 `overflow: hidden` 的祖先会让后代 sticky 失效，而外框的圆角正要靠
      overflow 切 ⇒ 也不能把 sticky 框再塞进另一个框里。
   ⇒ 一个 `.chat-nav--sticky` 直接挂在 `.page__inner` 下，整框 sticky。

   "吸顶时高度最小"：整框吸住后（JS 打上 `.is-stuck`）**整框上移**，屏幕上只剩
   最后一行 —— 聊天室＝月份排，经典页＝月份排（讲义分类只有一排，就原样不动）。
   可见高度 110px → 约 56px，而且**下方内容一动不动**（走 transform，不动布局）。
   代价：滚动中换年/换分类要回到顶部，那是低频操作；换月是高频，所以留下月份排。 */
.chat-nav {
  margin-top: var(--sp-3);
  padding: var(--sp-2);
  display: flex;
  flex-direction: column;
  gap: 6px;
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-panel);
  background: var(--surface);
  box-shadow: var(--shadow-soft);
  overflow: hidden;
}

/* 吸顶的是框自己（见上面 ②）。左右留满、不带圆角边框的那种通栏做法这里不用：
   圆角外侧那四个小角会漏出底下的列表，而列表也是白底，几乎看不出来。 */
.chat-nav--sticky {
  position: sticky;
  top: 0;
  z-index: var(--z-sticky);
  transition: transform 0.18s ease;
}

.chat-nav__row {
  display: flex;
  gap: 6px;
  padding: 2px 0;
  /* ⚠️ 必须 `align-items: center`：默认 `stretch` 会把 chip 拉到和这一排一样高，
     于是 chip 的内容盒不再等于 40px —— 上面那条"行盒高度 == 内容盒高度"的
     居中前提就塌了（flex 失效的浏览器里文字会重新变成贴顶）。 */
  align-items: center;
  overflow-x: auto;
  scrollbar-width: none;
  -webkit-overflow-scrolling: touch;
}

/* 吸住后整个框**上移**，把上面的排推出屏幕之外，只把最后一行留在屏幕上
   （聊天室＝月份排，经典页＝月份排；上移量由 JS 量出来写进 `--nav-collapse`）。

   ⚠️ **必须用 transform**，不能改成"把上面的排收起来"（max-height / padding 归零）：
   改高度是改布局 ⇒ ① 下方内容整体上跳一次；② Chrome 的 scroll anchoring 会补偿
   这次跳动，把 scrollY 回调几十像素 ⇒ 框的顶边退回吸顶线之上 ⇒ 类被摘掉 ⇒ 行展开
   ⇒ 内容回落 ⇒ 又满足吸顶条件……正好在阈值上来回振荡，用户看到的就是"抖 + 闪"。
   transform 不参与布局，下方内容和 scrollY 都不受影响，这条回路从根上不存在。

   副作用（可接受）：框的上边框和上面两个圆角被推到屏幕外，看上去就是一根贴顶的条。
   被推出屏幕的那几排在 HOME 键意义上还在 DOM 里，所以顺手屏蔽掉点击。 */
.chat-nav--sticky.is-stuck {
  transform: translateY(calc(-1 * var(--nav-collapse, 0px)));
}

.chat-nav--sticky.is-stuck .chat-nav__row:not(:last-child) {
  pointer-events: none;
}

@media (prefers-reduced-motion: reduce) {
  .chat-nav--sticky {
    transition: none;
  }
}

.chat-nav__row::-webkit-scrollbar {
  display: none;
}

/* 🔑 文字为什么"看起来没居中"、以及怎么让它**在任何浏览器**都居中：
   光靠 `display:inline-flex + align-items:center` 是有前提的 —— 它要求浏览器
   支持**把 `<button>` 本身当 flex 容器**。这条在部分 WebView / 老 Safari 上不成立：
   那里 button 的内容会被塞进一个 UA 私有的匿名盒，`align-items:center` 无效，
   文字直接贴着内容区顶部 —— 用户看到的就是"上下不居中"。

   改法：让**行盒自己等于内容盒高度**，这样居中不再依赖 flex：
     line-height(=38px) 撑出的行盒 == min-height(40px) − 上下边框(2px) 的内容盒，
     单行文本永远落在行盒正中 ⇒ 无论 flex 生效与否，结果都一样。
   （数学上 line-height 只是缩放行盒，content area 始终对称于行盒中心，
     所以单纯改 line-height 并不能修 → 必须让它**等于**内容盒高度。）
   两个值用同一个变量 `--chip-h` 表达，改高度时不会失配。 */
.chat-chip {
  --chip-h: 40px;
  position: relative;
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: var(--chip-h);
  padding: 0 14px;
  line-height: calc(var(--chip-h) - 2px);   /* −2px = 上下边框（border-box） */
  border: 1px solid var(--line);
  border-radius: var(--radius-pill);
  background: var(--surface);
  color: var(--text-body);
  font-size: var(--fs-caption);
  font-weight: 700;
  text-align: center;
  white-space: nowrap;
}

/* 视觉高度 40px，实际命中区上下各外扩 3px ⇒ 46px，满足触控下限 */
.chat-chip::after {
  content: '';
  position: absolute;
  inset: -3px 0;
}

.chat-chip.is-active {
  border-color: var(--accent);
  background: var(--accent-soft);
  color: var(--accent-deep);
}

.chat-chip--sm {
  padding: 0 12px;
}

/* ---------------- 目录页：月 · 日 · 条目 ---------------- */

.chat-month-head {
  margin: 14px 0 2px;
  font-size: var(--fs-title);
  font-weight: 800;
  color: var(--accent-deep);
}

/* 月份标题在**外框里面**当表头（用户口径：列表框要把「01月」框住）。
   在框里就没有外边距了，改成内边距，并跟条目对齐同一条左边界（14px）。 */
.list-frame .chat-month-head {
  margin: 0;
  padding: 14px 14px 6px;
}

.chat-day {
  margin-top: var(--sp-4);
}

/* 日期行只留日期：早先右边还有个「星期六 · 3 条」，
   用户明确要求去掉（导航性信息，条数属于"点进去才知道有没有用"的噪音）。 */
.chat-day__head {
  margin: 0 0 var(--sp-2);
  padding: 0 2px;
  font-size: var(--fs-caption);
  font-weight: 700;
  color: var(--text-soft);
}

.chat-day__date {
  color: var(--text-body);
  font-size: calc(var(--fs-caption) + 1px);
}

/* ---------------- 列表外框 ----------------
   用户口径：目录里的条目要"装进一个白底的外框"，而不是散在灰底上一张张小卡片。
   所以外框负责描边和圆角，框内的条目**反过来把自己那圈边和阴影卸掉**，
   改用 1px 底边做分隔 —— 否则就是"卡片套卡片"，边上双线、阴影叠阴影。

   两个页面共用（聊天室 /chat 与经典目录 /classics），所以规则挂在
   `.list-frame` 后代上、不在 `.chat-item` 本体上改 —— 搜索结果页那些
   没套框的列表照旧。

   最后一行的底边要和外框的下边重合，否则底部是两条线：
   给外框的最后一个子元素 `margin-bottom: -1px`，让它整体上提 1px，
   正好把最后一条的底边压在外框下边框上。 */
.list-frame {
  margin-top: var(--sp-4);
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-panel);
  background: var(--surface);
  box-shadow: var(--shadow-soft);
  overflow: hidden;   /* 条目是直角，靠这里把四个角切成外框的圆角 */
}

.list-frame > :last-child {
  margin-bottom: -1px;
}

.list-frame .chat-list {
  gap: 0;
}

.list-frame .chat-item {
  border: 0;
  border-bottom: 1px solid var(--line);
  border-radius: 0;
  background: transparent;
  box-shadow: none;
  padding: 12px 14px;
}

/* 框内没有边框了，按下去得另外给反馈，不然点了没反应 */
.list-frame .chat-item:active {
  background: var(--bg-soft);
}

/* 日期小标题（聊天室）与分类小标题（经典页）在框里要跟着内缩 */
.list-frame .chat-day {
  margin-top: 0;
  padding-top: var(--sp-3);
}

.list-frame .chat-day__head {
  padding: 0 14px;
}

.chat-list {
  display: grid;
  gap: var(--sp-2);
}

.chat-item {
  position: relative;
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  min-height: var(--row-h);
  padding: 10px 12px;
  border: 1px solid var(--line);
  border-radius: 14px;
  background: var(--surface);
  box-shadow: var(--shadow-soft);
  text-align: left;
}

.chat-item__no {
  flex: 0 0 auto;
  padding: 2px 6px;
  border-radius: 8px;
  background: var(--bg-soft);
  color: var(--text-soft);
  font-size: 12px;
  font-variant-numeric: tabular-nums;
}

.chat-item__title {
  flex: 1;
  min-width: 0;
  font-weight: 700;
  line-height: 1.4;
  word-break: break-word;
}

.chat-item__arrow {
  flex: 0 0 auto;
  color: var(--text-soft);
}

/* ---------------- 阅读页：时间轴 ---------------- */

.chat-reader {
  --chat-time-col: calc(var(--chat-time-w) * var(--font-scale));
  padding: 0;
  overflow: hidden;
}

.chat-reader__body {
  max-width: var(--chat-read-max);
  padding: 14px 14px 18px;
}

.chat-line {
  display: grid;
  grid-template-columns: var(--chat-time-col) minmax(0, 1fr);
  gap: var(--sp-2);
  padding: var(--chat-line-gap) 0;
}

/* 行首时间戳：纯展示的等宽小字。
   早先它是个 `<button>`（点一下复制该行）—— 用户要求去掉：命中区外扩后整行左边
   都能点，滚动时极易误触，而且这个场景里没人会复制单独一行。 */
.chat-line__time {
  display: block;
  color: var(--text-soft);
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: calc(12px * var(--font-scale));
  line-height: 1.75;
  font-variant-numeric: tabular-nums;
  text-align: left;
  white-space: nowrap;
  overflow: hidden;
  user-select: text;
}

.chat-line__text {
  margin: 0;
  line-height: 1.75;
  word-break: break-word;
}

.chat-line--head .chat-line__text {
  color: var(--text-soft);
  font-size: var(--fs-caption);
}

.chat-line--raw {
  grid-template-columns: minmax(0, 1fr);
}

.chat-line--blank {
  height: 6px;
}

.chat-figure {
  margin: 10px 0;
  border: 1px solid var(--line);
  border-radius: 14px;
  overflow: hidden;
  background: var(--surface);
}

.chat-figure img {
  display: block;
  width: 100%;
  height: auto;
}

/* ---------------- 阅读页：上一篇 / 下一篇 ---------------- */

.chat-adjacent {
  display: flex;
  gap: var(--sp-2);
  margin-top: var(--sp-3);
}

.chat-adjacent__link {
  flex: 1 1 0;
  min-width: 0;
  display: block;
  padding: 10px 12px;
  border: 1px solid var(--line);
  border-radius: var(--radius-panel);
  background: var(--panel);
  box-shadow: var(--shadow-soft);
  text-align: left;
  cursor: pointer;
}

.chat-adjacent__link--next {
  text-align: right;
}

.chat-adjacent__link:hover {
  border-color: var(--accent);
}

.chat-adjacent__link:active {
  background: var(--accent-soft);
}

.chat-adjacent__label {
  display: block;
  font-size: var(--fs-caption);
  font-weight: 700;
  color: var(--accent-deep);
}

/* 标题只留两行：聊天室的标题本身就是"标题 + 时长"，长的能有两行以上，
   不夹住会把两个按钮撑成不同高度。 */
.chat-adjacent__title {
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
  margin-top: 2px;
  font-size: var(--fs-caption);
  line-height: 1.4;
  color: var(--text-soft);
  word-break: break-word;
}

/* 只有一条时补个空位，让另一条留在它本来的半侧 */
.chat-adjacent__gap {
  flex: 1 1 0;
  min-width: 0;
}

/* ---------------- 断点（与 theme.css 的令牌断点保持一致）---------------- */

@media (min-width: 768px) {
  .chat-list {
    grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
  }

  .chat-reader__body {
    padding: 12px 18px 22px;
  }
}

@media (min-width: 1024px) {
  /* 电脑端目录列表固定**一横排两个**。
     不能继续用上面的 auto-fill：960px 的容器配 280px 最小宽会排到 3 列，
     而标题长起来一列放不下就折成两三行、相邻行高不齐，反而更难扫。
     讲义目录页用的是同一个 .chat-list，所以一并生效。 */
  .chat-list {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  /* 宽屏下年份 / 月份**仍然是顶部两排**，不做成左侧栏。
     早先那版把 .chat-nav 改造成 sticky 左栏（220px），副作用是 12 个月的 chip 换行后
     能长到视口以下、垂下来盖住固定底栏（那时候四个 tab 点不到），于是不得不靠
     `max-height: calc(100vh - 底栏 - 安全区 - …)` + `overflow-y: auto` 兜。
     布局回到上下之后这个坑自然消失，`--z-nav`（底栏高于一切吸顶元素）这条纪律仍然保留，
     因为它还护着别的吸顶元素。 */

  /* ⚠️ 这里**曾经**写着 `.page--chat .floating-top-button { display: none }`
     （理由：整个导航都吸在顶部，「回到顶部」没有意义）。现在导航吸住后只留月份排，
     年份排被收起 ⇒ 想换年份得先回到顶部，宽屏上没别的手段，按钮要恢复。
     教训：隐藏一个控件的理由变了，规则就得跟着删，别让注释和代码各说各话。 */
}
