/* ============================================================================
 * 布局（Layout）· 三栏桌面 IM 架构
 *
 * 设计稿：Primary Navigation Rail(64px) ─ Channel List(300px) ─ Chat Chamber(flex)
 *
 * ## ⚠️ 这里同时是"滚不动 / 输入框跑出屏幕"问题的根因所在
 *
 * 规则：在一个 flex / grid 链条里，只要某一环要"内部滚动"，那么从根到这个
 * 可滚动元素之间的**每一环**都必须能收缩 —— 即 min-height: 0（纵向）
 * 和 min-width: 0（横向）。
 *
 * 因为 flex/grid 子项默认 min-height: auto，意思是"不许小于内容高度"，
 * 于是消息一多就把容器撑高、超出视口，而 body 又是 overflow: hidden，
 * 最终表现为：不能滚、底部输入框被推到屏幕外。
 *
 * ## 设计稿另外两条布局约定（本文件落实）
 *   · Level 0/1/2/3 的水下分层：画布平铺 → 列表玻璃 → 气泡浮起 → 弹窗悬空
 *   · 响应式断点：>1440 列表 340px；<1024 图标栏收成 52px 图标条
 * ==========================================================================*/

*, *::before, *::after { box-sizing: border-box; }

html, body { height: 100%; }

body {
  margin: 0;
  overflow: hidden;                 /* 只允许内部区域滚动 */
  background: var(--bg-app);
  color: var(--fg);
  font-family: var(--font-ui);
  font-size: 14px;
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  transition: background .2s var(--ease), color .2s var(--ease);
}

/* ---------- 外壳：三栏 ---------- */
.app {
  height: 100%;
  min-height: 0;                    /* ← 关键 1 */
  display: grid;
  grid-template-columns: var(--rail-w) var(--panel-w) minmax(0, 1fr);
  /*                                           ↑ 关键 2：minmax(0,1fr)
     用 1fr 时，列的最小宽度是 auto（= 内容宽度），长消息会把列撑宽；
     minmax(0,1fr) 才允许它收缩。 */
  grid-template-rows: minmax(0, 1fr);
}

.rail,
.panel,
.chat {
  min-height: 0;                    /* ← 关键 3：每栏都可压缩 */
  min-width: 0;
}

/* ---------- 最左图标栏（Level 0：深海基底） ---------- */
.rail {
  background: var(--bg-rail);
  border-right: 1px solid rgba(255, 255, 255, .08);
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: 16px 0 14px;
  gap: 6px;
  position: relative;
  z-index: 30;                      /* 压住列表的玻璃层 */
}

/* ---------- 左二列表（Level 1：半透明海沫玻璃） ---------- */
.panel {
  background: var(--bg-panel-glass, var(--bg-panel));
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
  border-right: var(--glass-border);
  display: flex;
  flex-direction: column;
  position: relative;
  z-index: 20;
}

.panel-scroll {
  flex: 1 1 0;                      /* basis 0 才肯收缩 */
  min-height: 0;
  overflow-y: auto;
  overflow-x: hidden;
  /* 列表底部给状态条让出位置，最后一行不会被压住 */
  padding-bottom: 6px;
}

/* 列表底部的系统状态条（设计稿的"太平洋深海 3000m 专线"位） */
.panel-foot {
  flex: none;
  display: flex; align-items: center; justify-content: space-between; gap: 8px;
  padding: 7px 12px;
  border-top: var(--glass-border);
  background: color-mix(in srgb, var(--bg-panel) 60%, transparent);
  font-size: var(--fs-caption);
  color: var(--fg-dim);
}
.panel-foot__left { display: flex; align-items: center; gap: 6px; min-width: 0; }
.panel-foot__text {
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  font-weight: 600;
}
.panel-foot__ver { flex: none; font-family: var(--font-mono); letter-spacing: .02em; }

/* ---------- 右侧对话 ---------- */
.chat {
  background: var(--bg-app);
  display: flex;
  flex-direction: column;
  overflow: hidden;                 /* 兜底：任何溢出都在内部消化 */
  position: relative;
  /* Level 0 的水光：极缓慢的明暗流动（设计稿的 causticShimmer） */
  background-image: linear-gradient(
    135deg,
    color-mix(in srgb, var(--bb-cyan-soft) 10%, transparent) 0%,
    transparent 45%,
    color-mix(in srgb, var(--bb-cyan-soft) 6%, transparent) 100%
  );
  background-size: 200% 200%;
  animation: causticShimmer 24s ease infinite;
}

.chat-head {
  flex: none;
  height: var(--head-h);
  position: relative;
  z-index: 10;                      /* 在环境气泡之上 */
}

/* ---------- 主题壁纸（设计稿 _2 的「比奇堡主题壁纸」） ----------
 * 默认不设 `data-wallpaper` → 用上面那条 causticShimmer 水光，观感不变。
 * 选了壁纸就换成一组分层柔光；`animation: none` 是因为 causticShimmer 动的是
 * `background-position` + `background-size: 200% 200%`，套到多图层上会各层
 * 一起漂移（看起来像糊了一层）。关掉动画，代价只是少一点流动感。 */
