/* =============================================================================
   澄光 · 设计系统 v1.0 [2026-10-21]
   -----------------------------------------------------------------------------
   这一层只做三件事，且必须是「全站最后加载」的样式表（见 index.html / admin.html
   的 link 顺序）：
     1) 令牌（design tokens）：颜色 / 字号 / 间距 / 圆角 / 阴影 / 动效 全部变量化
     2) 基础层：字体、排版、选中态、焦点环、滚动条、可访问性降级
     3) 组件层：按钮 / 输入框 / 卡片 / 导航 / 标签 / 表格 / 浮层 的统一长相

   为什么变量写在 :root 与 html[data-theme="dark"] 上：
   本站历史上有过「外部 CSS 的 [data-theme] 被更晚加载的 :root 压住」的坑，
   统一用 html[data-theme=...] 提权 + 本文件最后加载，两头都堵住。

   命名约定：
     --surface-*  表面（越往后越"高"，越大越不透）
     --text-*     文字层级（1 最深 → 4 只做装饰）
     --border-*   描边
     --brand-*    品牌色；--accent-* 辅助色；--ok/--warn/--danger/--info 语义色
     --r-*        圆角；--sp-* 间距；--fs-*/--lh-*/--ls-*/--fw-* 排版；--dur-*/--ease-* 动效
   所有文字色都按「叠在玻璃上的合成底色」实测过对比度，见 qa/contrast-tokens.js。
   ========================================================================== */

/* ---------------------------------------------------------------------------
   0. 字体：Inter 只覆盖拉丁字母与数字（48KB，本地托管，PWA 离线可用）。
      中文继续走系统字体（苹方 / 微软雅黑 / HarmonyOS Sans），逐字回退。
   --------------------------------------------------------------------------- */