html[data-wallpaper='sun'] .chat,
html[data-wallpaper='reef'] .chat,
html[data-wallpaper='jelly'] .chat,
html[data-wallpaper='none'] .chat { animation: none; }

html[data-wallpaper='sun'] .chat {
  background-image:
    radial-gradient(115% 80% at 86% 4%, var(--wl-sun) 0%, transparent 62%),
    radial-gradient(90% 70% at 8% 98%, var(--wallpaper-tint) 0%, transparent 60%);
}
html[data-wallpaper='reef'] .chat {
  background-image:
    radial-gradient(110% 75% at 10% 94%, var(--wl-reef) 0%, transparent 60%),
    radial-gradient(85% 65% at 92% 8%, var(--wl-jelly) 0%, transparent 58%);
}
/* 水母平原：点阵（像水下悬浮的小水母），比前两个更像"纹理" */
html[data-wallpaper='jelly'] .chat {
  background-image:
    radial-gradient(var(--wl-jelly) 1.6px, transparent 1.8px),
    radial-gradient(100% 70% at 50% 0%, var(--wl-jelly) 0%, transparent 55%);
  background-size: 26px 26px, auto;
}

/* 消息区：唯一允许纵向滚动的区域 */
.timeline {
  flex: 1 1 0;
  min-height: 0;
  overflow-y: auto;
  overflow-x: hidden;
  overscroll-behavior: contain;      /* 滚到头不要带动外层 */
  scroll-behavior: auto;             /* 自己控制滚动时机，别用平滑 */
  /* ⚠️ 关掉浏览器的**滚动锚定**。
   *    只写在 `.timeline` 上**不够** —— 实测 Chromium 仍会在与滚动无关的重排
   *    （比如在输入框打一个字）时把 scrollTop 顶上去几十像素：内容高度没变、
   *    输入区高度也没变，就是它动一下又弹回来，肉眼是"抖一下"。
   *    贴底这件事我们自己在 `timeline.js` 里用 ResizeObserver 管，
   *    这里要的是"没人替我们乱动 scrollTop"。 */
  overflow-anchor: none;
  position: relative;
  z-index: 10;
}

/* ⚠️ 必须关掉时间线**内部所有**元素的滚动锚定。
 *    锚点是逐元素判定的，只有容器和直接子元素写 `overflow-anchor: none`
 *    挡不住更深层的元素被选为锚点 —— 实测在输入框打一个字时，
 *    scrollTop 会被浏览器内部顶掉 26px 又弹回来（JS 一次都没写它，
 *    抓调用栈是空的），肉眼就是"抖一下"。
 *    代价：用户往上翻看历史时，上方内容高度变化会让视线轻微跳一下。
 *    取舍是显然的 —— 每敲一个字抖一下远比这个糟。 */
.timeline * { overflow-anchor: none; }

.composer { flex: none; position: relative; z-index: 20; }

/* ---------- 环境气泡层（设计稿 floatUp） ----------
 * 纯装饰、不吃事件。放在 .chat 里、消息区之下，z-index 让给 .timeline。
 * 2026-10-13：由 motion.js 的**一张画布按 ~12fps 画**（原来是 7 个 DOM 各跑 CSS 动画；
 * 只要有一条 CSS 常驻动画在跑，浏览器就永远以 60fps 出帧 —— 老 Intel Mac 上风扇狂转）。
 * 视觉不变：还是 7 颗、同一条上浮路径（关键帧与缓动逐项搬进 motion.js）。
 *
 * top 从头部下缘开始：气泡本来也从头部后面穿过，而头部 90% 不透明（看不见）；
 * 裁掉这一段后，头部那条 `backdrop-filter` 的背景就是静态的 —— 省掉每帧重算模糊。 */
.ambient {
  position: absolute;
  top: var(--head-h);
  right: 0;
  bottom: 0;
  left: 0;
  overflow: hidden;
  pointer-events: none;
  z-index: 1;
}
.ambient__canvas {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  display: block;
}

/* 设计稿里消息流中央还有一枚巨大的水滴水印 */
.chat-watermark {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  pointer-events: none;
  z-index: 0;
  opacity: .035;
}
.chat-watermark svg { width: 260px; height: 260px; color: var(--bb-cyan-deep); }

/* ==========================================================================
 * 响应式（设计稿的三个断点）
 * ========================================================================*/

/* 超宽屏：列表加宽到 340px（设计稿 Desktop Ultrawide >1440px） */
@media (min-width: 1441px) {
  .app { --panel-w: 340px; }
}

/* 紧凑桌面 / 平板横屏：图标栏收成 52px 图标条（设计稿 <1024px） */
@media (max-width: 1024px) {
  .app { --rail-w: 52px; }
}

/* ---------- 移动端 ----------
 *
 * 窄屏改成"单栏 + 抽屉"：列表是覆盖在聊天之上的抽屉，选中房间后收起。
 * 之前面板 `is-open` 加上了就再没人摘掉，而聊天区在它底下一格 ——
 * 结果是手机上选完房间整个聊天区被完全遮住，且没有任何返回手段。
 */
.panel-scrim {
  display: none;
  position: fixed;
  inset: 0;
  z-index: calc(var(--z-pop) - 1);
  background: var(--scrim);
}

@media (max-width: 760px) {
  .app { grid-template-columns: var(--rail-w) minmax(0, 1fr); }
  .chat-watermark svg { width: 180px; height: 180px; }

  .panel {
    position: absolute;
    top: 0; bottom: 0; left: var(--rail-w);
    /* ⚠️ 末尾那 28px 是**刻意留的**：抽屉与遮罩同占一层，遮罩 z-index 更低，
       抽屉一旦盖满剩余宽度，遮罩就完全点不到 —— 在 320px 宽的设备上
       表现为"抽屉打不开也关不掉"（点遮罩会命中面板本身）。实测踩过。 */
    width: min(var(--panel-w), calc(100vw - var(--rail-w) - 28px));
    z-index: var(--z-pop);
    transform: translateX(-100%);
    transition: transform .18s var(--ease);
    box-shadow: 2px 0 12px rgba(0, 0, 0, .2);
    visibility: hidden;   /* transform 移出屏幕后仍可点，这里彻底关掉 */
  }
  .panel.is-open { transform: none; visibility: visible; }
  .panel-scrim.is-on { display: block; }

  /* 手机上没有 hover，"点自己进房间"这个入口要点得到 */
  .row::after {
    content: '›';
    margin-left: auto;
    padding-left: 8px;
    color: var(--fg-faint);
    font-size: 18px;
    align-self: center;
  }

  /* 触屏上按钮太小不好点 */
  .rail-btn { width: 44px; height: 44px; }
  .tool-btn { width: 36px; height: 36px; }
  .pending__x { opacity: 1; width: 22px; height: 22px; font-size: 15px; }
  .pending__item { height: 64px; }
  .pending__item.is-img { width: 64px; }
  .pending__item img { width: 64px; height: 64px; }

  .msg { max-width: 86%; }
  .msg--file { max-width: 94%; }
  .filecard { min-width: 0; max-width: 100%; }
  .imgcard { width: min(220px, 58vw); }

  .emoji-pop {
    left: 8px; right: 8px;
    width: auto;
    bottom: 108px;
  }

  .composer { padding: 0 10px 8px; }
  .timeline-inner { padding: 12px 12px 6px; }
  .panel-foot { display: none; }        /* 手机上省掉这一行，把高度让给列表 */
  .conn-foot { display: none; }

  /* 顶栏：手机宽度放不下"标题 + 成员药丸 + 在线药丸 + 三个操作"。
     砍掉提示音 / 加密说明这两个次要入口（它们在设置页里都有），
     把宽度让给房间名 —— 房间名被截成「bb…」比少两个图标严重得多。 */
  .chat-head { gap: 6px; padding: 0 10px; }
  .chat-head__title { font-size: var(--fs-headline); }
  #btn-head-sound, #btn-head-lock { display: none; }
  .chat-head__members { max-width: 34vw; }
}

/* ==========================================================================
 * 关键帧（设计稿定义的水下动效；放这里是为了组件层不重复声明）
 * ========================================================================*/

/* ⚠️ `floatUp` 关键帧已搬进 js/ui/motion.js（`floatUpAt`，画布执行）——
   别再在这里加回来：CSS 常驻动画会把出帧锁在 60fps（见 .ambient 的注释）。 */

@keyframes causticShimmer {
  0%   { background-position: 0% 50%; }
  50%  { background-position: 100% 50%; }
  100% { background-position: 0% 50%; }
}

/* ⚠️ `radarPing` keyframes 已删除：在线光点的环改由 motion.js 每 ~83ms 写 `--ping`
   驱动（transform/opacity 在 components.css 里算）。别加回 CSS 常驻动画。 */

/* 消息弹入（设计稿 popInBounce） */
@keyframes popInBounce {
  0%   { opacity: 0; transform: scale(.85) translateY(12px); }
  60%  { opacity: 1; transform: scale(1.03) translateY(-2px); }
  100% { opacity: 1; transform: scale(1) translateY(0); }
}

/* 头像悬停时的海绵摆动（设计稿 spongeWiggle） */
@keyframes spongeWiggle {
  0%, 100% { transform: rotate(0deg) scale(1); }
  25%      { transform: rotate(-5deg) scale(1.06); }
  75%      { transform: rotate(5deg) scale(1.06); }
}

/* 进度条高光扫过（设计稿 progressSheen） */
@keyframes progressSheen {
  0%   { background-position: -200% 0; }
  100% { background-position: 200% 0; }
}

@keyframes pulse { 0%, 100% { opacity: 1; } 50% { opacity: .25; } }

/* 尊重系统的"减少动态效果"——水下动效很多，必须给一个静音开关。
   否则前庭敏感的用户会被满屏上浮的气泡晃到。 */
@media (prefers-reduced-motion: reduce) {
  .chat { animation: none; }
  .ambient { display: none; }
  .radar-ring { animation: none; }
  .animate-pop-in { animation: none; }
}