@font-face {
  font-family: 'Inter var';
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url('/assets/fonts/inter-latin-var.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
                 U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122,
                 U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

/* ===========================================================================
   1. 令牌 · 浅色（默认）
   -------------------------------------------------------------------------
   设计意图：白天的「柔光玻璃」不是白纸，而是**有色温的雾面**。
   画布铺靛蓝 / 藕紫 / 湖蓝三团柔光，玻璃面板透明度压到 46%，
   这样叠起来仍能看见底下的光，而不是一整片死白。
   =========================================================================== */
:root {
  color-scheme: light;

  /* ---- 1.1 品牌与语义色 ---------------------------------------------- */
  /* 品牌：澄光靛 #5265d0 —— 白字对比度 5.08:1，作为正文色 4.69:1，两用都过 AA */
  --brand:          #5265d0;
  --brand-strong:   #4354bb;          /* hover / 按下 */
  --brand-ink:      #4b5cc4;          /* 品牌色文字 */
  --brand-contrast: #ffffff;          /* 品牌色上的文字 */
  --brand-soft:     rgba(82, 101, 208, 0.12);
  --brand-soft-2:   rgba(82, 101, 208, 0.20);
  --brand-line:     rgba(82, 101, 208, 0.32);
  --brand-grad:     linear-gradient(135deg, #5265d0 0%, #7a5bd0 100%);

  /* 辅助：藕紫 #7c5cd6，只用于渐变收尾与强调点，不承担正文 */
  --accent:         #7c5cd6;
  --accent-ink:     #6b4bc4;
  --accent-soft:    rgba(124, 92, 214, 0.13);

  /* 语义色：文字用途，全部 ≥ 4.5:1（叠在玻璃上实测） */
  --ok:             #0f7a58;
  --ok-soft:        rgba(15, 122, 88, 0.12);
  --ok-line:        rgba(15, 122, 88, 0.30);
  --warn:           #96550a;
  --warn-soft:      rgba(150, 85, 10, 0.12);
  --warn-line:      rgba(150, 85, 10, 0.30);
  --danger:         #bd3535;
  --danger-soft:    rgba(189, 53, 53, 0.10);
  --danger-line:    rgba(189, 53, 53, 0.30);
  /* 自己气泡的底色跟着主题色走，不写死靛紫 */
  --bubble-mine-bg: linear-gradient(135deg, rgba(150, 170, 248, 0.72), rgba(184, 160, 248, 0.66));
  --bubble-mine-fg: #17233f;
  --badge-bg:       #c93a4a;
  --badge-fg:       #ffffff;
  --info:           #2f6fb5;
  --info-soft:      rgba(47, 111, 181, 0.12);
  --info-line:      rgba(47, 111, 181, 0.30);

  /* ---- 1.2 表面与描边 ------------------------------------------------ */
  /* 画布：三团柔光 + 冷调渐变底，给玻璃提供可透视的"光源" */
  --bg-canvas:
    radial-gradient(1200px 820px at 6% 4%,  #d3e1ff 0%, rgba(211, 225, 255, 0) 62%),
    radial-gradient(1000px 780px at 102% 104%, #e2d1ff 0%, rgba(226, 209, 255, 0) 60%),
    radial-gradient(900px 620px at 62% 14%, #d7eaff 0%, rgba(215, 234, 255, 0) 58%),
    linear-gradient(160deg, #e9eff9 0%, #e2e9f4 46%, #dae2ef 100%);

  --surface-1:      rgba(255, 255, 255, 0.54);   /* 主面板 / 侧栏 / 大卡 */
  --surface-2:      rgba(255, 255, 255, 0.68);   /* 抬升：输入框、次级按钮、表头 */
  --surface-3:      rgba(253, 254, 255, 0.97);   /* 浮层：菜单、气泡弹层（几乎不透） */
  --surface-sunken: rgba(232, 238, 249, 0.55);   /* 凹陷：日志、代码、轨道底 */
  --surface-hover:  rgba(255, 255, 255, 0.66);
  --surface-active: rgba(255, 255, 255, 0.82);

  --border-glass:   rgba(255, 255, 255, 0.72);   /* 玻璃边缘的内高光 */
  --border-line:    rgba(80, 100, 138, 0.18);    /* 真实发丝线：表格、分隔 */
  --border-strong:  rgba(88, 108, 145, 0.28);
  --divider:        rgba(88, 108, 145, 0.12);

  --overlay:        rgba(19, 27, 45, 0.34);      /* 遮罩 */
  --overlay-blur:   4px;

  /* ---- 1.3 文字层级 -------------------------------------------------- */
  --text-1: #16202f;   /* 15.1:1 标题/正文主力 */
  --text-2: #46586f;   /*  6.7:1 次级说明 */
  --text-3: #55627c;   /*  5.7:1 元信息/时间戳（叠在品牌选中底上仍有 4.9:1）—— 原站用 #94a3b8 只有 2.6:1 */
  --text-4: #62718a;   /*  4.6:1 仅用于图标/分隔等非文本元素（非文本要求 3:1，这里给足余量） */
  --text-inverse: #ffffff;

  /* ---- 1.4 玻璃与层次 ------------------------------------------------ */
  --glass-blur: 26px;
  --glass-blur-lg: 34px;
  --glass-saturate: 150%;
  --glass-highlight: inset 0 1px 0 rgba(255, 255, 255, 0.92);

  /* ---- 1.5 圆角 ------------------------------------------------------ */
  --r-xs: 6px;    /* 标签、内联小块 */
  --r-sm: 9px;    /* 小按钮、图标钮 */
  --r-md: 12px;   /* 输入框、菜单项 */
  --r-lg: 16px;   /* 次级卡片、气泡小图 */
  --r-xl: 22px;   /* 卡片、顶栏 */
  --r-2xl: 28px;  /* 大面板、弹窗 */
  --r-full: 999px;

  /* ---- 1.6 间距（4px 基准） ------------------------------------------ */
  --sp-1: 4px;   --sp-2: 8px;   --sp-3: 12px;  --sp-4: 16px;
  --sp-5: 20px;  --sp-6: 24px;  --sp-8: 32px;  --sp-10: 40px;
  --sp-12: 48px; --sp-16: 64px;
  --gutter: 18px;                 /* 页面外边距，随视口微调 */

  /* ---- 1.7 排版 ------------------------------------------------------ */
  --font-sans: 'Inter var', -apple-system, BlinkMacSystemFont, 'Segoe UI',
               'PingFang SC', 'HarmonyOS Sans SC', 'Microsoft YaHei',
               'Source Han Sans SC', system-ui, sans-serif;
  --font-mono: ui-monospace, 'SF Mono', SFMono-Regular, Menlo, Consolas,
               'Liberation Mono', monospace;

  --fs-2xs: 11px;    /* 角标、极小注释（并入 11 档，不再用 10.5） */
  --fs-xs:  11.5px;  /* 元信息、时间戳 */
  --fs-sm:  12.5px;  /* 表格、次级按钮 */
  --fs-base: 13.5px; /* 正文 */
  --fs-md:  14.5px;  /* 强调正文、消息 */
  --fs-lg:  16px;    /* 卡片标题、页面副标题 */
  --fs-xl:  18px;    /* 区块标题 */
  --fs-2xl: 22px;    /* 页面主标题 */
  --fs-3xl: 28px;    /* 数据大字 */
  --fs-4xl: 34px;    /* 首屏展示字 */

  --lh-tight: 1.2;
  --lh-snug: 1.4;
  --lh-normal: 1.6;
  --lh-relaxed: 1.75;

  --ls-tight: -0.015em;
  --ls-normal: 0;
  --ls-wide: 0.04em;
  --ls-caps: 0.06em;          /* 中文标签不用 0.12em：字距过大反而散 */

  --fw-regular: 400;
  --fw-medium: 500;
  --fw-semibold: 600;
  --fw-bold: 700;

  /* ---- 1.8 阴影（三层递进：贴地 → 悬浮 → 浮层 → 全景） ---------------- */
  --shadow-1: 0 1px 2px rgba(23, 34, 56, 0.06), 0 1px 1px rgba(23, 34, 56, 0.03);
  --shadow-2: 0 6px 16px rgba(38, 55, 90, 0.09), 0 1px 3px rgba(38, 55, 90, 0.06);
  --shadow-3: 0 16px 40px rgba(38, 55, 90, 0.13), 0 2px 6px rgba(38, 55, 90, 0.06);
  --shadow-4: 0 28px 70px rgba(30, 45, 75, 0.20), 0 4px 12px rgba(30, 45, 75, 0.08);
  --shadow-glass: 0 22px 58px rgba(64, 86, 138, 0.16);
  --shadow-brand: 0 8px 20px rgba(82, 101, 208, 0.28);

  /* ---- 1.9 动效 ------------------------------------------------------ */
  --dur-1: 120ms;   /* 按下、hover 微反馈 */
  --dur-2: 180ms;   /* 常规过渡 */
  --dur-3: 280ms;   /* 浮层进出 */
  --dur-4: 420ms;   /* 页面级 */
  --ease-out: cubic-bezier(0.16, 1, 0.3, 1);
  --ease-standard: cubic-bezier(0.2, 0.8, 0.2, 1);
  --ease-spring: cubic-bezier(0.34, 1.56, 0.64, 1);

  /* ---- 1.10 层级 ----------------------------------------------------- */
  --z-sticky: 30;
  --z-menu: 60;
  --z-overlay: 80;
  --z-modal: 90;
  --z-toast: 100;
  --z-max: 9999;

  /* ---- 1.11 焦点环（键盘可见，鼠标不打扰） --------------------------- */
  --focus-ring: 0 0 0 3px rgba(82, 101, 208, 0.36);
  --focus-ring-danger: 0 0 0 3px rgba(189, 53, 53, 0.30);

  /* ---- 1.12 兼容别名 -------------------------------------------------
     站内历史样式大量使用这些名字（app.css / enhance.css / admin.css）。
     保留别名 = 老规则不用改也能吃到新配色，避免"改一处崩一处"。 */
  --ink: var(--text-1);
  --muted: var(--text-3);
  --glass: var(--surface-1);
  --glass-2: var(--surface-2);
  --line: var(--border-glass);
  --accent-legacy: var(--brand);
  --radius: var(--r-xl);
  --shadow: var(--shadow-glass), var(--glass-highlight);
}

/* ===========================================================================
   2. 令牌 · 深色
   -------------------------------------------------------------------------
   深色不是浅色反相：底是带冷调的近黑（#080b13），玻璃只有 5.5% 白，
   靠三层冷光（靛 / 紫 / 青）把面板"托"出来。
   光晕透明度一旦超过 0.3 整屏发紫，这里控制在 0.16~0.22。
   =========================================================================== */
html[data-theme='dark'] {
  color-scheme: dark;

  --brand:          #8b9bff;
  --brand-strong:   #a3b0ff;
  --brand-ink:      #aeb9ff;
  --brand-contrast: #0b1020;          /* 亮品牌色上用深字（7.4:1） */
  --brand-soft:     rgba(139, 155, 255, 0.16);
  --brand-soft-2:   rgba(139, 155, 255, 0.26);
  --brand-line:     rgba(139, 155, 255, 0.34);
  /* 深色下品牌是亮色块，渐变也走亮色、配深字（10:1）；
     原来这里是深紫渐变 + 深字，实测只有 3:1 —— 顺手修正。 */
  --brand-grad:     linear-gradient(135deg, #a3b2ff 0%, #c4b2ff 100%);

  --accent:         #b79bff;
  --accent-ink:     #c3acff;
  --accent-soft:    rgba(183, 155, 255, 0.16);

  --ok:             #45d6a0;
  --ok-soft:        rgba(69, 214, 160, 0.14);
  --ok-line:        rgba(69, 214, 160, 0.32);
  --warn:           #f3b969;
  --warn-soft:      rgba(243, 185, 105, 0.14);
  --warn-line:      rgba(243, 185, 105, 0.32);
  --danger:         #ff8f8f;
  --danger-soft:    rgba(255, 143, 143, 0.14);
  --danger-line:    rgba(255, 143, 143, 0.32);
  --bubble-mine-bg: linear-gradient(135deg, rgba(84, 99, 208, 0.94), rgba(104, 80, 198, 0.90));
  --bubble-mine-fg: #ffffff;
  --badge-bg:       #c2374a;
  --badge-fg:       #ffffff;
  --info:           #7fb6f5;
  --info-soft:      rgba(127, 182, 245, 0.14);
  --info-line:      rgba(127, 182, 245, 0.32);

  --bg-canvas:
    radial-gradient(1100px 760px at 8% 4%,   rgba(94, 104, 232, 0.20), transparent 58%),
    radial-gradient(900px 660px at 104% 106%, rgba(138, 84, 214, 0.14), transparent 56%),
    radial-gradient(820px 560px at 56% 12%,  rgba(56, 148, 210, 0.10), transparent 56%),
    linear-gradient(168deg, #0a0d18 0%, #080b13 46%, #06080e 100%);

  --surface-1:      rgba(255, 255, 255, 0.055);
  --surface-2:      rgba(255, 255, 255, 0.085);
  --surface-3:      rgba(26, 30, 44, 0.92);
  --surface-sunken: rgba(0, 0, 0, 0.28);
  --surface-hover:  rgba(255, 255, 255, 0.075);
  --surface-active: rgba(255, 255, 255, 0.11);

  --border-glass:   rgba(255, 255, 255, 0.115);
  --border-line:    rgba(255, 255, 255, 0.09);
  --border-strong:  rgba(255, 255, 255, 0.20);
  --divider:        rgba(255, 255, 255, 0.07);

  --overlay:        rgba(4, 6, 12, 0.60);

  --text-1: #eef1fa;   /* 15.7:1 */
  --text-2: #b3bfd4;   /*  9.6:1 */
  --text-3: #94a2ba;   /*  6.9:1 */
  --text-4: #7c89a1;   /*  5.2:1 */
  --text-inverse: #0b1020;

  --glass-blur: 30px;
  --glass-saturate: 150%;
  --glass-highlight: inset 0 1px 0 rgba(255, 255, 255, 0.10);

  --shadow-1: 0 1px 2px rgba(0, 0, 0, 0.45);
  --shadow-2: 0 8px 20px rgba(0, 0, 0, 0.45), 0 1px 2px rgba(0, 0, 0, 0.3);
  --shadow-3: 0 18px 44px rgba(0, 0, 0, 0.50), 0 2px 8px rgba(0, 0, 0, 0.35);
  --shadow-4: 0 32px 80px rgba(0, 0, 0, 0.60), 0 6px 18px rgba(0, 0, 0, 0.4);
  --shadow-glass: 0 30px 76px rgba(0, 0, 0, 0.55);
  --shadow-brand: 0 10px 26px rgba(72, 78, 200, 0.40);

  --focus-ring: 0 0 0 3px rgba(139, 155, 255, 0.42);
  --focus-ring-danger: 0 0 0 3px rgba(255, 143, 143, 0.36);
}

/* ===========================================================================
   2.5 主题色（「设置 → 外观 → 主题色」）
   -------------------------------------------------------------------------
   只覆盖品牌一组令牌，组件 / 页面一行都不用改。规则：
     · 浅色：深一档的品牌色，白字 ≥ 4.9:1（按钮、渐变、气泡都按这个算过）
     · 深色：亮一档的品牌色，配深字 ≥ 9:1
     · 默认靛蓝就是 :root 里的值，不需要 data-accent
   主题色只改"品牌"，语义色（成功/警告/危险）永远不动 —— 红还是红，绿还是绿。
   =========================================================================== */

/* --- 藕紫 --- */
[data-accent='violet'] {
  --brand: #7b4fc8;
  --brand-strong: #6a41b4;
  --brand-ink: #6a3fb8;
  --brand-contrast: #ffffff;
  --brand-soft: rgba(123, 79, 200, 0.13);
  --brand-soft-2: rgba(123, 79, 200, 0.22);
  --brand-line: rgba(123, 79, 200, 0.34);
  --brand-grad: linear-gradient(135deg, #7b4fc8 0%, #9658cf 100%);
  --accent: #a24ac9;
  --accent-ink: #8f3fae;
  --accent-soft: rgba(162, 74, 201, 0.13);
  --bubble-mine-bg: linear-gradient(135deg, rgba(160, 124, 236, 0.72), rgba(196, 138, 240, 0.64));
  --bubble-mine-fg: #241a3d;
  --focus-ring: 0 0 0 3px rgba(123, 79, 200, 0.36);
  --shadow-brand: 0 8px 20px rgba(123, 79, 200, 0.28);
}
html[data-theme='dark'][data-accent='violet'] {
  --brand: #b18cff;
  --brand-strong: #c7adff;
  --brand-ink: #c7adff;
  --brand-contrast: #0b1020;
  --brand-soft: rgba(177, 140, 255, 0.16);
  --brand-soft-2: rgba(177, 140, 255, 0.26);
  --brand-line: rgba(177, 140, 255, 0.34);
  --brand-grad: linear-gradient(135deg, #b18cff 0%, #d3b6ff 100%);
  --accent: #d0a0ff;
  --accent-ink: #dcbbff;
  --accent-soft: rgba(208, 160, 255, 0.16);
  --bubble-mine-bg: linear-gradient(135deg, rgba(112, 80, 190, 0.94), rgba(140, 95, 205, 0.90));
  --bubble-mine-fg: #ffffff;
  --focus-ring: 0 0 0 3px rgba(177, 140, 255, 0.42);
  --shadow-brand: 0 10px 26px rgba(120, 80, 200, 0.40);
}

/* --- 青碧 --- */
[data-accent='teal'] {
  --brand: #12756f;
  --brand-strong: #0d645f;
  --brand-ink: #0d6a64;
  --brand-contrast: #ffffff;
  --brand-soft: rgba(18, 117, 111, 0.13);
  --brand-soft-2: rgba(18, 117, 111, 0.22);
  --brand-line: rgba(18, 117, 111, 0.34);
  --brand-grad: linear-gradient(135deg, #12756f 0%, #1b8090 100%);
  --accent: #0f8f9e;
  --accent-ink: #0b7c88;
  --accent-soft: rgba(15, 143, 158, 0.13);
  --bubble-mine-bg: linear-gradient(135deg, rgba(118, 206, 198, 0.68), rgba(150, 214, 220, 0.58));
  --bubble-mine-fg: #10322f;
  --focus-ring: 0 0 0 3px rgba(18, 117, 111, 0.36);
  --shadow-brand: 0 8px 20px rgba(18, 117, 111, 0.26);
}
html[data-theme='dark'][data-accent='teal'] {
  --brand: #5fd6cd;
  --brand-strong: #86e3dc;
  --brand-ink: #86e3dc;
  --brand-contrast: #0b1020;
  --brand-soft: rgba(95, 214, 205, 0.16);
  --brand-soft-2: rgba(95, 214, 205, 0.26);
  --brand-line: rgba(95, 214, 205, 0.34);
  --brand-grad: linear-gradient(135deg, #5fd6cd 0%, #8fe6df 100%);
  --accent: #7fe6da;
  --accent-ink: #9dede2;
  --accent-soft: rgba(127, 230, 218, 0.16);
  --bubble-mine-bg: linear-gradient(135deg, rgba(20, 120, 120, 0.94), rgba(28, 135, 150, 0.90));
  --bubble-mine-fg: #ffffff;
  --focus-ring: 0 0 0 3px rgba(95, 214, 205, 0.42);
  --shadow-brand: 0 10px 26px rgba(20, 120, 120, 0.40);
}

/* --- 琥珀 --- */
[data-accent='amber'] {
  --brand: #96610e;
  --brand-strong: #84550c;
  --brand-ink: #87560c;
  --brand-contrast: #ffffff;
  --brand-soft: rgba(150, 97, 14, 0.13);
  --brand-soft-2: rgba(150, 97, 14, 0.22);
  --brand-line: rgba(150, 97, 14, 0.34);
  --brand-grad: linear-gradient(135deg, #96610e 0%, #9a660f 100%);
  --accent: #b57a14;
  --accent-ink: #8f5f0c;
  --accent-soft: rgba(181, 122, 20, 0.14);
  --bubble-mine-bg: linear-gradient(135deg, rgba(232, 190, 120, 0.72), rgba(240, 206, 150, 0.62));
  --bubble-mine-fg: #3a2606;
  --focus-ring: 0 0 0 3px rgba(150, 97, 14, 0.34);
  --shadow-brand: 0 8px 20px rgba(150, 97, 14, 0.26);
}
html[data-theme='dark'][data-accent='amber'] {
  --brand: #f0be6a;
  --brand-strong: #f7d094;
  --brand-ink: #f7d094;
  --brand-contrast: #0b1020;
  --brand-soft: rgba(240, 190, 106, 0.16);
  --brand-soft-2: rgba(240, 190, 106, 0.26);
  --brand-line: rgba(240, 190, 106, 0.34);
  --brand-grad: linear-gradient(135deg, #f0be6a 0%, #f9d79c 100%);
  --accent: #ffd08a;
  --accent-ink: #ffdca8;
  --accent-soft: rgba(255, 208, 138, 0.16);
  --bubble-mine-bg: linear-gradient(135deg, rgba(146, 96, 18, 0.94), rgba(160, 112, 26, 0.92));
  --bubble-mine-fg: #ffffff;
  --focus-ring: 0 0 0 3px rgba(240, 190, 106, 0.42);
  --shadow-brand: 0 10px 26px rgba(150, 100, 20, 0.40);
}

/* --- 玫红 --- */
[data-accent='rose'] {
  --brand: #b23b60;
  --brand-strong: #9d3455;
  --brand-ink: #a03256;
  --brand-contrast: #ffffff;
  --brand-soft: rgba(178, 59, 96, 0.13);
  --brand-soft-2: rgba(178, 59, 96, 0.22);
  --brand-line: rgba(178, 59, 96, 0.34);
  --brand-grad: linear-gradient(135deg, #b23b60 0%, #c14a70 100%);
  --accent: #cf4f7a;
  --accent-ink: #b03e66;
  --accent-soft: rgba(207, 79, 122, 0.13);
  --bubble-mine-bg: linear-gradient(135deg, rgba(240, 150, 180, 0.70), rgba(246, 178, 196, 0.62));
  --bubble-mine-fg: #3a1424;
  --focus-ring: 0 0 0 3px rgba(178, 59, 96, 0.34);
  --shadow-brand: 0 8px 20px rgba(178, 59, 96, 0.26);
}
html[data-theme='dark'][data-accent='rose'] {
  --brand: #ff9ab5;
  --brand-strong: #ffb8cb;
  --brand-ink: #ffb8cb;
  --brand-contrast: #0b1020;
  --brand-soft: rgba(255, 154, 181, 0.16);
  --brand-soft-2: rgba(255, 154, 181, 0.26);
  --brand-line: rgba(255, 154, 181, 0.34);
  --brand-grad: linear-gradient(135deg, #ff9ab5 0%, #ffc2d2 100%);
  --accent: #ffb0c6;
  --accent-ink: #ffc9d8;
  --accent-soft: rgba(255, 176, 198, 0.16);
  --bubble-mine-bg: linear-gradient(135deg, rgba(160, 50, 80, 0.94), rgba(185, 65, 100, 0.90));
  --bubble-mine-fg: #ffffff;
  --focus-ring: 0 0 0 3px rgba(255, 154, 181, 0.42);
  --shadow-brand: 0 10px 26px rgba(160, 50, 80, 0.40);
}

/* ===========================================================================
   2.6 外观风格 · 伤感秋天落叶（data-skin="autumn"）
   -------------------------------------------------------------------------
   不是"把界面染成橘色"，而是换一套完整的气候：
     · 画布：低饱和的宣纸米色 + 三团琥珀/赭石柔光（浅色）/ 余烬暗褐（深色）
     · 品牌：枫橘 #ab5a1c → 赭石 #8f4f10（浅色白字 4.99:1；深色 #e8a24a 深字 8.6:1）
     · 文字：深褐墨 #3a2b20 … 枯草灰 #7c6450（最浅一档 4.85:1）
     · 玻璃：暖白而非冷白，阴影带褐色，像旧相纸
   动效与氛围层（飘叶 / 柔光 / 视差 / 点击涟漪）由 autumn.js 注入，令牌在这里定义。
   =========================================================================== */
html[data-skin='autumn'] {
  --brand: #ab5a1c;
  --brand-strong: #96490f;
  --brand-ink: #96491a;
  --brand-contrast: #fffaf2;
  --brand-soft: rgba(171, 90, 28, 0.12);
  --brand-soft-2: rgba(171, 90, 28, 0.20);
  --brand-line: rgba(171, 90, 28, 0.32);
  --brand-grad: linear-gradient(135deg, #ab5a1c 0%, #8f4f10 100%);

  --accent: #a8761a;
  --accent-ink: #8a5e0c;
  --accent-soft: rgba(168, 118, 26, 0.14);

  --ok: #456f33;
  --ok-soft: rgba(69, 111, 51, 0.12);
  --ok-line: rgba(69, 111, 51, 0.30);
  --warn: #8a5e0c;
  --warn-soft: rgba(138, 94, 12, 0.12);
  --warn-line: rgba(138, 94, 12, 0.30);
  --danger: #a33a2a;
  --danger-soft: rgba(163, 58, 42, 0.10);
  --danger-line: rgba(163, 58, 42, 0.30);
  --info: #5f6b7a;
  --info-soft: rgba(95, 107, 122, 0.12);
  --info-line: rgba(95, 107, 122, 0.30);

  --bubble-mine-bg: linear-gradient(135deg, rgba(214, 152, 94, 0.62), rgba(190, 120, 66, 0.52));
  --bubble-mine-fg: #2f1f12;
  --badge-bg: #a33a2a;
  --badge-fg: #fffaf2;

  /* 暖白玻璃：同一透明度，色温从冷白换成宣纸白 */
  --surface-1: rgba(255, 250, 242, 0.46);
  --surface-2: rgba(255, 250, 242, 0.62);
  --surface-3: rgba(253, 248, 240, 0.97);
  --surface-sunken: rgba(238, 226, 210, 0.55);
  --surface-hover: rgba(255, 250, 242, 0.68);
  --surface-active: rgba(255, 250, 242, 0.84);

  --border-glass: rgba(255, 252, 246, 0.74);
  --border-line: rgba(122, 92, 58, 0.20);
  --border-strong: rgba(122, 92, 58, 0.32);
  --divider: rgba(122, 92, 58, 0.14);

  --text-1: #3a2b20;
  --text-2: #5f4a37;
  --text-3: #755c49;   /* 5.3:1（叠在品牌选中的暖底上仍有 4.76） */
  --text-4: #7c6450;
  --text-inverse: #fffaf2;

  --bg-canvas:
    radial-gradient(1200px 820px at 8% 4%, #f8e2bf 0%, rgba(248, 226, 191, 0) 62%),
    radial-gradient(1000px 780px at 102% 104%, #e9d0b6 0%, rgba(233, 208, 182, 0) 60%),
    radial-gradient(900px 620px at 62% 16%, #f2e7d2 0%, rgba(242, 231, 210, 0) 58%),
    linear-gradient(160deg, #f4ecdf 0%, #ece1d0 46%, #e3d6c2 100%);

  --shadow-glass: 0 22px 58px rgba(88, 58, 30, 0.16);
  --shadow-brand: 0 8px 20px rgba(171, 90, 28, 0.28);
  --focus-ring: 0 0 0 3px rgba(171, 90, 28, 0.36);
  --focus-ring-danger: 0 0 0 3px rgba(163, 58, 42, 0.30);
  --glass-highlight: inset 0 1px 0 rgba(255, 252, 246, 0.94);
  --overlay: rgba(58, 43, 32, 0.34);

  /* 叶片 / 氛围层（autumn.js 读取这些令牌绘制，避免 JS 里再写一套色值） */
  --leaf-1: #c9762b;
  --leaf-2: #b8862f;
  --leaf-3: #9a5a2a;
  --leaf-4: #7d5a35;
  --leaf-5: #d8a24a;
  --leaf-opacity: 0.58;
  --ambient-1: rgba(255, 196, 120, 0.30);
  --ambient-2: rgba(226, 150, 84, 0.22);
  --ambient-3: rgba(255, 226, 170, 0.20);
}

html[data-theme='dark'][data-skin='autumn'] {
  --brand: #e8a24a;
  --brand-strong: #f0b768;
  --brand-ink: #f0b768;
  --brand-contrast: #1a1208;
  --brand-soft: rgba(232, 162, 74, 0.16);
  --brand-soft-2: rgba(232, 162, 74, 0.26);
  --brand-line: rgba(232, 162, 74, 0.34);
  --brand-grad: linear-gradient(135deg, #e8a24a 0%, #f2c078 100%);

  --accent: #d9b26a;
  --accent-ink: #e8c98f;
  --accent-soft: rgba(217, 178, 106, 0.16);

  --ok: #a8c47a;
  --ok-soft: rgba(168, 196, 122, 0.14);
  --ok-line: rgba(168, 196, 122, 0.32);
  --warn: #ecc06e;
  --warn-soft: rgba(236, 192, 110, 0.14);
  --warn-line: rgba(236, 192, 110, 0.32);
  --danger: #ef8f7a;
  --danger-soft: rgba(239, 143, 122, 0.14);
  --danger-line: rgba(239, 143, 122, 0.32);
  --info: #a9bfd0;
  --info-soft: rgba(169, 191, 208, 0.14);
  --info-line: rgba(169, 191, 208, 0.32);

  --bubble-mine-bg: linear-gradient(135deg, rgba(126, 58, 24, 0.94), rgba(154, 76, 30, 0.90));
  --bubble-mine-fg: #fff8ef;
  --badge-bg: #b8432f;
  --badge-fg: #fff8ef;

  --surface-1: rgba(255, 244, 232, 0.048);
  --surface-2: rgba(255, 244, 232, 0.075);
  --surface-3: rgba(30, 25, 20, 0.94);
  --surface-sunken: rgba(0, 0, 0, 0.28);
  --surface-hover: rgba(255, 244, 232, 0.075);
  --surface-active: rgba(255, 244, 232, 0.11);

  --border-glass: rgba(255, 240, 224, 0.11);
  --border-line: rgba(255, 240, 224, 0.09);
  --border-strong: rgba(255, 240, 224, 0.18);
  --divider: rgba(255, 240, 224, 0.07);

  --text-1: #f6ede2;
  --text-2: #cbb8a4;
  --text-3: #b09b85;   /* 6.7:1（叠在品牌选中的暖底上 4.9） */
  --text-4: #9a8672;
  --text-inverse: #1a1208;

  --bg-canvas:
    radial-gradient(1100px 760px at 8% 4%, rgba(198, 112, 46, 0.20), transparent 58%),
    radial-gradient(900px 660px at 104% 106%, rgba(146, 72, 28, 0.14), transparent 56%),
    radial-gradient(820px 560px at 56% 12%, rgba(96, 62, 32, 0.16), transparent 56%),
    linear-gradient(168deg, #17110c 0%, #100c09 46%, #0b0806 100%);

  --shadow-glass: 0 30px 76px rgba(0, 0, 0, 0.55);
  --shadow-brand: 0 10px 26px rgba(130, 70, 25, 0.42);
  --focus-ring: 0 0 0 3px rgba(232, 162, 74, 0.42);
  --focus-ring-danger: 0 0 0 3px rgba(239, 143, 122, 0.36);
  --glass-highlight: inset 0 1px 0 rgba(255, 240, 224, 0.10);
  --overlay: rgba(6, 4, 3, 0.62);

  --leaf-1: #d98a3c;
  --leaf-2: #c99a45;
  --leaf-3: #a86a38;
  --leaf-4: #8a6540;
  --leaf-5: #e6b463;
  --leaf-opacity: 0.46;
  --ambient-1: rgba(198, 112, 46, 0.26);
  --ambient-2: rgba(146, 72, 28, 0.18);
  --ambient-3: rgba(232, 162, 74, 0.10);
}

/* ---------- 秋天氛围层（#autumn-fx 由 autumn.js 注入到 <html> 下） ----------
   放在 html 层而不是 body：renderApp() 会整体替换 body.innerHTML，
   挂在 body 里会被登录/登出/改资料时顺手抹掉。 */
html[data-skin='autumn'] {
  background-color: #f4ecdf;
  background-image: var(--bg-canvas);
  background-attachment: fixed;
}
html[data-theme='dark'][data-skin='autumn'] { background-color: #17110c; }
/* body 让出背景：画布移到 <html>，这样 #autumn-fx（html 的子元素、z-index:0）
   能落在"背景之上、内容之下"——叶子从磨砂玻璃后面飘过，而不是盖在文字上。 */
html[data-skin='autumn'] body { position: relative; z-index: 1; background: transparent !important; }
#autumn-fx {
  position: fixed;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  overflow: hidden;
  contain: strict;
}
#autumn-fx .autumn-ambient {
  position: absolute;
  inset: -12vh -12vw;
  background:
    radial-gradient(38vw 30vw at 18% 12%, var(--ambient-1), transparent 62%),
    radial-gradient(32vw 26vw at 82% 78%, var(--ambient-2), transparent 60%),
    radial-gradient(26vw 22vw at 62% 30%, var(--ambient-3), transparent 60%);
  filter: blur(10px) saturate(105%);
  transform: translate3d(0, calc(var(--autumn-shift, 0) * 1px), 0);
  will-change: transform;
  animation: autumn-breathe 46s ease-in-out infinite alternate;
}
@keyframes autumn-breathe {
  from { opacity: 0.78; scale: 1; }
  to   { opacity: 1; scale: 1.04; }
}
/* 叶片单独一层、盖在内容之上：
   玻璃面板有 backdrop-filter，放在它背后的叶片会被模糊成一片色斑，
   所以叶片必须在上层（z-index 2），但用 pointer-events:none + 低不透明度，
   不挡点击、不遮文字。菜单/弹窗（z-index ≥60）仍然盖住叶片。 */
#autumn-leaves {
  position: fixed;
  inset: 0;
  z-index: 2;
  pointer-events: none;
  overflow: hidden;
  contain: strict;
}
#autumn-leaves canvas {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  opacity: var(--leaf-opacity, 0.55);
}
/* 用户要求"减弱动效"或系统开启减少动态时：氛围层保留（静态光），叶片与动画全部停掉 */
html[data-motion='reduced'] #autumn-fx .autumn-ambient { animation: none; transform: none; }
html[data-motion='reduced'] #autumn-leaves { display: none; }
@media (prefers-reduced-motion: reduce) {
  #autumn-fx .autumn-ambient { animation: none; transform: none; }
  #autumn-leaves { display: none; }
}

/* ---------- 点击反馈：暖色涟漪 + 落叶散开 ---------- */
.autumn-ripple {
  position: fixed;
  width: 14px; height: 14px;
  margin: -7px 0 0 -7px;
  border-radius: 50%;
  border: 1px solid var(--brand-line);
  background: radial-gradient(circle, rgba(255, 196, 130, 0.34), rgba(255, 196, 130, 0) 70%);
  pointer-events: none;
  z-index: var(--z-max);
  transform: scale(0.2);
  opacity: 0.9;
  animation: autumn-ripple 520ms var(--ease-out) forwards;
}
@keyframes autumn-ripple {
  to { transform: scale(9); opacity: 0; }
}
.autumn-bit {
  position: fixed;
  width: 9px; height: 9px;
  margin: -4px 0 0 -4px;
  border-radius: 62% 4% 62% 4%;
  background: var(--bit-color, #b06a2c);
  opacity: 0.9;
  pointer-events: none;
  z-index: var(--z-max);
  animation: autumn-bit 680ms cubic-bezier(0.16, 1, 0.3, 1) forwards;
}
@keyframes autumn-bit {
  0%   { transform: translate3d(0, 0, 0) rotate(0deg) scale(1); opacity: 0.95; }
  70%  { opacity: 0.75; }
  100% { transform: translate3d(var(--dx, 0), var(--dy, 0), 0) rotate(var(--rot, 90deg)) scale(0.6); opacity: 0; }
}
html[data-motion='reduced'] .autumn-ripple,
html[data-motion='reduced'] .autumn-bit,
.autumn-ripple.autumn-off,
.autumn-bit.autumn-off { display: none; }

/* ---------- 秋日下的细节：暖描边、旧相纸质感、按钮按压 ---------- */
html[data-skin='autumn'] .card:hover,
html[data-skin='autumn'] .ugroup:hover,
html[data-skin='autumn'] .stat:hover {
  border-color: var(--brand-line);
  box-shadow: var(--shadow-2), var(--glass-highlight);
}
html[data-skin='autumn'] .btn.primary:active {
  box-shadow: 0 2px 8px rgba(140, 74, 22, 0.32), inset 0 1px 0 rgba(255, 255, 255, 0.18);
}
html[data-skin='autumn'] .bubble.theirs {
  background: rgba(255, 250, 242, 0.70);
  border-color: rgba(255, 252, 246, 0.88);
}
html[data-theme='dark'][data-skin='autumn'] .bubble.theirs {
  background: rgba(255, 244, 232, 0.08);
  border-color: rgba(255, 240, 224, 0.09);
}
/* 日期分割线：暖色渐隐 */
html[data-skin='autumn'] .cx-date::before,
html[data-skin='autumn'] .cx-date::after {
  background: linear-gradient(90deg, transparent, rgba(150, 100, 60, 0.28) 22%, rgba(150, 100, 60, 0.28) 78%, transparent);
}
html[data-theme='dark'][data-skin='autumn'] .cx-date::before,
html[data-theme='dark'][data-skin='autumn'] .cx-date::after {
  background: linear-gradient(90deg, transparent, rgba(255, 210, 160, 0.18) 22%, rgba(255, 210, 160, 0.18) 78%, transparent);
}

/* 动效开关（「外观 → 动态效果」）：作用与系统级 prefers-reduced-motion 一致，
   只是把选择权交给用户 —— 有些人不改系统设置，但确实不想看动画。 */
html[data-motion='reduced'] *,
html[data-motion='reduced'] *::before,
html[data-motion='reduced'] *::after {
  animation-duration: 0.001ms !important;
  animation-iteration-count: 1 !important;
  transition-duration: 0.001ms !important;
  scroll-behavior: auto !important;
}
html[data-motion='reduced'] .btn:hover,
html[data-motion='reduced'] .stat:hover,
html[data-motion='reduced'] .file-card:hover,
html[data-motion='reduced'] .conv:hover { transform: none; }

/* ===========================================================================
   3. 基础层
   =========================================================================== */

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

html {
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
}

body {
  margin: 0;
  min-height: 100vh;
  color: var(--text-1);
  font-family: var(--font-sans);
  font-size: var(--fs-base);
  font-weight: var(--fw-regular);
  line-height: var(--lh-normal);
  letter-spacing: var(--ls-normal);
  background-color: #e4ebf6;
  background-image: var(--bg-canvas);
  background-attachment: fixed;
  background-repeat: no-repeat;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
  font-feature-settings: 'cv11', 'ss01';   /* Inter：单层 a / 单层 g，更接近苹果观感 */
  font-variant-numeric: tabular-nums;      /* 时间、计数、表格数字对齐 */
}
html[data-theme='dark'] body { background-color: #080b13; }

/* 标题：统一"字号收紧 + 字重 600"，避免到处 bold 导致层级糊成一片 */
h1, h2, h3, h4, h5 {
  margin: 0;
  color: var(--text-1);
  font-weight: var(--fw-semibold);
  line-height: var(--lh-tight);
  letter-spacing: var(--ls-tight);
}
h1 { font-size: var(--fs-2xl); }
h2 { font-size: var(--fs-xl); }
h3 { font-size: var(--fs-lg); }
h4 { font-size: var(--fs-base); }
p  { margin: 0 0 var(--sp-3); }

/* 链接与按钮的默认观感 */
a { color: var(--brand-ink); text-decoration: none; transition: color var(--dur-1) var(--ease-standard); }
a:hover { color: var(--brand-strong); }

button, input, textarea, select { font-family: inherit; font-size: inherit; color: inherit; }
button { -webkit-tap-highlight-color: transparent; }

::selection { background: var(--brand-soft-2); color: var(--text-1); }

/* 焦点：只给键盘用户画环，鼠标点击不出现（避免"到处发光"） */
:focus { outline: none; }
:focus-visible {
  outline: 2px solid var(--brand);
  outline-offset: 2px;
  border-radius: var(--r-sm);
}
input:focus-visible, textarea:focus-visible, select:focus-visible {
  outline: none;
}

/* 滚动条：细、半透明、两套主题都压得住 */
::-webkit-scrollbar { width: 10px; height: 10px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb {
  background: rgba(120, 138, 170, 0.34);
  border: 2px solid transparent;
  background-clip: padding-box;
  border-radius: var(--r-full);
}
::-webkit-scrollbar-thumb:hover { background: rgba(120, 138, 170, 0.55); background-clip: padding-box; }
html[data-theme='dark'] ::-webkit-scrollbar-thumb { background: rgba(150, 165, 195, 0.26); background-clip: padding-box; }
html[data-theme='dark'] ::-webkit-scrollbar-thumb:hover { background: rgba(150, 165, 195, 0.44); background-clip: padding-box; }

/* 图片默认不留缝、不撑破容器 */
img, video, canvas, svg { max-width: 100%; }
img { -webkit-user-drag: none; }

[hidden] { display: none !important; }

/* 只读文本（日志、代码、机器名）统一等宽 + 稍小 */
code, kbd, pre, samp {
  font-family: var(--font-mono);
  font-size: 0.92em;
}

/* ===========================================================================
   4. 通用排版工具类（页面里可直接用，比 Tailwind 的 text-slate-* 更语义化）
   =========================================================================== */
.t-display { font-size: var(--fs-3xl); font-weight: var(--fw-bold); letter-spacing: -0.02em; line-height: var(--lh-tight); }
.t-title   { font-size: var(--fs-2xl); font-weight: var(--fw-semibold); letter-spacing: var(--ls-tight); }
.t-h2      { font-size: var(--fs-lg);  font-weight: var(--fw-semibold); letter-spacing: -0.005em; }
.t-body    { font-size: var(--fs-base); line-height: var(--lh-normal); }
.t-meta    { font-size: var(--fs-xs);  color: var(--text-3); }
.t-caps    { font-size: var(--fs-2xs); font-weight: var(--fw-semibold); letter-spacing: var(--ls-caps); text-transform: uppercase; color: var(--text-3); }
.t-num     { font-variant-numeric: tabular-nums; font-feature-settings: 'tnum'; }

/* ===========================================================================
   5. 玻璃与容器
   =========================================================================== */
.glass {
  background: var(--surface-1);
  border: 1px solid var(--border-glass);
  box-shadow: var(--shadow-glass), var(--glass-highlight);
  -webkit-backdrop-filter: blur(var(--glass-blur)) saturate(var(--glass-saturate));
  backdrop-filter: blur(var(--glass-blur)) saturate(var(--glass-saturate));
}
.glass-soft {
  background: var(--surface-2);
  border: 1px solid var(--border-glass);
  box-shadow: var(--glass-highlight);
  -webkit-backdrop-filter: blur(18px) saturate(140%);
  backdrop-filter: blur(18px) saturate(140%);
}

.card {
  border-radius: var(--r-xl);
  background: var(--surface-1);
  border: 1px solid var(--border-glass);
  box-shadow: var(--shadow-glass), var(--glass-highlight);
  -webkit-backdrop-filter: blur(var(--glass-blur)) saturate(var(--glass-saturate));
  backdrop-filter: blur(var(--glass-blur)) saturate(var(--glass-saturate));
  padding: var(--sp-4) var(--sp-5);
}
.card + .card { margin-top: 0; }
.card-title {
  font-size: var(--fs-sm);
  font-weight: var(--fw-semibold);
  letter-spacing: var(--ls-wide);
  color: var(--text-1);
  margin: 0 0 var(--sp-3);
  display: flex;
  align-items: center;
  gap: var(--sp-2);
}
.card-title .hint {
  font-weight: var(--fw-regular);
  color: var(--text-3);
  font-size: var(--fs-xs);
  letter-spacing: 0;
}

/* ===========================================================================
   6. 按钮
   -------------------------------------------------------------------------
   尺寸：默认 34px 高（后台表格里够点），sm 26px，lg 40px，图标钮方形。
   状态：hover 抬 1px + 加深一档阴影；active 缩到 .97；disabled 半透明且不动；
        loading 用一个 CSS 转圈，不依赖图标字体。
   =========================================================================== */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--sp-2);
  min-height: 34px;
  padding: 0 14px;
  border-radius: var(--r-md);
  border: 1px solid var(--border-glass);
  background: var(--surface-2);
  color: var(--text-1);
  font-size: var(--fs-sm);
  font-weight: var(--fw-medium);
  letter-spacing: 0.005em;
  line-height: 1;
  white-space: nowrap;
  cursor: pointer;
  text-decoration: none;
  transition: transform var(--dur-1) var(--ease-standard),
              background-color var(--dur-2) var(--ease-standard),
              border-color var(--dur-2) var(--ease-standard),
              box-shadow var(--dur-2) var(--ease-standard),
              color var(--dur-2) var(--ease-standard);
  -webkit-backdrop-filter: blur(14px) saturate(150%);
  backdrop-filter: blur(14px) saturate(150%);
  box-shadow: var(--shadow-1);
}
.btn:hover {
  background: var(--surface-active);
  border-color: var(--border-strong);
  box-shadow: var(--shadow-2);
  transform: translateY(-1px);
}
.btn:active { transform: scale(0.97); box-shadow: var(--shadow-1); transition-duration: 80ms; }
.btn:focus-visible { box-shadow: var(--focus-ring); outline: none; }

.btn.primary {
  background: var(--brand-grad);
  border-color: transparent;
  color: var(--brand-contrast);
  box-shadow: var(--shadow-brand), inset 0 1px 0 rgba(255, 255, 255, 0.20);
}
.btn.primary:hover {
  filter: brightness(1.06) saturate(1.02);
  box-shadow: 0 12px 28px rgba(82, 101, 208, 0.36), inset 0 1px 0 rgba(255, 255, 255, 0.24);
}
.btn.danger {
  color: var(--danger);
  border-color: var(--danger-line);
  background: var(--danger-soft);
}
.btn.danger:hover { background: var(--danger-soft); border-color: var(--danger); box-shadow: var(--shadow-2); }
.btn.danger:focus-visible { box-shadow: var(--focus-ring-danger); }
.btn.ghost { background: transparent; border-color: transparent; box-shadow: none; color: var(--text-2); }
.btn.ghost:hover { background: var(--surface-2); border-color: var(--border-glass); color: var(--text-1); }
.btn.sm { min-height: 26px; padding: 0 10px; font-size: var(--fs-xs); border-radius: var(--r-sm); gap: 4px; }
.btn.lg { min-height: 40px; padding: 0 18px; font-size: var(--fs-base); border-radius: var(--r-lg); }
.btn.block { width: 100%; }
.btn:disabled, .btn[aria-disabled='true'] {
  opacity: 0.45;
  cursor: not-allowed;
  transform: none !important;
  box-shadow: none;
  filter: none;
}
.btn.is-loading { color: transparent !important; position: relative; pointer-events: none; }
.btn.is-loading::after {
  content: '';
  position: absolute;
  width: 14px; height: 14px;
  border-radius: 50%;
  border: 2px solid currentColor;
  border-top-color: transparent;
  color: var(--text-1);
  animation: cx-spin 0.7s linear infinite;
}
@keyframes cx-spin { to { transform: rotate(360deg); } }

/* 图标按钮：48px 触控热区 / 32px 视觉尺寸 */
.btn.icon, .icon-btn {
  width: 34px; min-width: 34px; padding: 0;
  border-radius: var(--r-md);
  font-size: var(--fs-lg);
  line-height: 1;
}

/* ===========================================================================
   7. 输入框 / 文本域 / 表单
   =========================================================================== */
.input, .textarea, .select,
.cx-field input, .cx-field textarea,
.dialog input, .dialog textarea,
.cx-panel-head input {
  color: var(--text-1);
  background: var(--surface-2);
  border: 1px solid var(--border-line);
  border-radius: var(--r-md);
  font-size: var(--fs-base);
  line-height: var(--lh-normal);
  transition: border-color var(--dur-2) var(--ease-standard),
              box-shadow var(--dur-2) var(--ease-standard),
              background-color var(--dur-2) var(--ease-standard);
}
.input, .select { min-height: 36px; padding: 0 12px; }
.textarea { padding: 10px 12px; resize: vertical; }
.input::placeholder, .textarea::placeholder,
.cx-field input::placeholder, .cx-field textarea::placeholder,
.dialog input::placeholder, .dialog textarea::placeholder,
#input::placeholder, textarea::placeholder, input::placeholder {
  color: var(--text-4);
  opacity: 1;
}
.input:hover, .textarea:hover, .cx-field input:hover, .cx-field textarea:hover,
.dialog input:hover, .dialog textarea:hover { border-color: var(--border-strong); }
.input:focus, .textarea:focus, .select:focus,
.cx-field input:focus, .cx-field textarea:focus,
.dialog input:focus, .dialog textarea:focus,
.cx-panel-head input:focus {
  border-color: var(--brand);
  background: var(--surface-active);
  box-shadow: var(--focus-ring);
  outline: none;
}
.input[aria-invalid='true'], .is-invalid {
  border-color: var(--danger);
  box-shadow: var(--focus-ring-danger);
}
/* 登录/注册/重置密码页的输入框用的是 .glass-soft（白玻璃 68%），
   叠在白色卡片上几乎看不见边界 —— 这里单独给"输入框语义"：内凹底色 + 发丝描边。 */
input.glass-soft, textarea.glass-soft, select.glass-soft {
  background: var(--surface-sunken) !important;
  border: 1px solid var(--border-line) !important;
  box-shadow: none !important;
  color: var(--text-1);
  border-radius: var(--r-md);
  transition: border-color var(--dur-2), box-shadow var(--dur-2), background-color var(--dur-2);
}
input.glass-soft::placeholder, textarea.glass-soft::placeholder { color: var(--text-4); opacity: 1; }
input.glass-soft:hover, textarea.glass-soft:hover { border-color: var(--border-strong) !important; }
input.glass-soft:focus, textarea.glass-soft:focus {
  background: var(--surface-2) !important;
  border-color: var(--brand) !important;
  box-shadow: var(--focus-ring) !important;
}

.field-label, .cx-field label, .dialog .field-label {
  display: block;
  margin-bottom: 6px;
  font-size: var(--fs-xs);
  font-weight: var(--fw-medium);
  letter-spacing: var(--ls-wide);
  color: var(--text-3);
}

/* ===========================================================================
   8. 导航（后台侧栏 + 聊天左侧竖排）
   =========================================================================== */
.nav-item {
  position: relative;
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  min-height: 36px;
  padding: 0 11px;
  border: 0;
  border-radius: var(--r-md);
  background: transparent;
  color: var(--text-3);
  font-size: var(--fs-sm);
  font-weight: var(--fw-medium);
  text-align: left;
  cursor: pointer;
  transition: background-color var(--dur-2) var(--ease-standard),
              color var(--dur-2) var(--ease-standard),
              transform var(--dur-1) var(--ease-standard);
}
.nav-item:hover { background: var(--surface-2); color: var(--text-1); }
.nav-item:active { transform: scale(0.985); }
.nav-item:focus-visible { box-shadow: var(--focus-ring); }
.nav-item.on {
  color: var(--brand-ink);
  font-weight: var(--fw-semibold);
  background: var(--brand-soft);
  box-shadow: inset 0 0 0 1px var(--brand-soft-2);
}
.nav-item.on::before {
  content: '';
  position: absolute;
  left: -6px; top: 50%;
  width: 3px; height: 18px;
  margin-top: -9px;
  border-radius: var(--r-full);
  background: var(--brand);
  box-shadow: 0 0 8px var(--brand-soft-2);
}
.nav-item .ico { width: 18px; text-align: center; font-size: 14px; opacity: 0.9; }
.nav-item .badge {
  margin-left: auto;
  min-width: 18px; height: 18px;
  padding: 0 6px;
  border-radius: var(--r-full);
  background: var(--danger);
  color: #fff;
  font-size: var(--fs-2xs);
  font-weight: var(--fw-semibold);
  line-height: 18px;
  text-align: center;
}

/* 分段控件 / 页签 / 筛选：三处长得一样，只是语义不同，统一同一套视觉 */
.seg, .tabs2 {
  display: inline-flex;
  gap: 2px;
  padding: 3px;
  border-radius: var(--r-md);
  background: var(--surface-sunken);
  border: 1px solid var(--border-line);
}
.seg button, .tabs2 button {
  border: 0;
  background: transparent;
  color: var(--text-2);
  font-size: var(--fs-xs);
  font-weight: var(--fw-medium);
  padding: 5px 12px;
  border-radius: var(--r-sm);
  cursor: pointer;
  transition: background-color var(--dur-1), color var(--dur-1), box-shadow var(--dur-1);
}
.seg button:hover, .tabs2 button:hover { color: var(--text-1); background: var(--surface-hover); }
.seg button.on, .tabs2 button.on {
  background: var(--surface-3);
  color: var(--text-1);
  font-weight: var(--fw-semibold);
  box-shadow: var(--shadow-1);
}
html[data-theme='dark'] .seg button.on,
html[data-theme='dark'] .tabs2 button.on {
  background: var(--brand-soft-2);
  color: var(--brand-ink);
}

/* 外观切换：日/月图标 + 文字，让"这是主题开关"一眼可辨；选中态由 .on 控制，
   切换时只改 class，不重建 DOM（面板不会闪一下） */
.seg-theme button {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 6px 14px;
}
/* 浅色下白胶囊叠在浅轨道上边界太弱，补一圈发丝描边把"选中"钉住 */
.seg button.on { box-shadow: var(--shadow-1), inset 0 0 0 1px var(--border-line); }
.seg-theme button .ico {
  font-size: 12.5px;
  line-height: 1;
  opacity: 0.7;
  transition: opacity var(--dur-1) var(--ease-standard), color var(--dur-1);
}
/* 半明半暗的小圆点 = 跟随系统（比字形 ◐ 稳，不依赖系统字体） */
.seg-theme button .ico-auto {
  width: 11px;
  height: 11px;
  border-radius: 50%;
  border: 1px solid currentColor;
  background: linear-gradient(90deg, currentColor 50%, transparent 50%);
  opacity: 0.75;
}
.seg-theme button:hover .ico { opacity: 0.9; }
.seg-theme button.on .ico { opacity: 1; color: var(--brand-ink); }

/* 外观面板里的子分组：主题色 / 动态效果 */
.cx-sub {
  margin: 14px 0 8px;
  font-size: var(--fs-xs);
  font-weight: var(--fw-medium);
  color: var(--text-2);
}
.accent-row { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.accent-swatch {
  position: relative;
  width: 26px; height: 26px;
  padding: 0;
  border: 0;
  border-radius: var(--r-full);
  background: var(--sw, var(--brand));
  cursor: pointer;
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.35), 0 1px 2px rgba(20, 30, 50, 0.18);
  transition: transform var(--dur-1) var(--ease-standard), box-shadow var(--dur-2) var(--ease-standard);
}
.accent-swatch:hover { transform: scale(1.08); }
.accent-swatch:focus-visible { outline: 2px solid var(--text-1); outline-offset: 3px; }
.accent-swatch[aria-pressed='true'] {
  box-shadow: 0 0 0 2px var(--surface-3), 0 0 0 4px var(--sw), inset 0 1px 0 rgba(255, 255, 255, 0.35);
}
.accent-swatch[aria-pressed='true']::after {
  content: '✓';
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  color: #fff;
  font-size: 12px;
  font-weight: var(--fw-bold);
  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.35);
}
.accent-name { font-size: var(--fs-xs); color: var(--text-3); margin-left: 2px; }
/* 风格：经典柔光 / 秋叶 */
.seg-skin button { padding: 6px 14px; }
.cx-sub-note {
  margin-left: 6px;
  font-size: var(--fs-2xs);
  font-weight: var(--fw-regular);
  color: var(--text-3);
}
/* 秋叶风格下主题色不可用：只做视觉淡化 + 禁用指针，保留可读性（读屏仍能读到当前值） */
.accent-row.is-disabled { opacity: 0.45; pointer-events: none; filter: grayscale(0.2); }
.accent-row.is-disabled .accent-swatch { cursor: default; }

.filters { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; margin-bottom: var(--sp-3); }
.filters button {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  min-height: 28px;
  padding: 0 11px;
  border-radius: var(--r-full);
  border: 1px solid var(--border-line);
  background: var(--surface-1);
  color: var(--text-2);
  font-size: var(--fs-xs);
  font-weight: var(--fw-medium);
  cursor: pointer;
  transition: background-color var(--dur-1), color var(--dur-1), border-color var(--dur-1), box-shadow var(--dur-1);
}
.filters button:hover { color: var(--text-1); background: var(--surface-2); border-color: var(--border-strong); }
.filters button.on {
  color: var(--brand-contrast);
  border-color: transparent;
  background: var(--brand-grad);
  box-shadow: var(--shadow-brand);
}
.filters button .c { opacity: 0.72; font-variant-numeric: tabular-nums; }

/* ===========================================================================
   9. 标签 / 角标
   =========================================================================== */
.chip {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 2px 8px;
  border-radius: var(--r-full);
  font-size: var(--fs-2xs);
  font-weight: var(--fw-medium);
  letter-spacing: 0.01em;
  background: var(--surface-2);
  border: 1px solid var(--border-line);
  color: var(--text-2);
  white-space: nowrap;
}
.chip.ok     { color: var(--ok);     background: var(--ok-soft);     border-color: var(--ok-line); }
.chip.warn   { color: var(--warn);   background: var(--warn-soft);   border-color: var(--warn-line); }
.chip.danger { color: var(--danger); background: var(--danger-soft); border-color: var(--danger-line); }
.chip.info   { color: var(--info);   background: var(--info-soft);   border-color: var(--info-line); }
.chip.brand  { color: var(--brand-ink); background: var(--brand-soft); border-color: var(--brand-line); }

/* ===========================================================================
   10. 表格（后台）
   =========================================================================== */
table.list { width: 100%; border-collapse: collapse; font-size: var(--fs-sm); }
table.list th {
  position: sticky;
  top: 0;
  z-index: 1;
  padding: 8px 10px;
  text-align: left;
  font-size: var(--fs-2xs);
  font-weight: var(--fw-semibold);
  letter-spacing: var(--ls-caps);
  text-transform: uppercase;
  color: var(--text-3);
  background: var(--surface-2);
  border-bottom: 1px solid var(--border-line);
  -webkit-backdrop-filter: blur(12px);
  backdrop-filter: blur(12px);
}
table.list td { padding: 10px; border-top: 1px solid var(--divider); vertical-align: middle; color: var(--text-1); }
table.list tbody tr { transition: background-color var(--dur-1) var(--ease-standard); }
table.list tbody tr:hover td { background: var(--surface-hover); }

/* ===========================================================================
   11. 浮层：菜单 / 弹窗 / 抽屉 / 轻提示
   -------------------------------------------------------------------------
   统一规则：surface-3（近乎不透明的玻璃）+ shadow-4 + r-lg/xl。
   菜单绝不用高透明玻璃 —— 下面表格内容会透上来，看起来像"菜单项消失"。
   =========================================================================== */
.headmenu, .cx-menu, .row-menu, .mention-pop, #plusMenu {
  background: var(--surface-3);
  border: 1px solid var(--border-line);
  box-shadow: var(--shadow-4);
  border-radius: var(--r-lg);
  color: var(--text-1);
  -webkit-backdrop-filter: blur(30px) saturate(160%);
  backdrop-filter: blur(30px) saturate(160%);
  isolation: isolate;
}
.headmenu-item, .cx-menu button, .row-menu button, .mention-item {
  display: flex;
  align-items: center;
  gap: 8px;
  width: 100%;
  padding: 8px 10px;
  border: 0;
  border-radius: var(--r-sm);
  background: transparent;
  color: var(--text-2);
  font-size: var(--fs-sm);
  text-align: left;
  cursor: pointer;
  transition: background-color var(--dur-1), color var(--dur-1);
}
.headmenu-item:hover, .cx-menu button:hover, .row-menu button:hover, .mention-item:hover {
  background: var(--brand-soft);
  color: var(--text-1);
}
.cx-menu button.danger, .row-menu button.danger { color: var(--danger); }
.cx-menu button.danger:hover, .row-menu button.danger:hover { background: var(--danger-soft); }

.modal, .dialog, .cx-panel-inner {
  background: var(--surface-3);
  border: 1px solid var(--border-line);
  border-radius: var(--r-2xl);
  box-shadow: var(--shadow-4);
  color: var(--text-1);
  -webkit-backdrop-filter: blur(var(--glass-blur-lg)) saturate(170%);
  backdrop-filter: blur(var(--glass-blur-lg)) saturate(170%);
}
.mask, .cx-panel, .drawer-mask {
  background: var(--overlay);
  -webkit-backdrop-filter: blur(var(--overlay-blur));
  backdrop-filter: blur(var(--overlay-blur));
}
.toast {
  background: var(--surface-3);
  color: var(--text-1);
  border: 1px solid var(--border-line);
  border-radius: var(--r-md);
  box-shadow: var(--shadow-3);
  font-size: var(--fs-sm);
  -webkit-backdrop-filter: blur(24px) saturate(160%);
  backdrop-filter: blur(24px) saturate(160%);
}

/* ===========================================================================
   12. 头像与状态点
   =========================================================================== */
.avatar {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
  /* 头像底是浅紫/浅青渐变，白字只有 1.9:1；改用墨色首字母（6.8:1），
     有真实头像时被 img 覆盖，不受影响。 */
  color: #22304a;
  font-weight: var(--fw-semibold);
  background: linear-gradient(145deg, #b8c7ff, #a49be9);
  box-shadow: 0 4px 12px rgba(126, 143, 221, 0.24), inset 0 1px 0 rgba(255, 255, 255, 0.55);
  border: 1px solid rgba(255, 255, 255, 0.35);
}
.avatar.alt   { background: linear-gradient(145deg, #b9e4e8, #94b7ee); }
.avatar.peach { background: linear-gradient(145deg, #f8d7c8, #c6b1f3); }
html[data-theme='dark'] .avatar {
  border-color: rgba(255, 255, 255, 0.12);
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.35), inset 0 1px 0 rgba(255, 255, 255, 0.14);
}
.avatar img { width: 100%; height: 100%; object-fit: cover; }

.dot {
  display: inline-block;
  width: 7px; height: 7px;
  border-radius: 50%;
  background: var(--ok);
  box-shadow: 0 0 0 3px var(--ok-soft);
}
.dot.off { background: #b9c3d4; box-shadow: none; }
html[data-theme='dark'] .dot.off { background: #4a5568; }

/* ===========================================================================
   13. 消息气泡
   -------------------------------------------------------------------------
   浅色：对方是白玻璃、自己是浅靛渐变 + 深字（沿用原设计，只把边界和阴影理干净）。
   深色：对方 8% 白玻璃，自己是深靛紫渐变 + 白字（对比度 5.1:1 起）。
   =========================================================================== */
.bubble {
  border-radius: var(--r-xl);
  padding: 12px 15px;
  line-height: var(--lh-normal);
  font-size: var(--fs-md);
  overflow-wrap: break-word;
  box-shadow: var(--shadow-1);
}
/* 靠近说话人的那一侧下角收窄，形成"从谁那里说出来"的指向 */
.bubble.mine, .mine { border-bottom-right-radius: var(--r-xs); }
.bubble.theirs, .theirs { border-bottom-left-radius: var(--r-xs); }
.bubble.mine, .mine {
  background: var(--bubble-mine-bg);
  border: 1px solid rgba(255, 255, 255, 0.72);
  color: var(--bubble-mine-fg);
  box-shadow: 0 6px 18px rgba(96, 110, 205, 0.14), inset 0 1px 0 rgba(255, 255, 255, 0.65);
}
.bubble.theirs, .theirs {
  background: rgba(255, 255, 255, 0.68);
  border: 1px solid rgba(255, 255, 255, 0.85);
  color: var(--text-1);
  box-shadow: 0 4px 14px rgba(70, 92, 145, 0.08), inset 0 1px 0 rgba(255, 255, 255, 0.9);
}
html[data-theme='dark'] .bubble.mine,
html[data-theme='dark'] .mine {
  /* 深色下自己气泡压一点饱和度、留一点透明：大面积纯色块在暗场里会跳出来，
     92% 左右既能和对方气泡分开，又不抢视线。 */
  border-color: rgba(255, 255, 255, 0.14);
  color: var(--bubble-mine-fg);
  box-shadow: 0 10px 26px rgba(72, 78, 200, 0.32), inset 0 1px 0 rgba(255, 255, 255, 0.18);
}
html[data-theme='dark'] .bubble.theirs,
html[data-theme='dark'] .theirs {
  background: rgba(255, 255, 255, 0.08);
  border-color: rgba(255, 255, 255, 0.09);
  color: var(--text-1);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.06);
}

/* 气泡里的发送人 / 时间：11px，字距宽一点，颜色走 text-3（5:1），不再用 slate-400 */
.bubble .mb-1.text-\[11px\] {
  font-size: var(--fs-2xs);
  letter-spacing: var(--ls-wide);
  color: var(--text-3);
  margin-bottom: 6px;
  /* 名字 + 时间永远一行：气泡再窄也不拆成两三行（超长名字用省略号） */
  white-space: nowrap;
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
}
html[data-theme='dark'] .bubble.mine .mb-1.text-\[11px\] { color: rgba(255, 255, 255, 0.76); }

/* 日期分割：给一个胶囊底，夹在两条渐隐线之间 */
.cx-date {
  display: flex;
  align-items: center;
  gap: 12px;
  margin: 20px 0 8px;
  font-size: var(--fs-xs);
  letter-spacing: var(--ls-wide);
  color: var(--text-3);
}
.cx-date::before, .cx-date::after {
  content: '';
  flex: 1;
  height: 1px;
  background: linear-gradient(90deg, transparent, var(--divider) 22%, var(--divider) 78%, transparent);
  opacity: 1;
}

/* ===========================================================================
   14. Tailwind 调色板收口
   -------------------------------------------------------------------------
   页面里 83 处 text-slate-400、20 处 text-slate-500 … 都是写死的 Tailwind 灰。
   这一层把它们映射到语义令牌，等于「零改模板」完成全站换色；
   之所以能生效，是因为本文件在 tailwind.css 之后加载、同权重后者胜。
   =========================================================================== */
.text-slate-400 { color: var(--text-3) !important; }
.text-slate-500 { color: var(--text-3) !important; }
.text-slate-600 { color: var(--text-2) !important; }
.text-slate-700 { color: var(--text-1) !important; }
.text-indigo-400,
.text-indigo-500,
.text-indigo-600,
.text-indigo-700 { color: var(--brand-ink) !important; }
.text-violet-600, .text-violet-700 { color: var(--accent-ink) !important; }
.text-green-600, .text-emerald-600 { color: var(--ok) !important; }
.text-amber-500, .text-amber-600 { color: var(--warn) !important; }
.text-rose-500, .text-rose-600, .text-red-500, .text-red-600 { color: var(--danger) !important; }

/* 半透明白底 → 抬升面（浅色下就是"更亮一档的玻璃"，深色下自动变成 8.5% 白） */
.bg-white\/40, .bg-white\/50, .bg-white\/60, .bg-white\/70, .bg-white\/80 { background-color: var(--surface-2) !important; }
.bg-indigo-200\/40, .bg-indigo-200\/50, .bg-indigo-200\/60, .bg-indigo-100\/50, .bg-indigo-100\/60 { background-color: var(--brand-soft) !important; }
.bg-green-200\/50, .bg-green-200\/70 { background-color: var(--ok-soft) !important; }
.bg-rose-100\/50, .bg-rose-100\/70 { background-color: var(--danger-soft) !important; }
.bg-slate-900\/20, .bg-slate-900\/30, .bg-slate-900\/35 { background-color: var(--overlay) !important; }

.border-white\/45, .border-white\/50, .border-white\/60 { border-color: var(--border-line) !important; }

/* 主按钮渐变（模板里是 from-indigo-300 to-violet-300 两个类拼出来的） */
.bg-gradient-to-br.from-indigo-300.to-violet-300,
.bg-gradient-to-br.from-indigo-400.to-violet-400 {
  background-image: var(--brand-grad) !important;
  color: var(--brand-contrast) !important;
  box-shadow: var(--shadow-brand), inset 0 1px 0 rgba(255, 255, 255, 0.18);
}
.bg-gradient-to-br.from-indigo-100\/80.to-violet-100\/80 {
  background-image: linear-gradient(135deg, var(--brand-soft), var(--accent-soft)) !important;
}

/* ===========================================================================
   15. 内联样式兜底
   -------------------------------------------------------------------------
   composer 的 <table>、加号菜单、表情面板、发送按钮的颜色是写在 style="" 里的
   （历史原因，CSP 的 style-src-attr 允许），只能在这里用 !important 覆盖。
   =========================================================================== */
footer > table {
  background: var(--surface-2) !important;
  border: 1px solid var(--border-glass) !important;
  border-radius: var(--r-2xl) !important;
  box-shadow: var(--shadow-glass), var(--glass-highlight) !important;
  -webkit-backdrop-filter: blur(var(--glass-blur)) saturate(var(--glass-saturate));
  backdrop-filter: blur(var(--glass-blur)) saturate(var(--glass-saturate));
  transition: border-color var(--dur-2) var(--ease-standard), box-shadow var(--dur-2) var(--ease-standard);
}
footer > table:focus-within {
  border-color: var(--brand-line) !important;
  box-shadow: var(--shadow-glass), var(--focus-ring) !important;
}
#input { color: var(--text-1) !important; caret-color: var(--brand); }
#input::placeholder { color: var(--text-4) !important; }

#plusMenu, #stickerPanel {
  background: var(--surface-3) !important;
  border-color: var(--border-line) !important;
  color: var(--text-1) !important;
  box-shadow: var(--shadow-4) !important;
}
#plusMenu > button { color: var(--text-2) !important; }
#plusMenu > button:hover { background: var(--brand-soft) !important; color: var(--text-1) !important; }

/* composer 两侧的 ＋ / ☺ 按钮：内联 color:#94a3b8 在浅色下只有 2.6:1 */
footer table button[data-act='togglePlusMenu'],
footer table button[data-act='toggleStickerPanel'] {
  color: var(--text-3) !important;
  transition: color var(--dur-1), background-color var(--dur-1), transform var(--dur-1);
}
footer table button[data-act='togglePlusMenu']:hover,
footer table button[data-act='toggleStickerPanel']:hover {
  color: var(--brand-ink) !important;
  background: var(--brand-soft) !important;
}
/* 发送键：#c7d2fe→#c4b5fd 的浅紫上放白箭头，对比度只有 1.6:1，改成品牌渐变 */
footer table button[data-act='send'] {
  background: var(--brand-grad) !important;
  color: var(--brand-contrast) !important;
  box-shadow: var(--shadow-brand), inset 0 1px 0 rgba(255, 255, 255, 0.22) !important;
  transition: transform var(--dur-1), filter var(--dur-2), box-shadow var(--dur-2);
}
footer table button[data-act='send']:hover { filter: brightness(1.08); transform: translateY(-1px); }
footer table button[data-act='send']:active { transform: scale(0.94); }

/* 聊天左侧竖排导航：76px 宽的胶囊列，选中态用品牌底 + 左侧竖条 */
.vtab {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  min-height: 40px;
  padding: 10px 0;
  border: 1px solid transparent;
  border-radius: var(--r-md);
  background: transparent;
  color: var(--text-3);
  font-size: var(--fs-xs);
  font-weight: var(--fw-medium);
  line-height: var(--lh-snug);
  cursor: pointer;
  transition: background-color var(--dur-2) var(--ease-standard),
              color var(--dur-2) var(--ease-standard),
              border-color var(--dur-2) var(--ease-standard);
}
.vtab:hover { background: var(--surface-2); color: var(--text-1); }
.vtab.nav-active {
  background: var(--brand-soft);
  border-color: var(--brand-soft-2);
  color: var(--brand-ink);
  font-weight: var(--fw-semibold);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.35);
}
.vtab.nav-active::before {
  content: '';
  position: absolute;
  left: 3px; top: 50%;
  width: 3px; height: 16px;
  margin-top: -8px;
  border-radius: var(--r-full);
  background: var(--brand);
}
html[data-theme='dark'] .vtab.nav-active { box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.10); }

/* 会话列表行 / 搜索结果行：统一 hover 与选中反馈 */
#tabContent [data-act='select'] {
  border-radius: var(--r-md);
  transition: background-color var(--dur-1) var(--ease-standard), transform var(--dur-1);
}
#tabContent [data-act='select']:hover { background: var(--surface-2); }
#tabContent [data-act='select']:active { transform: scale(0.995); }

/* ===========================================================================
   16. 聊天页细节
   =========================================================================== */
/* 顶栏标题区 */
#head h2, #head .font-semibold { letter-spacing: var(--ls-tight); }
#head { border-color: var(--divider) !important; }

/* 气泡旁的「⋯」：hover 才出现，但要能看清 */
.msgmenu {
  color: var(--text-3);
  background: var(--surface-3);
  border: 1px solid var(--border-line) !important;
  box-shadow: var(--shadow-2);
  border-radius: var(--r-sm);
  transition: color var(--dur-1), background-color var(--dur-1), opacity var(--dur-2);
}
.msgmenu:hover { color: var(--brand-ink); background: var(--surface-3); }

/* 引用条 / 被引用块 */
.quotebar {
  background: var(--surface-2) !important;
  border: 1px solid var(--border-line) !important;
  color: var(--text-2);
  border-radius: var(--r-md);
}
.quote-in {
  background: var(--surface-sunken);
  border-left: 3px solid var(--brand-line);
  color: var(--text-3);
  border-radius: var(--r-xs);
}
.mention { color: var(--brand-ink); }
.mention-me { background: var(--brand-soft-2); color: var(--brand-ink); border-radius: var(--r-xs); }

/* 文件卡片：外框、悬停、下载文字 */
.file-card {
  background: var(--surface-2);
  border: 1px solid var(--border-line);
  border-radius: var(--r-md);
  transition: background-color var(--dur-2), border-color var(--dur-2), transform var(--dur-1), box-shadow var(--dur-2);
}
.file-card:hover {
  background: var(--surface-active);
  border-color: var(--border-strong);
  box-shadow: var(--shadow-2);
  transform: translateY(-1px);
}
.file-dl { color: var(--text-3); }


/* 会话列表里的按钮一律不换行：窄侧栏里「搜索」「同意」曾被压成竖排两行 */
#tabContent button { white-space: nowrap; }
/* 好友申请行：文案单行截断，按钮不被挤压 */
#friendRequests .copy span { display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
#friendRequests { border-radius: var(--r-md); }

/* 输入区高度：三行变两行半，去掉中间那块空得发慌的白 */
#input { min-height: 48px !important; }
footer > table { padding: 8px !important; }
@media (max-width: 820px) {
  #input { min-height: 44px !important; }
}

/* ===========================================================================
   17. 后台细节
   =========================================================================== */
.nav, .top { border-color: var(--border-glass); }
.nav-group-label {
  font-size: var(--fs-2xs);
  letter-spacing: var(--ls-caps);
  text-transform: uppercase;
  color: var(--text-3);   /* 10.5px 的标签必须 ≥4.5:1，text-4 只有 4.26 */
  padding: 14px 10px 6px;
  font-weight: var(--fw-semibold);
}
.brand-name { font-size: var(--fs-base); font-weight: var(--fw-semibold); letter-spacing: 0.01em; }
.brand-sub { font-size: var(--fs-2xs); letter-spacing: var(--ls-caps); color: var(--text-3); }
.top h1 { font-size: var(--fs-lg); font-weight: var(--fw-semibold); letter-spacing: var(--ls-tight); }
.top .sub { font-size: var(--fs-xs); color: var(--text-3); margin-top: 3px; }
.search {
  border-radius: var(--r-md);
  background: var(--surface-2);
  border: 1px solid var(--border-line);
  transition: border-color var(--dur-2), box-shadow var(--dur-2), background-color var(--dur-2);
}
.search:focus-within { border-color: var(--brand); box-shadow: var(--focus-ring); background: var(--surface-active); }
.search > span { color: var(--text-3); }

/* 数据卡：数字用品牌色渐变只在"强调卡"上，其余保持高对比墨色，避免整页花 */
.stat {
  border-radius: var(--r-lg);
  background: var(--surface-1);
  border: 1px solid var(--border-glass);
  box-shadow: var(--shadow-1), var(--glass-highlight);
  -webkit-backdrop-filter: blur(20px) saturate(150%);
  backdrop-filter: blur(20px) saturate(150%);
  padding: var(--sp-3) var(--sp-4);
  transition: transform var(--dur-2) var(--ease-standard), box-shadow var(--dur-2);
}
.stat:hover { transform: translateY(-1px); box-shadow: var(--shadow-2), var(--glass-highlight); }
.stat .k { font-size: var(--fs-2xs); letter-spacing: var(--ls-caps); text-transform: uppercase; color: var(--text-3); }
.stat .v { font-size: var(--fs-3xl); font-weight: var(--fw-bold); letter-spacing: -0.02em; color: var(--text-1); margin-top: 6px; }
.stat .d { font-size: var(--fs-xs); color: var(--text-3); margin-top: 4px; }
.stat.accent .v {
  background: linear-gradient(135deg, var(--brand), var(--accent));
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}

/* 进度条 / 迷你分布条：轨道统一，填充统一渐变 */
.meter .track, .core-bars .cb .bar, .seg-bar, .upload-bar .track {
  background: var(--surface-sunken);
  border: 1px solid var(--divider);
}
.meter .fill, .core-bars .cb .bar > i, .upload-bar .track > i {
  background: linear-gradient(90deg, var(--brand), var(--accent));
}
.meter.warn .fill { background: linear-gradient(90deg, #d9912f, var(--warn)); }
.meter.crit .fill { background: linear-gradient(90deg, #d94a4a, var(--danger)); }

/* 日志块：等宽 + 深底，浅色主题下也保持"终端感"但不刺眼 */
.logs {
  background: var(--surface-sunken);
  border: 1px solid var(--border-line);
  color: var(--text-2);
  border-radius: var(--r-md);
  font-size: var(--fs-xs);
  line-height: var(--lh-relaxed);
}
.logs .err { color: var(--danger); }
.logs .warn { color: var(--warn); }
.logs:empty::before { color: var(--text-4); }
html[data-theme='dark'] .logs { color: #c3cee0; }

/* 面包屑 / 只读提示 / 空状态 */
.crumbs button { color: var(--brand-ink); border-radius: var(--r-xs); }
.crumbs button:hover { background: var(--brand-soft); }
.crumbs .cur { color: var(--text-1); }
.empty, .cx-empty, .stk-empty { color: var(--text-3); }

.fs-note {
  background: var(--surface-sunken);
  border: 1px dashed var(--border-strong);
  color: var(--text-3);
  border-radius: var(--r-md);
}
.fs-note b { color: var(--text-1); }
.fs-note code { color: var(--brand-ink); }

/* 备注徽标 / 引用计数徽标 */
.remark, .ref-badge {
  color: var(--brand-ink);
  background: var(--brand-soft);
  border: 1px solid var(--brand-line);
  border-radius: var(--r-xs);
  font-size: var(--fs-2xs);
  font-weight: var(--fw-medium);
}
.remark.plain { color: var(--text-3); background: transparent; border-color: var(--border-line); border-style: dashed; }
.ref-badge.none { background: transparent; color: var(--warn); border-color: var(--warn-line); }

/* 抽屉 */
.drawer {
  background: var(--surface-3);
  border-left: 1px solid var(--border-line);
  box-shadow: var(--shadow-4);
  color: var(--text-1);
  -webkit-backdrop-filter: blur(var(--glass-blur-lg)) saturate(160%);
  backdrop-filter: blur(var(--glass-blur-lg)) saturate(160%);
}
.dr-sec h4 { font-size: var(--fs-2xs); letter-spacing: var(--ls-caps); color: var(--text-3); }
.dr-item { background: var(--surface-2); border: 1px solid var(--border-line); border-radius: var(--r-sm); }
.dr-item .meta { color: var(--text-3); }
.dr-stats .cell { background: var(--surface-1); border: 1px solid var(--border-glass); }
.dr-stats .cell .k { color: var(--text-3); }

/* 服务器 / 进程 / 磁盘等密集表格 */
.kv .k, .svc .row .st, .fs-size, .fs-perm, .fs-time, .mono, .text.muted { color: var(--text-3); }
.kv .v { color: var(--text-1); }
.pager { color: var(--text-3); }
.warnText { color: var(--danger); }

/* ===========================================================================
   18. 响应式
   -------------------------------------------------------------------------
   断点：640（大手机）/ 820（平板竖屏）/ 1080（小笔记本）/ 1280（桌面）
   规则：小屏收紧留白、降低模糊半径（省 GPU）、触控目标 ≥ 40px。
   =========================================================================== */
@media (max-width: 1280px) {
  :root { --gutter: 16px; }
}
@media (max-width: 820px) {
  :root {
    --gutter: 12px;
    --glass-blur: 18px;        /* 移动端 GPU 弱，模糊半径减半，观感几乎无损 */
    --glass-blur-lg: 22px;
    --fs-4xl: 26px;
    --fs-3xl: 24px;
  }
  .card { border-radius: var(--r-lg); padding: var(--sp-3) var(--sp-4); }
  .modal, .dialog, .cx-panel-inner { border-radius: var(--r-xl); }
  .btn { min-height: 38px; }
  .btn.sm { min-height: 30px; }
  .filters button { min-height: 32px; }
  .nav-item { min-height: 40px; }
  .vtab { min-height: 44px; }
  table.list th, table.list td { padding: 8px; }
}
@media (max-width: 520px) {
  .stat .v { font-size: var(--fs-2xl); }
  .stat { padding: var(--sp-3); }
}

/* 触屏：hover 效果常驻会显得脏，改用 active 反馈 */
@media (hover: none) {
  .btn:hover, .stat:hover, .file-card:hover, .conv:hover { transform: none; box-shadow: var(--shadow-1); }
  .btn:active { transform: scale(0.97); }
}

/* ===========================================================================
   19. 可访问性降级
   =========================================================================== */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
    scroll-behavior: auto !important;
  }
  .btn:hover, .stat:hover, .file-card:hover { transform: none; }
}

/* 系统要求高对比度时：把玻璃压实、描边加深、文字再提一档 */
@media (prefers-contrast: more) {
  :root {
    --surface-1: rgba(255, 255, 255, 0.82);
    --surface-2: rgba(255, 255, 255, 0.92);
    --surface-3: #ffffff;
    --border-line: rgba(50, 65, 95, 0.42);
    --border-strong: rgba(50, 65, 95, 0.6);
    --text-3: #3d4c63;
    --text-4: #4a5a72;
  }
  html[data-theme='dark'] {
    --surface-1: rgba(20, 24, 36, 0.92);
    --surface-2: rgba(30, 36, 52, 0.95);
    --surface-3: #1a1f2e;
    --border-line: rgba(255, 255, 255, 0.34);
    --border-strong: rgba(255, 255, 255, 0.5);
    --text-3: #cdd6e6;
    --text-4: #b9c4d6;
  }
  .glass, .card, .nav, .top { -webkit-backdrop-filter: none; backdrop-filter: none; }
}

/* 强制颜色模式（Windows 高对比度主题）：交给系统，不跟它抢 */
@media (forced-colors: active) {
  .glass, .card, .nav, .top, .modal, .dialog { border: 1px solid CanvasText; }
  .btn { border: 1px solid ButtonText; }
}

/* ===========================================================================
   20. 打印
   =========================================================================== */
@media print {
  body { background: #fff !important; color: #000; }
  .glass, .card, .nav, .top { box-shadow: none !important; border-color: #ccc !important; background: #fff !important; }
  .nav-foot, .btn, .filters, .search { display: none !important; }
}


/* 未读角标：模板里是内联的 #f87171→#fb7185 渐变（白字仅 2.7:1），
   统一换成实心语义红，白字 5.4:1；用属性选择器抓内联样式，零改模板。 */
#tabContent span[style*='#f87171'],
span[style*='border-radius:999px'][style*='#f87171'] {
  background: var(--badge-bg) !important;
  color: var(--badge-fg) !important;
  box-shadow: 0 2px 6px rgba(0, 0, 0, 0.16) !important;
  font-variant-numeric: tabular-nums;
}
.cx-dot-badge, .nav-item .badge { background: var(--badge-bg); color: var(--badge-fg); }

/* 选中会话行：比普通 hover 再亮一档，并给一圈品牌描边（替代未映射的 Tailwind ring） */
/* 选中态用 12% 品牌底 + 左侧竖条 + 一圈描边：
   原来用 20% 底（brand-soft-2）会把底压暗到 #d3d9f2，
   压在上面的 11px 灰字对比度掉到 3.8:1 —— 审计脚本抓出来的真问题。 */
#tabContent .contact[class*='ring-indigo-300'] {
  background: var(--brand-soft) !important;
  box-shadow: inset 0 0 0 1px var(--brand-line), inset 3px 0 0 0 var(--brand);
}

/* 会话表头右侧两个 10px 的小按钮：字号提到 11.5、颜色提到次级墨色 */
#tabContent button[data-act='addFriend'],
#tabContent button[data-act='createGroup'] {
  font-size: var(--fs-xs) !important;
  color: var(--text-2) !important;
  letter-spacing: 0.02em;
}

/* 浅色主题下，自己气泡里的"我 · 时间"用更深的墨色，不能跟对方用同一档灰 */
html:not([data-theme='dark']) .bubble.mine .mb-1.text-\[11px\] { color: rgba(23, 35, 63, 0.74); }

/* ---------------------------------------------------------------------------
   21. 零散但影响观感的几处
   --------------------------------------------------------------------------- */

/* 侧栏「未绑定手机号」提示点：enhance.js 只给了内联的 #f59e0b，
   这里换成语义告警色 + 柔光圈，深色主题下也不会糊成一点脏黄。 */
.sidebar button[title*='未绑定手机号'] {
  background: var(--warn) !important;
  box-shadow: 0 0 0 3px var(--warn-soft) !important;
}
.sidebar button[title*='未绑定手机号']:hover {
  box-shadow: 0 0 0 4px var(--warn-soft), 0 0 0 1px var(--warn) !important;
}

/* 聊天顶栏与输入区的分隔线：用渐隐的发丝线，不用整条实线 */
#head { border-bottom: 1px solid transparent !important; position: relative; }
#head::after {
  content: '';
  position: absolute; left: 16px; right: 16px; bottom: 0; height: 1px;
  background: linear-gradient(90deg, transparent, var(--divider) 12%, var(--divider) 88%, transparent);
  pointer-events: none;
}
footer { border-top: 1px solid transparent !important; }

/* 后台窄屏：标题与操作按钮换行时保持 8px 节奏 */
@media (max-width: 640px) {
  .top { gap: 8px; padding: 10px 12px; }
  .top h1 { font-size: var(--fs-base); }
  .stats { grid-template-columns: repeat(auto-fit, minmax(132px, 1fr)); }
}

/* 移动端返回键：从默认的裸符号改成 32px 触控钮，和顶栏图标同一套观感 */
.m-back {
  width: 32px; height: 32px;
  align-items: center; justify-content: center;
  border-radius: var(--r-sm);
  border: 1px solid var(--border-line) !important;
  background: var(--surface-2);
  color: var(--text-2);
  font-size: var(--fs-lg);
  line-height: 1;
  flex: none;
}
.m-back:hover { background: var(--surface-active); color: var(--text-1); }

/* 登录 / 注册 / 重置密码页顶部的装饰图标（.text-center 里的 .avatar）：
   浅紫底 + 浅色符号几乎看不见，改成品牌渐变 + 白字，和白底卡片形成视觉锚点。 */
.modal .text-center > .avatar {
  background: var(--brand-grad) !important;
  color: var(--brand-contrast) !important;
  border-color: transparent !important;
  box-shadow: var(--shadow-brand), inset 0 1px 0 rgba(255, 255, 255, 0.22) !important;
}


/* ===========================================================================
   22. 风格强化层（2026-10-22）
   -------------------------------------------------------------------------
   体检结论（qa/style-audit.js 实测）：
     · 聊天页一屏 13 种字号（10/10.5/11/11.5/12/12.5/13.5…），会话标题只有 13.5px，
       比气泡正文（14.5px）还小 —— 标题层级是塌的
     · 品牌色只出现在 0.88%（聊天）/ 0.45%（后台）的元素上，观感 = 灰玻璃 + 黑字
     · 32 个 Unicode 字形当图标（✎ ↪ ⌕ ✦ ⋯ ◈ ⛁），字体不同、字重不齐
     · 所有玻璃面板同一层高度、同一道阴影，chrome 与内容没有前后关系
   这一层只做三件事：立字级、给光、点亮品牌；不改内容、不改结构。
   =========================================================================== */

/* ---------- 22.1 光学签名：光从左上角进来 ---------- */
:root {
  --sheen: rgba(255, 255, 255, 0.62);
  --sheen-soft: rgba(255, 255, 255, 0.20);
  --brand-wash: rgba(82, 101, 208, 0.07);
}
html[data-theme='dark'] {
  --sheen: rgba(255, 255, 255, 0.075);
  --sheen-soft: rgba(255, 255, 255, 0.03);
  --brand-wash: rgba(139, 155, 255, 0.10);
}
html[data-skin='autumn'] {
  --sheen: rgba(255, 248, 235, 0.70);
  --sheen-soft: rgba(255, 226, 180, 0.22);
}
html[data-theme='dark'][data-skin='autumn'] {
  --sheen: rgba(255, 214, 160, 0.07);
  --sheen-soft: rgba(255, 190, 120, 0.03);
}

aside.sidebar,
main,
.nav,
.top,
.card,
.stat,
.ugroup,
.cx-panel-inner,
.dialog {
  background-image:
    radial-gradient(135% 95% at 8% -10%, var(--sheen), transparent 58%),
    radial-gradient(90% 70% at 105% 110%, var(--sheen-soft), transparent 62%);
  background-repeat: no-repeat;
}

/* ---------- 22.2 字级：4 级，砍掉 0.5px 噪声 ---------- */
#head .font-semibold {
  font-size: 16px !important;
  font-weight: 650 !important;
  letter-spacing: -0.012em;
  line-height: 1.25;
}
#head .text-xs { font-size: var(--fs-xs) !important; }
.top h1 {
  font-size: 20px;
  font-weight: 650;
  letter-spacing: -0.02em;
  text-wrap: balance;
}
.top .sub { font-size: var(--fs-xs); }
.card-title { font-size: 13px; font-weight: 650; letter-spacing: 0.005em; }
.card-title::before {
  content: '';
  flex: none;
  width: 3px;
  height: 12px;
  border-radius: 2px;
  background: var(--brand-grad);
  box-shadow: 0 0 8px var(--brand-soft-2);
}
.text-\[10px\] { font-size: 11px !important; line-height: 1.35 !important; }
.bubble .mb-1.text-\[11px\] { font-size: 11px; }

/* ---------- 22.3 品牌节奏 ---------- */
aside.sidebar {
  background-image:
    radial-gradient(105% 38% at 0% 0%, var(--brand-wash), transparent 64%),
    radial-gradient(135% 95% at 8% -10%, var(--sheen), transparent 58%);
}
.vtab.nav-active {
  box-shadow: inset 0 0 0 1px var(--brand-soft-2), 0 6px 18px var(--brand-soft);
}
.nav-item.on {
  box-shadow: inset 0 0 0 1px var(--brand-soft-2), 0 4px 14px var(--brand-soft);
}
.cx-sec-title::before {
  content: '';
  display: inline-block;
  width: 5px;
  height: 5px;
  margin-right: 7px;
  border-radius: 50%;
  background: var(--brand);
  box-shadow: 0 0 6px var(--brand-soft-2);
  vertical-align: 1px;
}
.cx-date { letter-spacing: 0.08em; }
.cx-date::before,
.cx-date::after {
  background: linear-gradient(90deg, transparent, var(--brand-line) 26%, var(--brand-line) 74%, transparent);
  opacity: 0.7;
}

/* ---------- 22.4 留白：空状态给一束光 ---------- */
#messages > div.flex.h-full { position: relative; isolation: isolate; color: var(--text-3); font-size: var(--fs-sm); }
#messages > div.flex.h-full::before {
  content: '';
  position: absolute;
  left: 50%; top: 50%;
  width: 420px; height: 420px;
  margin: -210px 0 0 -210px;
  border-radius: 50%;
  background: radial-gradient(circle, var(--brand-soft) 0%, transparent 62%);
  filter: blur(6px);
  z-index: -1;
  pointer-events: none;
}

/* ---------- 22.5 层次：chrome 退后，内容前浮 ---------- */
.nav, .top { box-shadow: var(--shadow-1), var(--glass-highlight); }
aside.sidebar, main { box-shadow: var(--shadow-glass), var(--glass-highlight); }
.card, .stat, .ugroup { box-shadow: var(--shadow-2), var(--glass-highlight); }
.card:hover, .stat:hover { box-shadow: var(--shadow-3), var(--glass-highlight); }

/* ---------- 22.6 字形按钮的字重/基线统一 ---------- */
footer table button,
#head button,
.sidebar button {
  font-family: var(--font-sans);
  font-weight: 400;
  letter-spacing: 0;
}

/* ---------- 22.7 线性图标系统 ---------- */
.nav-item .ico { display: flex; align-items: center; justify-content: center; width: 18px; }
.nav-item .ico svg { width: 17px; height: 17px; display: block; }
.nav-item { gap: 10px; }
.nav-item.on .ico svg { filter: drop-shadow(0 0 6px var(--brand-soft-2)); }

.vtab {
  flex-direction: column;
  gap: 5px;
  min-height: 54px;
  padding: 8px 2px;
  font-size: 11.5px;
  line-height: 1.3;
}
.vtab-ico { display: flex; align-items: center; justify-content: center; height: 18px; color: var(--text-2); }
.vtab-ico svg { width: 17px; height: 17px; }
.vtab.nav-active .vtab-ico { color: currentColor; }
.vtab.nav-active .vtab-ico svg { filter: drop-shadow(0 0 7px var(--brand-soft-2)); }

.cx-ico-btn { display: inline-flex; align-items: center; justify-content: center; line-height: 0; }
.cx-ico-btn svg { display: block; }
.msgmenu.cx-ico-btn svg { opacity: 0.85; }
.msgmenu:hover.cx-ico-btn svg { opacity: 1; }

/* ===========================================================================
   23. 字号收口（覆盖 22.2 里的过渡写法）
   -------------------------------------------------------------------------
   Tailwind 工具类把 10 / 11 / 12 / 14px 混着用，导致一屏七八种字号。
   这里把 Meta 档统一到 11.5、Body 档统一到 13.5，只保留：
     11.5（元信息）/ 13.5（正文）/ 14.5（气泡）/ 16（会话标题）/ 20（页面标题）
   =========================================================================== */
.text-\[10px\],
.text-\[11px\],
.text-xs { font-size: var(--fs-xs) !important; line-height: 1.4 !important; }
.text-sm { font-size: var(--fs-base) !important; }
.bubble .mb-1.text-\[11px\] { font-size: var(--fs-xs); }
.nav-group-label,
.brand-sub { font-size: 11.5px; }

/* 后台字号再收一档：卡片标题 12.5（与表格正文同级，靠字重和品牌条区分） */
.card-title { font-size: 12.5px; }

/* ===========================================================================
   24. 昼夜光影（daylight.js 驱动）
   -------------------------------------------------------------------------
   变量由 JS 每秒写入 <html> 的行内样式，CSS 只负责消费：
     --light-x / --light-y   光源方位（决定所有柔光与高光的方向）
     --day-c1 / --day-c2     天光两团环境色（清晨偏桃、正午偏白蓝、黄昏偏橘玫、夜晚偏藏蓝）
     --day-veil              夜间压暗（越晚越深，只压背景不压内容）
     --sheen / --sheen-soft  面板上那束光（强度随光强、色温随时段）
     --shadow-1..3 / --shadow-glass 阴影的方向、长度、柔度
     --glass-highlight       玻璃内高光（夜间更柔）
   未拿到 JS 变量时有回退值，首屏不会出现"没有光"的空白态。
   =========================================================================== */

body {
  background-image:
    radial-gradient(120% 92% at var(--light-x, 8%) var(--light-y, -10%), var(--day-c1, transparent), transparent 62%),
    radial-gradient(110% 90% at calc(100% - var(--light-x, 8%)) calc(100% - var(--light-y, -10%)), var(--day-c2, transparent), transparent 60%),
    linear-gradient(180deg, var(--day-veil, transparent) 0%, transparent 58%),
    var(--bg-canvas);
}
/* 秋叶风格把画布放在 <html> 上（body 透明），天光也跟着挪过去 */
html[data-skin='autumn'] {
  background-image:
    radial-gradient(120% 92% at var(--light-x, 8%) var(--light-y, -10%), var(--day-c1, transparent), transparent 62%),
    radial-gradient(110% 90% at calc(100% - var(--light-x, 8%)) calc(100% - var(--light-y, -10%)), var(--day-c2, transparent), transparent 60%),
    linear-gradient(180deg, var(--day-veil, transparent) 0%, transparent 58%),
    var(--bg-canvas);
}

/* 面板上那束光跟着太阳走：中午在顶上、清晨贴左边、黄昏滑到右边、夜里只剩一点点冷光 */
aside.sidebar,
main,
.nav,
.top,
.card,
.stat,
.ugroup,
.cx-panel-inner,
.dialog {
  background-image:
    radial-gradient(135% 95% at var(--light-x, 8%) var(--light-y, -10%), var(--sheen), transparent 58%),
    radial-gradient(90% 70% at 105% 110%, var(--sheen-soft), transparent 62%);
}
aside.sidebar {
  background-image:
    radial-gradient(105% 38% at 0% 0%, var(--brand-wash), transparent 64%),
    radial-gradient(135% 95% at var(--light-x, 8%) var(--light-y, -10%), var(--sheen), transparent 58%);
}

/* 夜间：面板自身再压一点点，避免"背景黑了、卡片还发亮" */
html[data-daypart='night'] .card,
html[data-daypart='night'] .stat,
html[data-daypart='night'] .ugroup { border-color: var(--border-line); }
html[data-daypart='night'] aside.sidebar,
html[data-daypart='night'] main { filter: saturate(0.96); }

/* ---------- 外观面板：光照时段的控件 ---------- */
.seg-light { flex-wrap: wrap; }
.seg-light button { padding: 5px 10px; font-size: var(--fs-xs); }
.cx-switch {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-top: 10px;
  font-size: var(--fs-xs);
  color: var(--text-3);
  cursor: pointer;
}
.cx-switch input {
  width: 14px;
  height: 14px;
  accent-color: var(--brand);
  cursor: pointer;
}
.cx-switch[hidden] { display: none; }

/* ===========================================================================
   25. 容器自适应（adaptive.js 驱动）
   -------------------------------------------------------------------------
   为什么不看窗口宽度：聊天区的宽度不等于窗口宽度 —— 侧边栏可以拖到 560px、
   可以收起、后台面板会挤占、移动端还是单栏切换。用 100vw 算出来的气泡宽度
   在「窗口很大但聊天区很窄」时必然顶穿面板（截图里的右侧被裁就是这个原因）。

   所以以 main 的**真实内容盒尺寸**为唯一依据：
     JS  →  main[data-cw] = xs | sm | md | lg | xl      （宽度 5 档）
            main[data-ch] = tiny | short | tall          （高度 3 档）
            main 上写 --chat-w / --chat-h
     CSS →  所有间距、字号、气泡上限、输入区布局都从这里取值，不再出现魔法数字

   分档（阈值带 ±12px 回差，拖拽时不会在临界点来回跳）：
     xs  < 340     手机窄屏 / 被侧栏挤到极窄   三键紧凑 + 气泡 62px 余量
     sm  340–419   手机常规                    输入区转 flex，按钮 40
     md  420–519   小窗口 / 分屏               输入区转 flex，按钮 44
     lg  520–679   常规窗口                    留白收紧，气泡仍按容器算
     xl  ≥ 680     宽屏                        走原设计（气泡 620 上限）
   =========================================================================== */

/* ---------- 25.1 每档一套尺寸变量 ---------- */
main[data-cw] {
  --chat-pad-x: 20px;          /* 消息区左右留白 */
  --chat-pad-y: 24px;
  --chat-gap: 20px;            /* 消息之间的垂直间距 */
  --head-px: 28px;
  --head-py: 19px;
  --composer-btn: 48px;        /* 输入区三个按钮的边长 */
  --composer-gap: 12px;
  --bubble-max: min(620px, calc(var(--chat-w, 720px) - (var(--chat-pad-x) * 2) - 44px));
}
main[data-cw='lg'] {
  --chat-pad-x: 16px; --chat-pad-y: 20px; --chat-gap: 16px;
  --head-px: 22px; --head-py: 17px;
  --composer-gap: 10px;
}
main[data-cw='md'] {
  --chat-pad-x: 14px; --chat-pad-y: 16px; --chat-gap: 14px;
  --head-px: 18px; --head-py: 14px;
  --composer-btn: 44px; --composer-gap: 8px;
}
main[data-cw='sm'] {
  --chat-pad-x: 12px; --chat-pad-y: 14px; --chat-gap: 12px;
  --head-px: 14px; --head-py: 12px;
  --composer-btn: 40px; --composer-gap: 6px;
}
main[data-cw='xs'] {
  --chat-pad-x: 9px; --chat-pad-y: 12px; --chat-gap: 10px;
  --head-px: 10px; --head-py: 9px;
  --composer-btn: 34px; --composer-gap: 4px;
}

/* ---------- 25.2 气泡：上限永远由容器算出来 ---------- */
main[data-cw] .bubble {
  max-width: var(--bubble-max) !important;
  min-width: 0;
  overflow-wrap: anywhere;   /* 长链接、长英文串在窄容器里也要断行，不能顶出面板 */
}
/* 窄档位同步收紧气泡内边距与行高，但正文字号只掉 1px（低于 13px 就不像"读"了） */
main[data-cw='md'] .bubble { padding: 11px 13px; }
main[data-cw='sm'] .bubble { padding: 10px 12px; font-size: var(--fs-base); line-height: 1.6; }
main[data-cw='xs'] .bubble { padding: 8px 10px; border-radius: var(--r-lg); font-size: var(--fs-base); line-height: 1.58; }
main[data-cw='xs'] .bubble.mine, main[data-cw='xs'] .bubble.theirs { border-radius: var(--r-lg); }
main[data-cw='xs'] .msgwrap { gap: 4px !important; }

/* 头像跟着缩：xs 下 32px 头像 + 8px 间距会吃掉气泡 1/5 的宽度 */
main[data-cw='sm'] #messages .avatar { width: 28px !important; height: 28px !important; border-radius: 10px !important; }
main[data-cw='xs'] #messages .avatar { width: 22px !important; height: 22px !important; border-radius: 8px !important; margin-top: 2px !important; }
/* 头像没了宽度，气泡里那行"名字 · 时间"就别再留 6px 下边距 */
main[data-cw='xs'] .bubble .mb-1.text-\[11px\] { margin-bottom: 3px; letter-spacing: 0; }

/* ---------- 25.3 头部与消息区留白 ---------- */
main[data-cw] #head {
  padding: var(--head-py) var(--head-px) !important;
  gap: 8px;
}
main[data-cw] #head > * { min-width: 0; }
main[data-cw] #messages {
  padding: var(--chat-pad-y) var(--chat-pad-x) !important;
}
main[data-cw] #messages > * + * { margin-top: var(--chat-gap) !important; }
/* 日期分割线在窄容器里别撑满：两头渐隐留给它一点呼吸 */
main[data-cw='xs'] .cx-date { margin: 12px 0 6px; gap: 8px; }

/* ---------- 25.4 输入区：表格 → flex ----------
   原结构是 <table> 三列固定 48px + border-spacing:12px。
   容器 320px 时：padding 24 + 间距 60 + 按钮 144 = 228，输入框只剩 60px，
   占位文案竖着排、还带滚动条。改为 md 及以下用 flex，输入框拿剩余宽度。 */
main[data-cw='md'] footer > table,
main[data-cw='sm'] footer > table,
main[data-cw='xs'] footer > table {
  display: flex !important;
  align-items: flex-end;
  width: 100%;
  border-spacing: 0 !important;
  gap: var(--composer-gap);
  padding: 8px !important;
  border-radius: 20px !important;
}
main[data-cw='md'] footer > table > tbody,
main[data-cw='sm'] footer > table > tbody,
main[data-cw='xs'] footer > table > tbody,
main[data-cw='md'] footer > table > tbody > tr,
main[data-cw='sm'] footer > table > tbody > tr,
main[data-cw='xs'] footer > table > tbody > tr {
  display: flex;
  align-items: flex-end;
  width: 100%;
  gap: var(--composer-gap);
}
main[data-cw='md'] footer > table td,
main[data-cw='sm'] footer > table td,
main[data-cw='xs'] footer > table td {
  display: flex;
  align-items: flex-end;
  padding: 0 !important;
  width: auto !important;
  min-width: 0 !important;
  max-width: none !important;
}
/* 三个按钮列：定宽由 --composer-btn 给，别让它们被 flex 压缩 */
main[data-cw='md'] footer > table td[style*='width:48px'],
main[data-cw='sm'] footer > table td[style*='width:48px'],
main[data-cw='xs'] footer > table td[style*='width:48px'] {
  flex: 0 0 var(--composer-btn);
  width: var(--composer-btn) !important;
  min-width: var(--composer-btn) !important;
  max-width: var(--composer-btn) !important;
}
main[data-cw='md'] footer > table button[style*='width:48px'],
main[data-cw='sm'] footer > table button[style*='width:48px'],
main[data-cw='xs'] footer > table button[style*='width:48px'] {
  width: var(--composer-btn) !important;
  height: var(--composer-btn) !important;
  min-width: var(--composer-btn) !important;
  border-radius: 13px !important;
  font-size: 20px !important;
}
main[data-cw='xs'] footer > table button[style*='width:48px'] { font-size: 18px !important; }
/* 输入框吃掉剩下的全部宽度 */
main[data-cw='md'] footer > table td:nth-child(2),
main[data-cw='sm'] footer > table td:nth-child(2),
main[data-cw='xs'] footer > table td:nth-child(2) {
  flex: 1 1 auto;
  min-width: 0 !important;
}
main[data-cw='md'] footer textarea,
main[data-cw='sm'] footer textarea,
main[data-cw='xs'] footer textarea {
  width: 100% !important;
  min-width: 0 !important;
  min-height: 44px !important;
  padding: 2px 4px 2px 6px !important;
  font-size: 15px !important;
  line-height: 1.5 !important;
}
main[data-cw='sm'] footer textarea { min-height: 40px !important; font-size: 14.5px !important; }
main[data-cw='xs'] footer textarea { min-height: 36px !important; font-size: 14px !important; }
main[data-cw] footer { padding: 12px var(--chat-pad-x) 14px !important; }
main[data-cw='xs'] footer { padding: 8px var(--chat-pad-x) 10px !important; }

/* 表情面板固定 352px，窄容器里会横向溢出；改成跟着容器走 */
main[data-cw='md'] #stickerPanel,
main[data-cw='sm'] #stickerPanel,
main[data-cw='xs'] #stickerPanel {
  width: min(352px, calc(var(--chat-w, 100vw) - 20px)) !important;
  right: -4px !important;
}
main[data-cw='xs'] #stickerPanel { right: 0 !important; }
/* 加号菜单同理会顶到左边 */
main[data-cw='xs'] #plusMenu { width: min(160px, calc(var(--chat-w, 100vw) - 24px)) !important; }

/* ---------- 25.5 高度分档：矮容器先砍留白，最后才砍字号 ---------- */
main[data-ch='short'] { --chat-pad-y: 12px; --chat-gap: 12px; }
main[data-ch='short'] #head { padding-top: 10px !important; padding-bottom: 10px !important; }
main[data-ch='tiny'] { --chat-pad-y: 9px; --chat-gap: 8px; }
main[data-ch='tiny'] #head { padding-top: 7px !important; padding-bottom: 7px !important; }
main[data-ch='tiny'] #messages .avatar { display: none; }   /* 高度不够时头像最先让位 */
main[data-ch='tiny'] footer textarea { min-height: 32px !important; max-height: 96px !important; }
main[data-ch='tiny'] .cx-date { margin: 8px 0 4px; }

/* ---------- 25.6 侧边栏收起 ----------
   收起交互已整体重做（只留选项卡 + 悬浮预览），样式全部搬到 §26，
   这里只保留分隔条的基础定位，避免两套规则互相打架。 */
#splitter { position: relative; }
#splitter::after { content: ''; position: absolute; inset: -6px -8px; }

/* ---------- 25.7 极小尺寸兜底（容器 < 300px：被侧栏挤爆的极端情况） ----------
   这里刻意用「容器宽度」而不是 @media 窗口宽度：窗口 1440 也可能因为侧栏被拖到
   560px 而只剩 300px 的聊天区，用窗口断点永远不会触发。 */
main[data-cw-min] { --chat-pad-x: 6px; --composer-btn: 30px; --composer-gap: 3px; --chat-gap: 8px; }
main[data-cw-min] footer > table { padding: 5px !important; }
main[data-cw-min] footer textarea { font-size: 13.5px !important; min-height: 32px !important; }
main[data-cw-min] .bubble { padding: 7px 9px; }
main[data-cw-min] #messages .avatar { display: none; }
main[data-cw-min] #head { padding: 6px 8px !important; }
main[data-cw-min] .bubble .mb-1.text-\[11px\] { display: none; }   /* 名字/时间让位给正文 */
/* 分隔条本身也要能被"抓"到：8px 太细，触控笔/触屏上给 12px 的命中区 */
@media (pointer: coarse) {
  #splitter { width: 12px !important; }
  #sbToggle { width: 22px; height: 52px; }
}

/* ===========================================================================
   26. 侧边栏收起 + 选项卡悬浮预览（sidebar.js 驱动）
   -------------------------------------------------------------------------
   收起：344 → 100，只留竖排选项卡。面板 160ms 淡出后被搬进浮层宿主，
        所以宽度动画期间它不参与 flex 重排；内层行的 min-width 由 JS 冻结，
        否则面板会被逐帧压窄、文字重排 —— 那就是"跳/闪"的来源。
   浮层：#cxRailPop 挂在 body、position:fixed、z-index = --z-overlay。
        侧栏是 .glass（backdrop-filter 会创建 containing block），
        所以浮层必须离开侧栏才能真的相对视口定位；也躲开侧栏的 overflow 裁剪。
   =========================================================================== */

/* ---------- 26.1 收起态骨架 ---------- */
aside.sidebar { overflow: hidden; }
/* 只在收起/展开这一下开过渡：常驻 width 过渡会让拖分隔条变成拖着一团橡皮筋 */
aside.sidebar.cx-sb-anim {
  transition: width var(--dur-3) var(--ease-standard),
              padding var(--dur-3) var(--ease-standard),
              border-radius var(--dur-3) var(--ease-standard);
}
body.sb-collapsed aside.sidebar {
  width: 100px !important;
  min-width: 100px !important;
  padding: 16px 12px 14px !important;
  border-radius: 26px !important;
}
/* 顶部只留头像并居中；其余控件（含顶部收起按钮）在收起态完全让位 */
body.sb-collapsed .cx-sb-top { justify-content: center; padding: 0 0 4px; }
body.sb-collapsed .cx-sb-top .copy,
body.sb-collapsed .cx-sb-top > button:not(#cxSbCollapse),
body.sb-collapsed #cxSbCollapse { display: none !important; }

/* 面板：收起时淡出；搬进浮层后恢复 */
.cx-sb-panel { transition: opacity var(--dur-2) var(--ease-standard); }
body.sb-collapsed aside.sidebar .cx-sb-panel { opacity: 0; pointer-events: none; }
.cx-rail-pop .cx-sb-panel {
  opacity: 1 !important;
  pointer-events: auto !important;
  flex: 0 0 auto;
  width: 322px;
}
.cx-rail-pop .cx-sb-panel #tabContent { max-height: min(520px, calc(100vh - 148px)); }

/* ---------- 26.2 顶部收起按钮 ---------- */
.cx-sb-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  margin-left: auto;
  padding: 0;
  border: 1px solid transparent;
  border-radius: 9px;
  background: transparent;
  color: var(--text-3);
  cursor: pointer;
  transition: background-color var(--dur-2) var(--ease-standard),
              color var(--dur-2) var(--ease-standard),
              border-color var(--dur-2) var(--ease-standard),
              transform var(--dur-2) var(--ease-out);
}
.cx-sb-btn:hover {
  background: var(--brand-wash);
  border-color: var(--border-line);
  color: var(--brand-ink);
}
.cx-sb-btn:active { transform: scale(0.93); }
.cx-sb-btn svg { display: block; }

/* ---------- 26.3 边缘按钮（只在收起态 + 鼠标停到边上时出现） ---------- */
#sbToggle {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%) scale(0.9);
  z-index: 6;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 20px;
  height: 48px;
  padding: 0;
  border: 1px solid var(--border-line);
  border-radius: var(--r-full);
  background: var(--surface-3);
  -webkit-backdrop-filter: blur(var(--glass-blur));
  backdrop-filter: blur(var(--glass-blur));
  color: var(--text-3);
  box-shadow: var(--shadow-2);
  cursor: pointer;
  opacity: 0;
  pointer-events: none;
  transition: opacity var(--dur-2) var(--ease-standard),
              transform var(--dur-2) var(--ease-out),
              color var(--dur-2) var(--ease-standard),
              box-shadow var(--dur-2) var(--ease-standard);
}
/* 收起态把按钮挪到侧栏边缘上：分隔条中心离侧栏右缘 20px（gap 16 + 半宽 4），
   往左让 20px 正好骑在边上，看起来像侧栏自带的手柄而不是漂在缝里 */
body.sb-collapsed #sbToggle { left: calc(50% - 20px); }
body.sb-collapsed #splitter:hover #sbToggle,
body.sb-collapsed #sbToggle:focus-visible {
  opacity: 1;
  pointer-events: auto;
  transform: translate(-50%, -50%) scale(1);
}
#sbToggle:hover { color: var(--brand-ink); box-shadow: var(--shadow-3); }
#sbToggle:active { transform: translate(-50%, -50%) scale(0.93); }
#sbToggle svg { transition: transform var(--dur-3) var(--ease-spring); }
body.sb-collapsed #sbToggle svg { transform: rotate(180deg); }
body.sb-collapsed .grip { opacity: 0 !important; }
#splitter:hover .grip { opacity: 0.3; }
.grip { transition: background-color var(--dur-2), height var(--dur-2), opacity var(--dur-2); }

/* ---------- 26.4 悬浮预览层 ---------- */
.cx-rail-pop {
  position: fixed;
  z-index: var(--z-overlay);
  /* 浮层内部滚到底时不要把滚动链传给页面：否则列表滚过头会带着整页一起动 */
  overscroll-behavior: contain;
  display: flex;
  max-height: min(632px, calc(100vh - 24px));
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  transform: translateX(-8px) scale(0.985);
  transform-origin: left center;
  transition: opacity 160ms var(--ease-standard),
              transform 190ms var(--ease-out),
              visibility 0s linear 190ms;
  will-change: opacity, transform;
}
.cx-rail-pop.is-open {
  opacity: 1;
  visibility: visible;
  pointer-events: auto;
  transform: none;
  transition: opacity 150ms var(--ease-standard),
              transform 180ms var(--ease-out),
              left 180ms var(--ease-out),
              top 180ms var(--ease-out);
}
/* 右侧放不下时翻到左边：滑入方向与尖角一起镜像 */
.cx-rail-pop.is-flipped { transform: translateX(8px) scale(0.985); transform-origin: right center; }
.cx-rail-pop.is-flipped.is-open { transform: none; }

.cx-rail-pop-card {
  position: relative;
  display: flex;
  flex-direction: column;
  min-height: 0;
  padding: 14px;
  border-radius: 20px;
  background: var(--surface-3);
  border: 1px solid var(--border-glass);
  box-shadow: var(--shadow-3), var(--glass-highlight);
  -webkit-backdrop-filter: blur(26px) saturate(150%);
  backdrop-filter: blur(26px) saturate(150%);
}
/* 尖角：始终指向被悬浮的那张选项卡 */
.cx-rail-pop-card::before {
  content: '';
  position: absolute;
  top: var(--cx-caret-y, 26px);
  left: -5px;
  width: 10px;
  height: 10px;
  border-radius: 2px;
  background: var(--surface-3);
  border-left: 1px solid var(--border-glass);
  border-bottom: 1px solid var(--border-glass);
  transform: translateY(-50%) rotate(45deg);
}
.cx-rail-pop.is-flipped .cx-rail-pop-card::before {
  left: auto;
  right: -5px;
  border-left: 0;
  border-bottom: 0;
  border-right: 1px solid var(--border-glass);
  border-top: 1px solid var(--border-glass);
}

/* 命令型入口（朋友圈 / 搜索 / 设置）：没有"下方内容"，给一张说明卡 */
.cx-rail-pop[data-kind='hint'] .cx-sb-panel { display: none; }
.cx-rail-hint {
  display: flex;
  align-items: center;
  gap: 10px;
  min-width: 216px;
  padding: 2px;
}
.cx-rail-hint[hidden] { display: none; }
.cx-rail-hint-ico {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 34px;
  height: 34px;
  flex: none;
  border-radius: 11px;
  background: var(--brand-wash);
  color: var(--brand-ink);
}
.cx-rail-hint-body { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.cx-rail-hint-t { font-size: var(--fs-sm); font-weight: var(--fw-semibold); color: var(--text-1); }
.cx-rail-hint-d { font-size: var(--fs-xs); line-height: 1.45; color: var(--text-3); }
.cx-rail-hint-k {
  margin-left: auto;
  padding-left: 10px;
  font-size: var(--fs-2xs);
  color: var(--text-4);
  white-space: nowrap;
}

/* ---------- 26.5 移动端：没有"收起"这回事，按钮与浮层全部关掉 ---------- */
@media (max-width: 820px) {
  #cxSbCollapse, #sbToggle, .cx-rail-pop { display: none !important; }
  body.sb-collapsed aside.sidebar {
    width: 100% !important;
    min-width: 0 !important;
    padding: 16px 14px !important;
    border-radius: 0 !important;
  }
  body.sb-collapsed .cx-sb-top .copy,
  body.sb-collapsed .cx-sb-top > button { display: revert !important; }
  body.sb-collapsed aside.sidebar .cx-sb-panel { opacity: 1; pointer-events: auto; }
}

/* ---------- 26.6 打印 ---------- */
@media print {
  .cx-rail-pop, #sbToggle, #cxSbCollapse { display: none !important; }
}

/* ===========================================================================
   27. 气泡内文字的对比度收口（2026-10-22）
   -------------------------------------------------------------------------
   qa/a11y-v2.js 换了一个会话后量出新问题（换会话 = 换了一批消息，之前没被抽到）：
     · 气泡上的「我 · 15:24」用 --text-3（mid-tone），压在淡紫/深紫气泡上只有 2.1–2.7:1
     · 五子棋邀请卡的标题/说明同样吃 --text-3 / --brand-ink，2.6–2.9:1
     · 文件卡片的「下载」也是 --text-3，深色下 1.8:1
   这些都是"灰字落在彩色底上"，跟主题无关，但既然量到了就一起收口：
   气泡内的次要文字统一取「气泡文字色」，靠字号/字重分层次，不靠降对比度。
   =========================================================================== */

/* 17.1 气泡时间戳 / 发送人 */
.bubble.mine .mb-1.text-\[11px\] { color: var(--bubble-mine-fg) !important; opacity: 0.86; }
html[data-theme='dark'] .bubble.mine .mb-1.text-\[11px\] { color: #eef1ff !important; opacity: 1; }
html[data-theme='dark'] .bubble.theirs .mb-1.text-\[11px\] { color: var(--text-2) !important; }

/* 17.2 气泡内富卡片（五子棋邀请 / 文件卡）：底色和气泡几乎同色，字必须同档 */
.bubble.mine .bg-indigo-200\/50 { color: var(--bubble-mine-fg); }
html[data-theme='dark'] .bubble.mine .bg-indigo-200\/50 { color: #eef1ff; }
.bubble.mine .bg-indigo-200\/50 .text-slate-400,
.bubble.mine .bg-indigo-200\/50 .text-slate-500,
.bubble.mine .bg-indigo-200\/50 .text-slate-600,
.bubble.mine .bg-indigo-200\/50 .text-indigo-600,
.bubble.mine .bg-indigo-200\/50 .font-semibold { color: inherit !important; }
html[data-theme='dark'] .bubble.mine .bg-indigo-200\/50 .text-slate-400,
html[data-theme='dark'] .bubble.mine .bg-indigo-200\/50 .text-slate-500,
html[data-theme='dark'] .bubble.mine .bg-indigo-200\/50 .text-indigo-600,
html[data-theme='dark'] .bubble.mine .bg-indigo-200\/50 .font-semibold { color: #eef1ff !important; }

/* 17.3 文件卡片里的「下载」 */
.bubble.mine .file-dl { color: var(--text-1) !important; opacity: 1; }
html[data-theme='dark'] .bubble.mine .file-dl { color: #ffffff !important; opacity: 1; }

/* 17.3b 五子棋邀请卡：from-indigo-100 → violet-100 的淡紫渐变卡片（/60 与 /80 两种都有），
   标题原来是 text-indigo-700（→ --brand-ink），压在淡紫底上只有 2.6:1 */
.bubble [class*="from-indigo-100"] .text-indigo-700,
.bubble [class*="from-indigo-100"] .text-indigo-600,
.bubble [class*="from-indigo-100"] .text-slate-400,
.bubble [class*="from-indigo-100"] .text-slate-500,
.bubble [class*="from-indigo-100"] .font-semibold { color: var(--text-1) !important; }
html[data-theme='dark'] .bubble [class*="from-indigo-100"] .text-indigo-700,
html[data-theme='dark'] .bubble [class*="from-indigo-100"] .text-indigo-600,
html[data-theme='dark'] .bubble [class*="from-indigo-100"] .text-slate-400,
html[data-theme='dark'] .bubble [class*="from-indigo-100"] .text-slate-500,
html[data-theme='dark'] .bubble [class*="from-indigo-100"] .font-semibold { color: #eef1ff !important; }

/* 17.4 深色自述气泡再压深一档：白字原本只有 4.65:1（勉强压线），
   压到 7:1 左右，夜间看长段文字更稳，也和"夜间环境光更暗"的设定一致 */
html[data-theme='dark'] { --bubble-mine-bg: linear-gradient(135deg, rgba(70, 84, 196, 0.97), rgba(90, 68, 186, 0.95)); }
html[data-theme='dark'][data-skin='autumn'] { --bubble-mine-bg: linear-gradient(135deg, rgba(96, 66, 168, 0.97), rgba(120, 78, 150, 0.95)); }

/* ===========================================================================
   28. 消息列表：完整展示 + 单条删除 + 多选（msgactions.js 驱动）
   -------------------------------------------------------------------------
   显示不全的三个来源，这里逐个收口：
     · 超长文本气泡 —— 折叠到 420px 并给「展开全文」
     · 消息菜单 —— 原来写死 left:34px，靠右时被 #messages 裁掉；定位改由 JS 按实测位置摆
     · 窄容器里的文件卡 —— 260px 定宽会顶破气泡，按容器宽度让位
   =========================================================================== */

/* ---------- 28.1 长消息折叠 ---------- */
.bubble.ms-clamp {
  max-height: 420px;
  overflow: hidden;
  -webkit-mask-image: linear-gradient(180deg, #000 76%, rgba(0, 0, 0, 0.15) 100%);
  mask-image: linear-gradient(180deg, #000 76%, rgba(0, 0, 0, 0.15) 100%);
}
.ms-more {
  margin-top: 4px;
  padding: 3px 10px;
  border: 1px solid var(--border-line);
  border-radius: var(--r-full);
  background: var(--surface-2);
  color: var(--brand-ink);
  font-size: var(--fs-xs);
  line-height: 1.6;
  cursor: pointer;
  transition: background-color var(--dur-1) var(--ease-standard), color var(--dur-1);
}
.ms-more:hover { background: var(--brand-soft); color: var(--text-1); }

/* ---------- 28.2 头部「多选」按钮 ---------- */
.ms-head-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 34px;
  height: 34px;
  padding: 0;
  border: 1px solid transparent;
  border-radius: 11px;
  background: transparent;
  color: var(--text-3);
  cursor: pointer;
  transition: background-color var(--dur-2) var(--ease-standard),
              color var(--dur-2) var(--ease-standard),
              border-color var(--dur-2) var(--ease-standard);
}
.ms-head-btn:hover { background: var(--brand-wash); border-color: var(--border-line); color: var(--brand-ink); }
.ms-head-btn.active { background: var(--brand); border-color: transparent; color: var(--brand-contrast); }

/* ---------- 28.3 选择态 ---------- */
#messages.ms-on .msgmenu { display: none !important; }   /* 多选态不需要单条菜单 */
#messages.ms-on .message-in { position: relative; padding-left: 30px; border-radius: 14px; transition: background-color var(--dur-1); }
#messages.ms-on .message-in.ms-pick { cursor: pointer; }
#messages.ms-on .message-in.ms-pick:hover { background: var(--brand-soft); }
#messages.ms-on .message-in.ms-pick::before {
  content: '';
  position: absolute;
  left: 2px;
  top: 10px;
  width: 19px;
  height: 19px;
  border: 1.5px solid var(--border-strong);
  border-radius: 50%;
  background: var(--surface-3);
  box-shadow: 0 1px 3px rgba(40, 55, 90, 0.18);
  transition: background-color var(--dur-1), border-color var(--dur-1);
}
/* 自己发的消息靠右：选择圈也放右边，紧贴头像那一侧 ——
   否则宽屏下圈在最左、气泡在最右，中间隔着一整个空白，根本对不上号 */
#messages.ms-on .message-in.justify-end { padding-left: 0; padding-right: 30px; }
#messages.ms-on .message-in.justify-end.ms-pick::before { left: auto; right: 2px; }
main[data-cw-min] #messages.ms-on .message-in.justify-end { padding-right: 26px; }

#messages.ms-on .message-in.ms-sel { background: var(--brand-soft); }
#messages.ms-on .message-in.ms-sel::before {
  content: '✓';
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--brand);
  border-color: var(--brand);
  color: var(--brand-contrast);
  font-size: 12px;
  font-weight: 700;
  line-height: 1;
}

/* ---------- 28.4 吸顶工具条 ---------- */
.ms-bar {
  position: sticky;
  top: 0;
  z-index: 6;
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
  margin: 0 !important;
  padding: 7px 10px 7px 14px;
  border: 1px solid var(--border-line);
  border-radius: var(--r-lg);
  background: var(--surface-3);
  box-shadow: var(--shadow-3);
  -webkit-backdrop-filter: blur(26px) saturate(160%);
  backdrop-filter: blur(26px) saturate(160%);
  color: var(--text-1);
  font-size: var(--fs-sm);
  animation: ms-bar-in 180ms var(--ease-out);
}
@keyframes ms-bar-in { from { opacity: 0; transform: translateY(-6px); } to { opacity: 1; transform: none; } }
.ms-bar-count { font-size: var(--fs-sm); color: var(--text-3); white-space: nowrap; }
.ms-bar-count b { color: var(--text-1); font-size: var(--fs-md); margin: 0 2px; }
.ms-bar-acts { display: flex; align-items: center; gap: 6px; margin-left: auto; flex-wrap: wrap; }
.ms-bar-btn {
  min-height: 30px;
  padding: 0 12px;
  border: 1px solid var(--border-line);
  border-radius: var(--r-full);
  background: var(--surface-2);
  color: var(--text-2);
  font-size: var(--fs-sm);
  cursor: pointer;
  transition: background-color var(--dur-1), color var(--dur-1), border-color var(--dur-1), transform var(--dur-1);
}
.ms-bar-btn:hover { background: var(--brand-soft); color: var(--text-1); border-color: var(--border-strong); }
.ms-bar-btn:active { transform: scale(0.97); }
.ms-bar-btn.ghost { background: transparent; border-color: transparent; color: var(--text-3); }
.ms-bar-btn.ghost:hover { color: var(--text-1); background: var(--brand-soft); }
.ms-bar-btn.danger { background: var(--danger-soft); border-color: transparent; color: var(--danger); font-weight: var(--fw-semibold); }
.ms-bar-btn.danger:hover { background: var(--danger); color: #fff; }
.ms-bar-btn:disabled { opacity: 0.42; pointer-events: none; }

/* 菜单里的「删除」：和 danger 按钮同一套语义色 */
.headmenu-item.ms-danger { color: var(--danger); }
.headmenu-item.ms-danger:hover { background: var(--danger-soft); color: var(--danger); }

/* ---------- 28.5 窄容器：文件卡不再顶破气泡 ---------- */
main[data-cw='xs'] .bubble.has-file { min-width: 0 !important; }
main[data-cw='xs'] .file-card { width: min(260px, calc(var(--chat-w, 320px) - 72px)) !important; }
main[data-cw-min] .bubble.has-file { min-width: 0 !important; }
main[data-cw-min] .file-card { width: 100% !important; max-width: 100% !important; }
main[data-cw-min] #messages.ms-on .message-in { padding-left: 26px; }
main[data-cw-min] .ms-bar { padding: 6px 8px; gap: 6px; }
main[data-cw-min] .ms-bar-btn { padding: 0 9px; font-size: var(--fs-xs); }

/* ---------- 28.6 移动端：工具条换行、按钮更好点 ---------- */
@media (max-width: 820px) {
  .ms-bar { padding: 6px 8px 6px 10px; gap: 8px; }
  .ms-bar-acts { width: 100%; margin-left: 0; justify-content: space-between; }
  .ms-bar-btn { min-height: 36px; padding: 0 10px; flex: 1 1 auto; }
  #messages.ms-on .message-in { padding-left: 28px; }
  .ms-head-btn { width: 32px; height: 32px; }
}

/* ===========================================================================
   29. 云盘（assets/cloud.js 驱动）
   -------------------------------------------------------------------------
   侧栏 tabContent 只有 ~210px 宽，所以行布局是「文件名吃剩余宽度 + 元信息 + 三个图标」，
   动作区默认透明、hover 才出现；触屏没有 hover，≤820px 常显。
   弹窗独立于 .mask/.dialog（那两个是后台的），这里自带一套前缀，避免和后台样式串味。
   =========================================================================== */

.cx-cloud { display: flex; flex-direction: column; gap: 10px; }

.cx-cloud-head { display: flex; align-items: center; justify-content: space-between; padding: 0 2px; }
.cx-cloud-title {
  font-size: var(--fs-xs); font-weight: var(--fw-semibold);
  letter-spacing: .16em; text-transform: uppercase; color: var(--text-3);
}
.cx-cloud-up {
  min-height: 26px; padding: 0 10px;
  border: 1px solid var(--border-line); border-radius: var(--r-full);
  background: var(--surface-2); color: var(--brand-ink);
  font-size: var(--fs-xs); cursor: pointer;
  transition: background-color var(--dur-1), border-color var(--dur-1), color var(--dur-1), transform var(--dur-1);
}
.cx-cloud-up:hover { background: var(--brand-soft); border-color: var(--border-strong); color: var(--text-1); }
.cx-cloud-up:active { transform: scale(.97); }

.cx-cloud-meter { display: flex; flex-direction: column; gap: 6px; padding: 2px; }
.cx-cloud-meter-k {
  display: flex; justify-content: space-between; gap: 8px;
  font-size: var(--fs-2xs); color: var(--text-3); font-variant-numeric: tabular-nums;
}
.cx-cloud-bar { height: 6px; border-radius: var(--r-full); background: var(--border-strong); overflow: hidden; }
.cx-cloud-bar > i {
  display: block; height: 100%; border-radius: var(--r-full);
  background: var(--brand-grad);
  transition: width var(--dur-3) var(--ease-out);
}
.cx-cloud-meter.warn .cx-cloud-bar > i { background: linear-gradient(90deg, #e0a12a, #c9801a); }
.cx-cloud-meter.danger .cx-cloud-bar > i { background: linear-gradient(90deg, #e0574f, #c93a4a); }

.cx-cloud-list { display: flex; flex-direction: column; gap: 4px; }
/* 侧栏只有 ~210px：文件名单行会元信息挤成 0 宽，所以改成名称在上、元信息在下两行 */
.cx-cloud-row {
  display: flex; align-items: center; gap: 6px;
  padding: 6px 8px; border-radius: 12px;
  border: 1px solid transparent; background: var(--surface-1);
  transition: background-color var(--dur-1), border-color var(--dur-1);
}
.cx-cloud-main { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 1px; }
.cx-cloud-row:hover { background: var(--surface-2); border-color: var(--border-line); }
.cx-cloud-name {
  flex: 1 1 auto; min-width: 0;
  font-size: var(--fs-sm); color: var(--text-1);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.cx-cloud-meta { font-size: 10.5px; color: var(--text-3); white-space: nowrap; font-variant-numeric: tabular-nums; }
.cx-cloud-acts { flex: none; display: flex; align-items: center; gap: 1px; opacity: 0; transition: opacity var(--dur-1); }
.cx-cloud-row:hover .cx-cloud-acts, .cx-cloud-row:focus-within .cx-cloud-acts { opacity: 1; }
.cx-cloud-a {
  display: inline-flex; align-items: center; justify-content: center;
  width: 22px; height: 22px; padding: 0;
  border: 0; border-radius: 7px; background: transparent;
  color: var(--text-3); font-size: 12px; line-height: 1; text-decoration: none; cursor: pointer;
  transition: background-color var(--dur-1), color var(--dur-1);
}
.cx-cloud-a:hover { background: var(--brand-wash); color: var(--brand-ink); }
.cx-cloud-a.danger:hover { background: var(--danger-soft); color: var(--danger); }

.cx-cloud-empty {
  padding: 18px 8px; text-align: center;
  font-size: var(--fs-sm); color: var(--text-4);
}
.cx-cloud-tip { padding: 0 2px; font-size: 10.5px; color: var(--text-3); min-height: 14px; }

/* ---------- 开通提示弹窗已改用 .cxm-*（见 §30），这里不再保留单独一套 ---------- */

/* ---------- 触屏 / 窄屏 ---------- */
@media (max-width: 820px), (pointer: coarse) {
  .cx-cloud-acts { opacity: 1; }
  .cx-cloud-a { width: 30px; height: 30px; font-size: 14px; }
  /* 上传按钮原来只有 26px 高，触屏上不好点 */
  .cx-cloud-up { min-height: 34px; padding: 0 14px; font-size: var(--fs-sm); }
}
/* 弹窗的移动端适配在 §30 的 .cxm-* 里，这里不再重复 */

/* ===========================================================================
   30. 统一弹窗（assets/modal.js 驱动）
   -------------------------------------------------------------------------
   主站之前用的是原生 confirm/prompt —— 手机上样式随系统、无法禁用按钮、
   连续弹两次还会被浏览器"阻止此页面再显示对话框"吞掉（点了删除毫无反应）。
   这里是最小的一套皮肤：遮罩 + 卡片 + 输入 + 操作行，全部走既有令牌，
   所以深浅色、秋叶、昼夜光影都自动跟着变。
   后台仍用 admin.css 的 .mask/.dialog（视觉不变，行为由同一个 modal.js 统一）。
   =========================================================================== */

.cxm-mask {
  position: fixed;
  inset: 0;
  z-index: var(--z-modal);
  display: grid;
  place-items: center;
  padding: 20px;
  background: var(--overlay);
  -webkit-backdrop-filter: blur(var(--overlay-blur));
  backdrop-filter: blur(var(--overlay-blur));
  animation: cxm-fade var(--dur-2) var(--ease-out) both;
}
@keyframes cxm-fade { from { opacity: 0; } to { opacity: 1; } }

.cxm-card {
  width: min(440px, 100%);
  max-height: calc(100vh - 40px);
  overflow: auto;
  padding: 20px 22px 18px;
  border: 1px solid var(--border-line);
  border-radius: var(--r-2xl);
  background: var(--surface-3);
  color: var(--text-1);
  box-shadow: var(--shadow-4);
  -webkit-backdrop-filter: blur(var(--glass-blur-lg)) saturate(170%);
  backdrop-filter: blur(var(--glass-blur-lg)) saturate(170%);
  animation: cxm-pop var(--dur-3) var(--ease-spring) both;
}
@keyframes cxm-pop {
  from { opacity: 0; transform: translateY(10px) scale(.97); }
  to { opacity: 1; transform: none; }
}
.cxm-card h3 {
  margin: 0 0 8px;
  font-size: var(--fs-lg);
  font-weight: var(--fw-semibold);
  line-height: 1.35;
  letter-spacing: -.01em;
}
.cxm-desc {
  margin: 0 0 14px;
  font-size: var(--fs-sm);
  line-height: 1.72;
  color: var(--text-3);
  word-break: break-word;
}
.cxm-fields { display: flex; flex-direction: column; gap: 8px; margin-bottom: 4px; }
.cxm-fields input,
.cxm-fields textarea {
  width: 100%;
  min-height: 42px;
  padding: 10px 12px;
  border: 1px solid var(--border-line);
  border-radius: var(--r-md);
  background: var(--surface-sunken);
  color: var(--text-1);
  font: inherit;
  font-size: var(--fs-base);
  outline: 0;
  transition: border-color var(--dur-1), box-shadow var(--dur-1);
}
.cxm-fields textarea { min-height: 84px; resize: vertical; }
.cxm-fields input:focus,
.cxm-fields textarea:focus {
  border-color: var(--brand);
  box-shadow: var(--focus-ring);
}
.cxm-actions {
  display: flex;
  justify-content: flex-end;
  gap: 8px;
  margin-top: 18px;
}
.cxm-btn {
  min-height: 36px;
  padding: 0 16px;
  border: 1px solid var(--border-line);
  border-radius: var(--r-full);
  background: var(--surface-2);
  color: var(--text-2);
  font: inherit;
  font-size: var(--fs-sm);
  cursor: pointer;
  transition: background-color var(--dur-1), color var(--dur-1),
              border-color var(--dur-1), transform var(--dur-1), opacity var(--dur-1);
}
.cxm-btn:hover { background: var(--brand-soft); color: var(--text-1); border-color: var(--border-strong); }
.cxm-btn:active { transform: scale(.97); }
.cxm-btn.primary {
  border-color: transparent;
  background: var(--brand-grad);
  color: var(--brand-contrast);
  font-weight: var(--fw-semibold);
}
.cxm-btn.danger {
  border-color: transparent;
  background: var(--danger-soft);
  color: var(--danger);
  font-weight: var(--fw-semibold);
}
.cxm-btn.danger:hover { background: var(--danger); color: #fff; }
.cxm-btn.ghost { background: transparent; border-color: transparent; color: var(--text-3); }
.cxm-btn.ghost:hover { background: var(--brand-soft); color: var(--text-1); }
.cxm-btn:disabled { opacity: .45; cursor: not-allowed; transform: none; }

@media (max-width: 520px) {
  .cxm-mask { padding: 14px; align-items: end; }
  .cxm-card { width: 100%; padding: 18px 16px 14px; border-radius: var(--r-xl); }
  .cxm-actions { flex-direction: column-reverse; }
  .cxm-btn { width: 100%; min-height: 42px; }
}
@media print { .cxm-mask { display: none !important; } }

/* ===========================================================================
   31. 额度进度条（附件每日流量 / 设置面板）
   -------------------------------------------------------------------------
   云盘面板那套 .cx-cloud-meter 是云盘专用的命名，这里给一份通用版本，
   以后再有"已用/剩余"都可以直接用 .cx-meter，不用再复制一遍。
   文字一律用 --text-3：10.5px 的 --text-4 在深色底上只有 4.3:1，过不了 AA。
   =========================================================================== */
.cx-quota { padding: 2px 0 2px; }
.cx-meter { display: flex; flex-direction: column; gap: 6px; }
.cx-meter-k {
  display: flex; justify-content: space-between; gap: 8px;
  font-size: var(--fs-2xs); color: var(--text-3);
  font-variant-numeric: tabular-nums;
}
.cx-meter-bar {
  height: 6px; border-radius: var(--r-full);
  background: var(--border-strong); overflow: hidden;
}
.cx-meter-bar > i {
  display: block; height: 100%; width: 0;
  border-radius: inherit;
  background: var(--brand-grad);
  transition: width var(--dur-3) var(--ease-out);
}
.cx-meter.warn .cx-meter-bar > i { background: linear-gradient(90deg, #e0a12a, #c9801a); }
.cx-meter.danger .cx-meter-bar > i { background: linear-gradient(90deg, #e0574f, #c93a4a); }
.cx-meter-note {
  font-size: 10.5px; line-height: 1.5;
  color: var(--text-3);
  font-variant-numeric: tabular-nums;
}

/* =============================================================================
   [背景 2026-11-01] 聊天 / 朋友圈自定义背景
   两套背景共用 #messages 这一个容器，靠 body.cx-moments 区分当前在看哪个视图。
   值由 enhance.js 写进 CSS 变量，切换/恢复都不需要重绘 DOM。
   ============================================================================= */
#messages {
  background-size: cover;
  background-position: center center;
  background-repeat: no-repeat;
  transition: background-image .22s ease;
}
body:not(.cx-moments) #messages { background-image: var(--cx-chat-bg, none); }
/* 朋友圈的背景作用在头部那张卡片上（微信也是这么做的：顶部背景图 + 头像 + 签名），
   不再给整个 #messages 铺图 —— 那层会被卡片本身的背景盖住，白设。 */

/* 有背景图时给气泡加一点模糊，花哨的图不至于把文字吃掉可读性 */
body.cx-has-chat-bg:not(.cx-moments) #messages .bubble,


/* 设置面板里的背景按钮行 */
.cx-bg-row { display: flex; gap: 8px; flex-wrap: wrap; margin-top: 6px; }
.cx-hint { margin: 10px 0 0; font-size: 11.5px; line-height: 1.7; color: var(--text-3); }


/* =============================================================================
   [2026-11-01] 朋友圈顶部横幅：背景图 + 可裁剪 + 可拖高度
   -----------------------------------------------------------------------------
   结构（模板在 tpl.js 的 T.momentsList）：
     .cx-moment-card          卡片外壳，position:relative，不裁切（头像要露出去一点）
       .cx-moment-cover       横幅本体，高度由 JS 写 inline style，可拖动底部改
         .cx-cover-layers     裁剪容器：overflow:hidden + 圆角，图像在这里被裁
           img.cx-cover-blur  模糊铺底层（只在「完整显示」模式可见，负责填满两侧）
           img.cx-cover-img   主图。**尺寸和位移全部由 JS 算好后写 inline style** ——
                              因为需要知道原图分辨率和容器尺寸才能算出可移动范围，
                              CSS 的 background 做不到「平移但保证不露白」。
         .cx-cover-veil       底部压暗，保证昵称/头像在亮背景上也看得清
         .cx-cover-hint       「调整背景」提示
         .cx-cover-grip       底部边缘的拖动条 → 改高度
       .cx-cover-id           昵称 + 头像，**位置挂在卡片上**而不是横幅里，
                              这样头像能半浮出横幅下边缘（微信就是这样），
                              也不会被横幅的 overflow:hidden 切掉。
   ============================================================================= */
.cx-moment-card {
  position: relative;
  overflow: visible;
  margin-bottom: 30px;
  /* 不要给底部留 padding —— 那会在横幅下面留一条卡片底色的空带（深色主题下像一条白杠）。
     头像改成直接探出卡片外（.cx-cover-id 的 bottom 为负），落到卡片之间 24px 的间距里，
     既不会被裁切，也不会压到下面那条动态。 */
}

.cx-moment-cover {
  position: relative;
  height: 220px;
  border-radius: 30px;
  overflow: hidden;
  cursor: pointer;
  background:
    radial-gradient(120% 150% at 16% 0%, rgba(255, 255, 255, .34), transparent 58%),
    linear-gradient(135deg, #8297ff, #c4b5fd);
  -webkit-tap-highlight-color: transparent;
  touch-action: pan-y;
}
@media (max-width: 640px) { .cx-moment-cover { height: 170px; } }

.cx-cover-layers {
  position: absolute;
  inset: 0;
  overflow: hidden;
  border-radius: inherit;
  background: #14161d;
}

/* 主图：位置/尺寸全由 enhance.js 写 inline style（left/top 50% + translate(-50%,-50%)） */
.cx-cover-img {
  position: absolute;
  left: 50%;
  top: 50%;
  max-width: none;
  max-height: none;
  transform: translate(-50%, -50%);
  will-change: transform;
  user-select: none;
  -webkit-user-drag: none;
}

/* 「完整显示」模式：主图外面加一圈圆角 + 投影，看起来像一张照片卡 */
.cx-moment-card:not(.cx-cover-fill) .cx-cover-img {
  border-radius: 14px;
  box-shadow: 0 14px 40px rgba(0, 0, 0, .45), 0 0 0 1px rgba(255, 255, 255, .14);
}
/* 「铺满裁剪」模式：主图贴边满铺，不留圆角 */
.cx-moment-card.cx-cover-fill .cx-cover-img { border-radius: 0; box-shadow: none; }

/* 模糊铺底层：只在完整显示模式显示 */
.cx-cover-blur {
  position: absolute;
  left: 50%;
  top: 50%;
  width: 128%;
  height: 128%;
  max-width: none;
  object-fit: cover;
  transform: translate(-50%, -50%);
  filter: blur(30px) saturate(1.25) brightness(.82);
  pointer-events: none;
}
.cx-moment-card.cx-cover-fill .cx-cover-blur { display: none; }

/* 没设置背景时两张图都不显示，露出渐变底 */
.cx-moment-card:not(.cx-has-bg) .cx-cover-img,
.cx-moment-card:not(.cx-has-bg) .cx-cover-blur { display: none; }

.cx-cover-veil {
  position: absolute;
  inset: 0;
  z-index: 2;
  pointer-events: none;
  border-radius: inherit;
  background: linear-gradient(to top, rgba(8, 10, 16, .58), rgba(8, 10, 16, .1) 40%, transparent 62%);
}

/* 昵称 + 头像：挂在卡片上，头像下边缘浮出横幅 26px */
.cx-cover-id {
  position: absolute;
  right: 18px;
  bottom: -22px;
  z-index: 4;
  display: flex;
  align-items: flex-end;
  gap: 10px;
  pointer-events: none;
}
.cx-cover-name {
  /* 往上抬一点：横幅底边在头像中线附近，昵称要留在横幅里面 */
  margin-bottom: 34px;
  color: #fff;
  font-size: 13.5px;
  font-weight: 600;
  letter-spacing: .01em;
  text-shadow: 0 1px 8px rgba(0, 0, 0, .55);
}

/* 头像：容器和图片**必须同圆角** —— 之前容器是方角、图片是 rounded-2xl，
   再套一圈 2px 白描边，就变成「方形白框套圆角照片」，四角还露出容器底色。 */
.cx-cover-avatar {
  width: 56px;
  height: 56px;
  flex: none;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 17px;
  overflow: hidden;
  background: linear-gradient(150deg, #a5b4fc, #ddd6fe);
  color: #4c4a7a;
  font-size: 20px;
  font-weight: 600;
  box-shadow: 0 0 0 3px rgba(255, 255, 255, .92), 0 8px 22px rgba(0, 0, 0, .28);
  pointer-events: auto;
}
.cx-cover-avatar-img {
  width: 100%;
  height: 100%;
  border-radius: inherit;
  object-fit: cover;
  display: block;
}

/* 「调整背景」提示 */
.cx-cover-hint {
  position: absolute;
  left: 16px;
  bottom: 14px;
  z-index: 3;
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 4px 11px;
  border-radius: 999px;
  font-size: 11.5px;
  line-height: 1.5;
  color: rgba(255, 255, 255, .94);
  background: rgba(12, 14, 20, .38);
  backdrop-filter: blur(8px);
  transition: background .18s ease, transform .18s ease;
}
.cx-moment-cover:hover .cx-cover-hint { background: rgba(12, 14, 20, .6); transform: translateY(-1px); }

/* 底部拖动条：拖动改横幅高度 */
.cx-cover-grip {
  position: absolute;
  left: 50%;
  bottom: 0;
  z-index: 5;
  width: 84px;
  height: 16px;
  margin-left: -42px;
  cursor: ns-resize;
  touch-action: none;
  display: flex;
  align-items: center;
  justify-content: center;
}
.cx-cover-grip::before {
  content: '';
  width: 42px;
  height: 4px;
  border-radius: 999px;
  background: rgba(255, 255, 255, .62);
  box-shadow: 0 1px 4px rgba(0, 0, 0, .35);
  transition: width .16s ease, background .16s ease;
}
.cx-cover-grip:hover::before,
.cx-cover-grip.dragging::before { width: 60px; background: rgba(255, 255, 255, .95); }
.cx-moment-cover:hover .cx-cover-grip { opacity: 1; }

/* 拖动 / 编辑时全局禁止选中，避免拖出一片蓝色高亮 */
body.cx-dragging { user-select: none; -webkit-user-select: none; }

/* =============================================================================
   背景裁剪编辑器
   ============================================================================= */
.cx-ce-mask {
  position: fixed;
  inset: 0;
  z-index: 140;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 20px;
  background: rgba(8, 10, 18, .82);
  backdrop-filter: blur(10px);
  animation: ivFade .16s ease;
}
.cx-ce-box {
  width: min(760px, 94vw);
  max-height: 92vh;
  display: flex;
  flex-direction: column;
  gap: 14px;
  padding: 18px;
  border-radius: 24px;
  background: var(--surface-1, #fff);
  border: 1px solid var(--border, rgba(0, 0, 0, .08));
  box-shadow: 0 30px 80px rgba(0, 0, 0, .35);
  overflow: auto;
}
.cx-ce-head { display: flex; align-items: center; gap: 10px; }
.cx-ce-title { font-size: 15px; font-weight: 600; color: var(--text-1); }
.cx-ce-sub { font-size: 11.5px; color: var(--text-3); margin-left: auto; }
.cx-ce-close {
  border: 0; background: transparent; cursor: pointer;
  color: var(--text-3); font-size: 20px; line-height: 1; padding: 2px 6px; border-radius: 8px;
}
.cx-ce-close:hover { background: var(--surface-hover, rgba(0, 0, 0, .06)); }

.cx-ce-stage {
  position: relative;
  width: 100%;
  border-radius: 18px;
  overflow: hidden;
  background: #14161d;
  cursor: grab;
  touch-action: none;
  user-select: none;
}
.cx-ce-stage:active { cursor: grabbing; }
.cx-ce-stage img {
  position: absolute;
  left: 50%;
  top: 50%;
  max-width: none;
  max-height: none;
  transform: translate(-50%, -50%);
  pointer-events: none;
  -webkit-user-drag: none;
}
.cx-ce-grid {
  position: absolute; inset: 0; pointer-events: none;
  background-image:
    linear-gradient(to right, rgba(255, 255, 255, .16) 50%, transparent 50%),
    linear-gradient(to bottom, rgba(255, 255, 255, .16) 50%, transparent 50%);
  background-size: 33.34% 100%, 100% 33.34%;
  opacity: 0;
  transition: opacity .2s ease;
}
.cx-ce-stage.dragging .cx-ce-grid { opacity: 1; }

.cx-ce-row { display: flex; align-items: center; gap: 10px; }
.cx-ce-row label { font-size: 12px; color: var(--text-2); flex: none; }
.cx-ce-row input[type="range"] { flex: 1; accent-color: #8b7cf6; }
.cx-ce-actions { display: flex; gap: 8px; flex-wrap: wrap; }
.cx-ce-actions .spacer { flex: 1; }
.cx-ce-btn {
  border: 1px solid var(--border, rgba(0, 0, 0, .1));
  background: var(--surface-2, #f6f6fa);
  color: var(--text-1);
  font-size: 13px;
  padding: 8px 16px;
  border-radius: 12px;
  cursor: pointer;
  transition: background .16s ease, transform .12s ease;
}
.cx-ce-btn:hover { background: var(--surface-hover, rgba(0, 0, 0, .06)); }
.cx-ce-btn:active { transform: scale(.98); }
.cx-ce-btn.primary {
  border-color: transparent;
  background: linear-gradient(135deg, #8b7cf6, #a78bfa);
  color: #fff;
  font-weight: 600;
}
.cx-ce-btn.ghost { background: transparent; }

/* =============================================================================
   [2026-11-01] 朋友圈图片网格
   -----------------------------------------------------------------------------
   核心思路：**按张数分档，而不是一律三列正方形**。
     · 单图：按原比例展示，最大 240×300，不裁切 —— 横图就横着、竖图就竖着、
       长图整体缩小（不丢内容），任何比例都不会被拉伸。
     · 2 张：两列；3 张：三列；4 张：2×2；5-9 张：三列。
     · 多图档用 object-fit: cover 只裁边缘，比例悬殊也不会变形。
   ============================================================================= */
.mv-grid {
  display: grid;
  gap: 6px;
  margin-top: 8px;
  max-width: 100%;
  justify-content: start;
}

.mv-cell {
  position: relative;
  display: block;
  padding: 0;
  border: none;
  border-radius: 12px;
  overflow: hidden;
  background: rgba(120, 132, 156, .10);
  cursor: zoom-in;
  width: 100%;
  -webkit-tap-highlight-color: transparent;
}
.mv-cell img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;      /* 多图：裁边缘，绝不拉伸 */
}

/* 单图：宽度随图片，限制最大尺寸，长图整体缩小而不是裁掉 */
.mv-grid[data-n="1"] { max-width: 100%; }
.mv-grid[data-n="1"] .mv-cell {
  display: inline-block;
  width: auto;
  max-width: min(72%, 240px);
  border-radius: 14px;
}
.mv-grid[data-n="1"] .mv-cell img {
  width: auto;
  height: auto;
  max-width: 100%;
  max-height: 300px;
  object-fit: contain;
}

/* 多图分档 */
.mv-grid[data-n="2"] { grid-template-columns: repeat(2, minmax(0, 1fr)); max-width: 68%; }
.mv-grid[data-n="3"] { grid-template-columns: repeat(3, minmax(0, 1fr)); max-width: 80%; }
.mv-grid[data-n="4"] { grid-template-columns: repeat(2, minmax(0, 1fr)); max-width: 62%; }
.mv-grid[data-n="5"],
.mv-grid[data-n="6"],
.mv-grid[data-n="7"],
.mv-grid[data-n="8"],
.mv-grid[data-n="9"] { grid-template-columns: repeat(3, minmax(0, 1fr)); max-width: 80%; }

/* 除单图外统一 1:1，保证网格对齐 */
.mv-grid:not([data-n="1"]) .mv-cell { aspect-ratio: 1 / 1; }

/* 加载失败：留一个能看懂的占位，而不是碎图标 */
.mv-cell.mv-broken::after {
  content: '图片加载失败';
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 11px;
  color: rgba(120, 132, 156, .9);
}
.mv-cell.mv-broken img { visibility: hidden; }

.mv-more {
  margin-top: 6px;
  font-size: 11px;
  color: rgba(120, 132, 156, .9);
}

/* 大图预览 */
.img-viewer {
  position: fixed;
  inset: 0;
  z-index: 120;
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(8, 10, 20, .94);
  backdrop-filter: blur(6px);
  animation: ivFade .16s ease;
}
@keyframes ivFade { from { opacity: 0 } to { opacity: 1 } }
.iv-img {
  max-width: 92vw;
  max-height: 88vh;
  object-fit: contain;
  border-radius: 10px;
  box-shadow: 0 24px 70px rgba(0, 0, 0, .55);
}
.iv-close,
.iv-prev,
.iv-next {
  position: absolute;
  border: none;
  cursor: pointer;
  color: #fff;
  background: rgba(255, 255, 255, .14);
  backdrop-filter: blur(8px);
  border-radius: 999px;
  line-height: 1;
  transition: background .18s ease;
}
.iv-close:hover,
.iv-prev:hover,
.iv-next:hover { background: rgba(255, 255, 255, .26); }
.iv-close { top: 18px; right: 20px; width: 40px; height: 40px; font-size: 22px; }
.iv-prev,
.iv-next { top: 50%; margin-top: -22px; width: 44px; height: 44px; font-size: 26px; }
.iv-prev { left: 18px; }
.iv-next { right: 18px; }
.iv-count {
  position: absolute;
  bottom: 22px;
  left: 50%;
  transform: translateX(-50%);
  font-size: 12px;
  color: rgba(255, 255, 255, .78);
  letter-spacing: .06em;
}

/* [2026-11-01] 超长竖图：按原比例会窄成一条，给宽度下限 + 顶部对齐裁切。
   cover 只裁边缘，不拉伸，比例本身不变形。 */
.mv-grid[data-n="1"] .mv-cell.mv-tall {
  width: 150px;
  max-width: 150px;
}
.mv-grid[data-n="1"] .mv-cell.mv-tall img {
  width: 150px;
  height: 260px;
  object-fit: cover;
  object-position: center center;   /* 长图裁切时保中间，通常才是主体内容 */
}
