/* mosse 设计 token —— **单一真源**。见 docs/design-system.md。
   阶段 3.2 从 apps/web/src/styles.css 迁出:admin 重建要用同一套 token,
   而那个文件另有 ~7,900 行 moss web 专属的遗留组件 CSS,admin 不需要。
   ⚠️ 铁律不变:值只存在于这里的 :root / .dark 两个块里,业务 CSS 一律 var(--x)。 */
:root {
  color-scheme: light; /* 让原生控件/滚动条浮层跟随主题(Wave 1) */

  /* —— 背景层(由深到浅:rail > sidebar > canvas) —— */
  --canvas: #ffffff;
  --sidebar: #f6f6f6;
  --rail: #f0f0f0; /* 导航层专属,始终最深一层 */
  --surface-1: #f8f8f8;
  --surface-2: #f0f0f0;
  --surface-3: #e8e8e8;
  --surface: var(--surface-1); /* 别名:消灭 var(--surface,#fff) 地雷 */
  --elevated: var(--surface-1); /* 浮起面(card/popover) */
  /* Elevation 语义(图底关系,Phase 0):L0 内容面=panel,L1 卡片=card。
     亮色反转——内容面浅灰、卡片纯白 + hairline 浮在其上(修"发灰发糊");暗色卡片比面亮一档。 */
  /* Helio 式:窗口/rail = 灰 chrome;sidebar+content = 白色 sheet(浮在灰底上);卡片 = 极浅灰 + 边框。 */
  --panel: var(--canvas); /* L0 内容面 = 白色 sheet */
  --card: var(--surface-1); /* L1 卡片 = 极浅灰填充 + hairline(在白 sheet 上区分) */

  /* —— 文本(纯中性,无蓝调;ink=#171717 对齐 Vercel) —— */
  --text: #171717;
  --muted: #6e6e6e; /* 信息性次要文本(≥4.5:1) */
  --subtle: #767676; /* 装饰/占位(≈4.5:1) */
  --text-faint: #a1a1a1; /* 纯装饰,不承载信息 */

  /* —— 边框 / 焦点(纯中性 hairline) —— */
  --border: #e6e6e6; /* 装饰 hairline(卡/分隔/弹层),对白清晰但克制 */
  --border-strong: #dcdcdc; /* 比 hairline 重一档的**装饰**边:chip / 徽章 / 附件卡 / 浮层 */
  /* 控件轮廓:input / textarea / select / checkbox / outline 按钮。控件是透明底,这条边是
     它唯一的可见轮廓 —— WCAG 1.4.11 要求 3:1。取值按控件**真正坐的底**算(实测 --surface-1
     #f7f8fa,不是纯白),所以是 3.08:1 而不是刚好卡 3.00。
     ⚠️ 别拿它画 chip / 徽章 / 卡片 —— 那些不是控件,加重只会让界面变脏,用 --border-strong。 */
  --border-control: #8e8e8e;
  /* 输入字段描边(input / textarea / select):**填充式形态的专用档**。
     这一族的控件的边界不再只靠这条线,而是「--surface-1 填充 + 这条浅边」两件套
     (iOS 设置页那套写法),所以它可以明显浅于 --border-control,不承担 3:1 的独立轮廓职责 ——
     焦点态由 --ring-color / --accent-fg 接管,那才是必须 ≥3:1 的地方。
     ⚠️ 别拿去画按钮/浮层:那些没有填充兜底,仍需 --border-control。 */
  --border-field: #d4d4d4;
  /* —— 内容表面描边档:卡片/面板/浮层/代码块。**这一档是填充式的开关** ——
     把它改成 transparent,全部内容表面一次性变成"只靠填充分层"。
     控件与 chip 不挂这一档(它们在填充式下仍保留描边),继续用 --border / --border-strong。 —— */
  --surface-border: transparent;

  /* —— 浮层面板(会话详情页的两片:屏 7 的 ⋯ 菜单、屏 5/6 的附件菜单)——
     设计稿 = bg-white + rounded-2xl + border-slate-100(/80) + shadow-xl / shadow-2xl。
     与 --elevated 的区别是**亮色下的底**:设计稿这两片是白底压在白 canvas 上,层级完全由
     阴影承担(不再靠填充明度差);暗色下近黑底上阴影读不出浮起,所以仍按老规矩比 canvas
     亮一档(--surface-2)。因此这一族是「亮=canvas 白 / 暗=surface-2」,不能拿 --elevated 代。
     ⚠️ 别拿它去改 web 的下拉/弹层:那些是 --color-popover(--elevated)的辖区。 —— */
  --menu-surface: #ffffff;
  --menu-border: #f2f2f2; /* 设计稿 slate-100 的**中性等价**:明度相同、去掉蓝调(见铁律 1 的中性色板) */

  /* —— 「浅灰页底」页面的画布色 ——
     有些页面是「浅灰页 + 白卡」(移动端屏 8 Files / 9 Memory / 10 Crons / 13 频道设置 / Board 首页),
     页底压在卡片之下;这些页面要把画布换成下面的值,卡片仍旧走 `--canvas` 白。
     **桌面端(web / desktop / admin)维持 `--canvas` 白** —— 那套界面是「白页 + 灰卡」的反向画法,
     把这里的值改到全局会让 web 的卡片和页面同时偏色。所以真正带色偏的取值**只挂在移动端断点里**,
     见文件末尾的 `@media`;默认值就是 canvas,桌面端等于什么都没改。
     值是 `#F9FAFC`:比 `--surface-1`(#f8f8f8,纯中性)多一丝蓝调(H≈220),
     是亮色下唯一偏离"纯中性"的**表面**档 —— 这是刻意的,别为了纯度把它改回 #f8f8f8。
     原取设计稿的 #F7F8FA;2026-10-09 用户实测嫌偏深,在同一色相上提亮一档到 #F9FAFC
     (再浅就会吃掉「浅灰页 + 白卡」的图底差,别继续往白靠)。 */
  --page-surface: var(--canvas);

  /* —— 浅灰页底上的两族控件面(mobile-pwa 设计稿:Add key / Memory maintenance 屏) ——
     ① 分段胶囊(SegmentedTabs)容器 = 设计稿的 #F4F6FA(比 --page-surface 深一丝的蓝调灰);
        激活枚不落 token —— 直接吃 --accent 填充档(主题色 + 白字,与 PillTabs 同口径);
     ② 字段填充面(选择行等自绘控件):浅灰页上字段必须是**纯白**,否则与透明底的 input 不是一个色。
     暗色不需要蓝调灰:容器/字段各走 surface-2/surface-1(比页底 canvas 亮一档)。 */
  --segmented-bg: #f4f6fa;
  --field-bg: #ffffff;

  --ring-color: var(--accent-fg); /* 焦点环纯色(实色,≥3:1);挂前景档而非填充档——暗色下填充档对底只有 3.06:1 */
  --ring: var(--ring-color); /* --ring 仅作颜色,与 shadcn --color-ring 同义 */

  /* —— 强调色:teal(与 logo 同色系 H188,把饱和度从 31% 拉到 80% 治"黑不黑绿不绿") ——
     一族三档,每档服务一种底,不是补丁:
       --accent        实心填充档(CTA / 选中 / 角标)——底,白字压在上面
       --accent-fg     画布前景档(链接 / @提及 / 活跃图标)——对 canvas ≥4.5:1
       --accent-chip-fg 软底前景档(pill 文字)——对 --accent-soft ≥4.5:1,比前景档再深一步
     三个底不同,所需明度就不同;合成一个 token 必然有一处读不了。 */
  --accent: #0f7a8a; /* 白字压其上 4.61:1 */
  --accent-rgb: 15, 122, 138; /* accent 的 rgb 三元组(rgba() 调透明用,如自己气泡底 / 焦点) */
  --accent-fg: #0d707f; /* 对白 5.76:1 */
  --accent-chip-fg: #0b5f6b; /* 对 --accent-soft 6.38:1 */
  --accent-hover: #0c6675;
  --accent-soft: rgba(15, 122, 138, 0.1); /* 软底填充(青色极浅),严禁当焦点环色 */
  --breathe-rgb: 47, 163, 182; /* 呼吸灯光晕(更亮 teal #2fa3b6;亮暗同值,浅色下也亮) */

  /* —— 动作档:主按钮/提交/确认。当前决定 = 用强调色填充(密集 IM 界面里近黑 CTA 在暗色
     会反成白块,一屏十几个太吵)。想换回 Vercel 式近黑 CTA,只改这两行。 —— */
  --action: var(--accent);
  --action-hover: var(--accent-hover);
  --action-fg: var(--on-accent);

  /* —— 品牌档:logo / 登录页 / 营销面。**不进产品 UI**,所以不跟随主题。 —— */
  --brand: #2c4a53; /* logo slate-teal */
  --brand-2: #16202b; /* logo 深藏青,做品牌渐变末端 */
  --grad-brand: linear-gradient(140deg, var(--brand), var(--brand-2));

  /* 等宽字体栈(命令/代码/ID/时间戳)。此前被 var(--font-mono, …) / var(--mono, …)
     引用 4 次却从未定义,一直跑在各自的回退栈上。 */
  --font-sans: Inter, system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  --font-mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;

  /* —— 选中面(克制路线):导航与列表的**选中态用中性面**,不用强调色。
     强调色只留给真正表示「可交互/有状态」的地方:链接、@提及、反应、未读角标、焦点环。
     装饰性的图标容器底同理走中性(--surface-2),它们不表示任何状态。 —— */
  --selected-bg: var(--surface-3);
  --selected-fg: var(--text);

  /* —— on-color 前景(底色上的文字,消灭散落 #fff) —— */
  --on-accent: #ffffff;
  --on-danger: #ffffff;
  /* 压在图片 / 深色遮罩上的文字。与 --on-accent 同值但**语义不同**:那是"压在强调色填充上",
     这是"压在图像上"。暗色不需要覆写 —— 遮罩本身已随主题加深,白字始终成立。 */
  --on-overlay: #ffffff;

  /* —— 状态色 —— */
  --ok: #2c966c; /* 图形档:压白 3.69:1(旧值 #3db887 只有 2.50,连 3:1 都不过) */
  --ok-text: #257e5b; /* 正文档:压白 4.98:1 —— warn/danger 都有 -text,ok 此前缺这一档 */
  --ok-soft: rgba(61, 184, 135, 0.12);
  --warn: #cc8f00;
  --warn-soft: rgba(204, 143, 0, 0.12);
  /* 正文可读级警示/危险色(小字 ≥4.5:1;--warn/--danger 偏亮,仅作背景/图标/大字)。 */
  --warn-text: #b45309;
  --danger-text: #dc2626;
  --danger: #d24b4e;
  --danger-soft: rgba(210, 75, 78, 0.12);
  --connecting: var(--warn);

  /* —— 装饰专用色(刻意不进语义主题档:依赖图图例 / access 徽标 / mock 标记)。
     这些是图表/徽标/引导的具体色相,不承担主题职责,故单列具名 token。 —— */
  --dep-leg-related: #9aa0a6; /* 依赖图图例:related 边(中性灰,亮暗同值) */
  --dep-leg-parent: #8b7cd8; /* 依赖图图例:parent 边(紫,亮暗同值) */
  --access-shared-fg: #3f6ea6; /* “shared” access 徽标:字 */
  --access-shared-bg: #eaf1f8; /* “shared” access 徽标:底 */
  --access-shared-border: #d7e5f3; /* “shared” access 徽标:边 */
  --cloud-guide-mark: #8b5cf6; /* cloud 引导 mock 标记底(紫,亮暗同值) */
  --agent-ava-fg: #5a5a64; /* 建同事 hero 头像占位字(灰,亮色专用;暗色见 .dark .agent-create-ava) */

  /* —— 输入交互态 —— */
  --placeholder: var(--subtle);

  /* —— 恒定深色皮肤(亮暗同值:toast / 终端块) —— */
  --inverse-surface: #2a2c31;
  --inverse-text: #f3f4f6;
  --code-bg: #14161b;
  --code-fg: #9be0a8;
  --code-meta: #c4ccd6;

  /* —— 浮层遮罩(中性,不带蓝调)—— */
  --overlay-bg: rgba(0, 0, 0, 0.5);

  --shadow-sm: 0 1px 2px rgba(16, 18, 24, 0.06);
  /* 扁平:贴边细影 + 远处极淡扩散(替 16px 大柔影) */
  --shadow-md: 0 1px 2px rgba(16, 18, 24, 0.06), 0 8px 24px -8px rgba(16, 18, 24, 0.12);
  /* **无描边的同色底字段**专用(mobile-pwa chat composer):胶囊是白面,压在同样发白的底栏上,
     边界只有阴影可依。--shadow-md 的第二层带 **-8px spread + 8px 下偏** —— 这两下合起来把
     上沿推掉 16px,压在白底上就是「胶囊上半部看不见边」(用户实测)。
     所以这一档:贴边细影层不变,扩散层**去掉负 spread、下偏收到 4px**,四边都收得到。
     ⚠️ 别用 0 偏移的 1px 环代替它 —— 试过,观感立刻变成「一条描边」而不是阴影(用户实测反馈)。 */
  --shadow-field: 0 1px 2px rgba(16, 18, 24, 0.05), 0 4px 16px rgba(16, 18, 24, 0.12);
  /* **无描边卡面**压在同色页底上专用(mobile-pwa 设置主页:白卡 + 白页)。
     填充差为零,边界只能靠阴影 —— 但卡是**大面**,任何向外扩散的模糊都会读成"一圈光晕":
     先试 16px(--shadow-field 的几何)糊成雾,再试 8px 仍嫌散、颜色也偏深(用户两轮实测)。
     所以这一档是 **0 偏移 + 0 模糊 + 1px spread 的环**:影只落在卡边那一圈,不向外扩散,
     观感就是"一条浅浅的边"。α 0.06 压在 --canvas 白上合出约 #f1f1f1,与其它页卡片的
     --menu-border(#f2f2f2)同档 —— 同一套卡片语言。
     写成 shadow 而不是 border:环不占布局盒,内距与行位置一个像素都不动。
     ⚠️ 同一几何在 --shadow-field 上是被否掉的(那是**控件**,1px 环会被读成"一条描边栏");
        卡片要的**正是**那条边 —— 区别在元素角色,不在几何,别把两档合并。 */
  --shadow-card: 0 0 0 1px rgba(16, 18, 24, 0.06);
  /* —— 附件分类色(移动端 composer 的附件浮层,设计稿屏 7)——
     只干一件事:让「图片」和「文件」在同一张列表里一眼可分。
     它们是**分类装饰色**,不是状态语义(别拿 --ok / --danger 顶替),也不进
     action / accent / brand 三族 —— 那三族各有职责约束,这里要的只是「浅底 + 同色系图标」。
     亮色直接取设计稿的 teal-50/600 与 blue-50/600(`.att-*` 的源头是同一屏)。
     ⚠️ 值刻意**不别名到 --accent**:分类色不该跟着 CTA 换色走。 */
  --att-image-bg: #f0fdfa;
  --att-image-fg: #0d9488;
  --att-file-bg: #eff6ff;
  --att-file-fg: #2563eb;
  /* 大浮层高程(hovercard / 全屏预览 / hover 微抬)。亮暗同值:这些浮层压在深底或
     图片上,阴影本就是恒定深色(同 --inverse-*),不随主题翻转。 */
  --shadow-lg: 0 8px 28px rgba(0, 0, 0, 0.16); /* 人卡片 popover */
  /* 浮层面板的两档(设计稿屏 5/6/7 直取):⋯ 菜单 = shadow-xl,附件菜单 = shadow-2xl。
     这两档比 --shadow-md 明显更"浮"——设计稿的白底浮层就靠它把边界画出来(见 --menu-surface),
     所以这里不是"大柔影",是**唯一的边界**。亮暗同值:阴影压在白底/近黑上都不随主题翻转。 */
  --menu-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 8px 10px -6px rgba(0, 0, 0, 0.1);
  --menu-shadow-lg: 0 25px 50px -12px rgba(0, 0, 0, 0.25);
  --shadow-lightbox: 0 8px 40px rgba(0, 0, 0, 0.5); /* 全屏图预览 */
  --shadow-lift: 0 6px 18px -12px rgba(0, 0, 0, 0.3); /* 卡片 hover 微抬 */
  /* 装饰「呼吸 / 闪光」辉光(keyframe 动画用)。颜色随 --breathe-rgb 主题自适应,
     几何是动画帧内参数(非高程档),集中在此消灭裸值。 */
  --glow-breathe: 0 0 0 2px rgba(var(--breathe-rgb), 0.9), 0 0 8px 1px rgba(var(--breathe-rgb), 0.4);
  --glow-breathe-peak: 0 0 0 2.5px rgba(var(--breathe-rgb), 0.4), 0 0 14px 4px rgba(var(--breathe-rgb), 0.14);
  --glow-breathe-sm: 0 0 0 1.5px rgba(var(--breathe-rgb), 0.85);
  --glow-breathe-sm-peak: 0 0 0 2px rgba(var(--breathe-rgb), 0.32);
  --glow-flash: 0 0 14px 3px rgba(var(--breathe-rgb), 0.7);
  --glow-flash-out: 0 0 14px 3px rgba(var(--breathe-rgb), 0);
  --glow-flash-dk: 0 0 20px 6px rgba(var(--breathe-rgb), 0.95);
  --glow-flash-dk-dip: 0 0 12px 2px rgba(var(--breathe-rgb), 0.4);
  --glow-flash-dk-2: 0 0 20px 6px rgba(var(--breathe-rgb), 0.85);
  --glow-flash-dk-out: 0 0 18px 5px rgba(var(--breathe-rgb), 0);
  --glow-flash-static: 0 0 12px 2px rgba(var(--breathe-rgb), 0.5);
  /* 间距 scale。基数 4px,组件内部另有 2px 半档 —— 密集型 IM 的行内间距(徽章内边距、
     图标与文字的缝、pill 的上下 padding)在 4px 网格上要么太挤要么太散,半档是必需的,
     不是妥协。`--sp-px` 单独留给 1px 光学微调(与 1px 描边对齐),它不是间距档。 */
  --sp-px: 1px;
  --sp-0-5: 2px;
  --sp-1: 4px;
  --sp-1-5: 6px;
  --sp-2: 8px;
  --sp-2-5: 10px;
  --sp-3: 12px;
  --sp-3-5: 14px;
  --sp-4: 16px;
  --sp-5: 20px;
  --sp-6: 24px;
  --sp-7: 28px;
  --sp-8: 32px;
  --sp-10: 40px;
  --sp-11: 44px;
  --sp-12: 48px;
  --sp-14: 56px;
  /* 最小点击区。WCAG 2.5.8(AA)要求目标 ≥24×24 CSS px —— 这是**尺寸下限**不是间距档,
     所以单列一个语义 token,别拿 --sp-* 凑。 */
  --hit-min: 24px;
  /* 移动端触屏目标下限(mobile-pwa,§9.4)。--hit-min 是桌面下限,触屏由这一档单独约束。 */
  --hit-touch: 44px;
  /* 聚焦柔光晕的宽度。它是**装饰**(对比度由边框换色承担),单列一个 token 免得各处写裸值。 */
  --focus-halo-w: 3px;
  /* 状态点(presence)空心环的描边宽——三处复用,单列免裸值。 */
  --presence-ring-w: 1.5px;
  /* 字距档。此前全站 37 处裸值、**11 个不同值**(还有一处写成 `.02em` 缺前导 0)——
     没有档位就只能各写各的,同类元素(几个大写小标签)字距各不相同。
     letter-spacing 不在 stylelint 的检查属性里,所以一直没人发现。 */
  --ls-tighter: -0.03em; /* 大标题 */
  --ls-tight: -0.02em; /* 中标题 */
  /* 正文(body)。**不是** -0.02 —— 归并那轮我误把它并进 --ls-tight,实测整屏文字变宽;
     修的时候又因为断言匹配到旧注释而静默没插上,body 引用了不存在的 token → 回退成
     normal,反而更宽。两次都是靠像素比对发现的,不是靠读代码。 */
  --ls-body: -0.011em;
  --ls-wide: 0.02em; /* chip / 徽章 */
  --ls-wider: 0.05em; /* 大写小标签(分组标题) */
  --ls-widest: 0.18em; /* 等宽验证码 */
  /* 设置类页面的内容栏宽度。同一个 900px 此前在 max-width ×2 + 媒体查询断点 ×1 里各写一遍 ——
     改栏宽必须三处同改,漏一处就是「内容变宽了但断点没跟上」。 */
  --content-max: 900px;
  /* 头像尺度。这七档本来就成套出现在代码里(18/22/24/32/36/40/52,各 2–4 处),
     只是没有 token 可用 —— 和间距 scale 缺 2px 半档是同一种病:档位在设计师脑子里,
     不在代码里,于是只能写裸值。命名按用途,不按数字。 */
  --avatar-xs: 18px; /* 线程回复堆叠 */
  --avatar-sm: 22px; /* 回执行 */
  --avatar-md: 24px; /* 侧栏 DM 行 / 密集列表 */
  --avatar-lg: 32px; /* rail 上的自己 */
  --avatar-xl: 36px; /* 消息行 */
  --avatar-2xl: 40px; /* 头像基准(post-avatar 默认) */
  --avatar-3xl: 52px; /* agent 主页 / 创建面 hero */
  /* 布局基准:rail 宽度(放宽更大气);白色内容顶栏高度、灰标题栏带高度均独立 */
  --rail-w: 64px;
  /* 可拖拽面板的宽度。默认值在这里,ResizeHandle 拖动时只是**覆盖**它(写到 <html> 的 style 上),
     所以业务 CSS 里不必再写 var(--w-x, 兜底值)——铁律 2:回退值是第二个真源。 */
  --w-sidebar: 232px;
  --w-thread: 360px;
  --header-h: 60px;
  /* 移动端(mobile-pwa):安全区 + 底部胶囊 tab。safe-area 的 0 兜底由 env() 自身提供,
     不写 var(--x, 0) 回退(铁律 2)。--tabbar-h 是胶囊 tab 内容高,不含 --safe-bottom。 */
  --safe-top: env(safe-area-inset-top);
  --safe-right: env(safe-area-inset-right);
  --safe-bottom: env(safe-area-inset-bottom);
  --safe-left: env(safe-area-inset-left);
  --tabbar-h: 64px;
  /* 顶部操作栏的行内容高。与 --tabbar-h 同语义:token 只管**内容盒**,
     状态栏(--safe-top)与底部 1px 分隔线都在它之外。全端唯一来源 ——
     所有页面顶栏的行高都取它,页面不再用 min-h + py 凑高度(凑出来的高度会随
     行内有没有 44px 控件而漂:有返回键 = 56,纯标题 = 44)。 */
  --topbar-h: 56px;
  /* 列表行(chat 列表的频道行 / DM 行)的**固定**行高。为什么固定而不是 min-h:
     行内容有一行(只有名称)和两行(名称 + 预览)两种,靠 min-h + py 凑就会一屏两种行高
     (实测 60 vs 67.88,2026-10-09 用户截图反馈间距不一致);固定后单行内容垂直居中、
     两行天然顶满,视觉上每行等高。68 = 两行内容实测合身值(上下各 --sp-2-5 内距 + 内容 48),
     也 ≥ --hit-touch(44),触区不缩水。 */
  --list-row-h: 68px;
  /* 字号 scale —— 唯一来源,所有 font-size 都从这里取,不写魔法数 */
  --fs-xs: 11px; /* 时间戳 / 徽章 / 大写小标签 */
  --fs-sm: 12px; /* 次要标签 / 提示 / 元信息 */
  --fs-base: 13px; /* 侧栏项 / 控件次要文字 */
  --fs-md: 14px; /* 正文 / 消息 / 输入框 */
  --fs-lg: 16px; /* 区块标题 / 详情名 / modal 标题 */
  --fs-xl: 20px; /* 卡片大标题 */
  --fs-2xl: 28px; /* 卡片大标题 */
  --fs-3xl: 40px; /* 登录 / onboarding 主标题 */
  /* 行高 */
  --lh-tight: 1.35; /* 标题 / 紧凑 UI */
  --lh-base: 1.6; /* 正文阅读 */
  /* 字重 */
  --fw-normal: 400;
  --fw-medium: 500;
  --fw-semibold: 600;
  /* 图标尺度(三档,和字号 scale 一样是唯一来源)。lucide 用 size 属性,所以这几个
     token 只在 CSS 直接控制图标尺寸时用;JSX 里按同样的三个值写 size={13|15|18}。 */
  --icon-sm: 13px; /* 内联于小字(fs-sm/xs):角标、chip、元信息 */
  --icon-md: 15px; /* 默认:正文内联、按钮内、列表行 */
  --icon-lg: 18px; /* 大号独立图标:rail 导航、搜索面板、主题切换 */
  --icon-xl: 22px; /* 空态 / 占位 / hero —— 只用于「这里空着」的示意图标 */
  --icon-2xl: 24px; /* 移动端底部 tab 图标(mobile-pwa) */
  /* emoji 字号:快捷条和全量 picker 共用同一个数,写死会立刻漂。
     不挂 --fs-*:emoji 是图形不是文字,跟着正文字阶走会跟不上格子尺寸。 */
  --emoji-size: 18px;
  /* 反应 chip 里的 emoji:比 picker/快捷条小一档 —— chip 只有 24px 高,塞 18px 会把胶囊撑满、
     比旁边 12px 的 count 还抢眼。web .reaction 用 --fs-base(13px)达成同一比例;
     移动端单列语义 token,与 picker 的尺寸不再共进退(mobile-pwa MessageRow ReactionsRow)。 */
  --emoji-chip-size: 14px;
  /* 圆角 scale */
  --r-xs: 6px;
  --r-sm: 8px;
  --r-md: 10px;
  --r-lg: 12px;
  --r-xl: 16px;
  --r-full: 9999px;
  /* 桌面标题栏灰带高度;web 端没有标题栏 = 0。.is-desktop 覆盖成 40。
     必须在这里给默认值,否则业务 CSS 只能写 var(--titlebar-inset) 那种回退。 */
  --titlebar-inset: 0px;
  /* 动效 */
  --ease: cubic-bezier(0.16, 1, 0.3, 1);
  --t-fast: 150ms;
  --t-mid: 200ms;
  --t-nav: 280ms; /* 移动端导航栈 push/pop、sheet 滑入(结构性转场,§9.6) */
  /* 层级 */
  --z-chrome: 40; /* 拖拽带:低于交互浮层、高于内容 */
  --z-backdrop: 100;
  --z-modal: 110; /* Dialog overlay + content(含 shadcn) */
  --z-dropdown: 120; /* select/dropdown/tooltip 等浮层:必须**高于** modal(否则模态框内的下拉弹层被盖在背后,点击无反应) */
  --z-palette: 150; /* 命令面板:介于 modal 与 toast */
  --z-blocking: 160; /* 整页过渡遮罩(切换 workspace,MOSS-143):盖住一切交互浮层,低于 toast(失败提示要露出来) */
  --z-toast: 200; /* toast / update-card:最顶 */
  /* 局部堆叠(组件内部小值,不属 app 级层级 scale,只需压过同容器内相邻内容) */
  --z-raised: 5; /* hover 操作条 / 顶部浮动 pill */
  --z-menu: 30; /* 从控件弹出的小浮层(Private 冲突确认等) */
  --z-popover: 50; /* 人卡片 hovercard */
  --z-lightbox: 1000; /* 全屏媒体预览:盖过一切 */
}

/* 暗色主题(F2.1):只覆盖颜色 token,间距/字号/圆角/动效与亮色共用。
   由 .dark(挂在 <html>,见 theme-store / 防 FOUC 内联脚本)激活。三层背景同样拉开:
   rail(surface-2 最深)> sidebar > canvas。 */
.dark {
  color-scheme: dark;
  --canvas: #0f0f0f;
  --sidebar: #161616;
  --rail: #121212; /* 比 sidebar 更深,修暗色层级倒置 */
  --surface-1: #1c1c1c;
  --surface-2: #242424;
  --surface-3: #2e2e2e;
  --elevated: var(--surface-2); /* 浮层比 canvas 亮一档,配 shadow 出层次 */
  /* 浮层面板:暗色下不能跟 --menu-surface 的亮色值(白),回到「比 canvas 亮一档」这条老规矩,
     边也换回暗色档的 whisper 边(对 --surface-2 的明度比与亮色的 #f2f2f2 对白大致相当)。 */
  --menu-surface: var(--surface-2);
  --menu-border: var(--border);
  /* 分段胶囊与字段面的暗色档(见 :root 那一族的注释):不取蓝调灰,各按「比页底亮一档」走。 */
  --segmented-bg: var(--surface-2);
  --field-bg: var(--surface-1);
  /* 暗色:内容面=最深 canvas,卡片=surface-1 比面亮一档 + hairline(本就成立) */
  --panel: var(--canvas);
  --card: var(--surface-1);
  --text: #ededed;
  --muted: #969696;
  --subtle: #8f8f8f; /* ≥4.5:1 */
  --text-faint: #6e6e6e;
  --border: #2a2a2a;
  --border-strong: #3a3a3a;
  --border-control: #676767; /* 对 --surface-1 #1c1c1c 是 3.01:1 */
  --border-field: #454545; /* 输入字段的填充式浅边(对 --surface-1 #1c1c1c 约 1.6:1,同亮色的比例) */
  /* teal 暗色:填充档仍走深 teal(白字 6.29:1,对底 3.06:1),前景档提亮到 #45b6c8。
     两档差这么多是暗色的固有约束,不是补丁——填充要能压住白字,前景要能在近黑上读出来。 */
  --accent: #16697a; /* 白字压其上 6.29:1;对 canvas 3.06:1 */
  --accent-rgb: 22, 105, 122;
  --accent-fg: #45b6c8; /* 对 canvas 8.05:1 */
  --accent-chip-fg: var(--accent-fg); /* 暗色软底够深,前景档直接够用(6.51:1),不必再开一档 */
  --accent-hover: #1c7d90;
  --accent-soft: rgba(69, 182, 200, 0.14);
  --on-accent: #ffffff;
  --ok: #46c596;
  --ok-text: var(--ok); /* 暗色下 --ok 对 canvas 已 8.84:1,不必再开一档 */
  --ok-soft: rgba(70, 197, 150, 0.16);
  --warn: #d8a425;
  --warn-soft: rgba(216, 164, 37, 0.16);
  --warn-text: #d8a425;
  --danger-text: #e06065;
  --danger: #e06065;
  --danger-soft: rgba(224, 96, 101, 0.16);
  /* 装饰:access “shared” 徽标暗色档(dep-leg / cloud-guide-mark 亮暗同值,不覆写;
     agent-ava-fg 暗色不用——.dark .agent-create-ava 直接覆写为 --muted) */
  --access-shared-fg: #8fb6e0;
  --access-shared-bg: rgba(63, 110, 166, 0.16);
  --access-shared-border: rgba(63, 110, 166, 0.3);
  --input-bg: var(--surface-1);
  --overlay-bg: rgba(0, 0, 0, 0.6);
  --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.4);
  --shadow-md: 0 4px 16px rgba(0, 0, 0, 0.5);
  /* 暗色里投影压在近黑底上本就看不见 —— 胶囊的边界由它自己的 --surface-1 与底栏 --canvas
     的明度差承担,这一档只保留一点近距影。**不要 1px 环**:暗色下那会变成一条描边。 */
  --shadow-field: 0 1px 2px rgba(0, 0, 0, 0.4), 0 4px 16px rgba(0, 0, 0, 0.35);
  /* 卡片档同样是 1px 环,只是暗色下要**提亮**:压在 --elevated(#1c1c1c)上合出约 #2a2a2a,
     与暗色的 --border 同档 —— 暗底上深影本来就画不出边,拿深色画环等于没有边。 */
  --shadow-card: 0 0 0 1px rgba(255, 255, 255, 0.06);
  /* 附件分类色:亮色的「浅底」在暗色不成立(白底上的 4% 淡色压到近黑上等于没有),
     底换成同色相的低透明度,前景提亮到对 --surface-2 有 5:1 以上。 */
  --att-image-bg: rgba(13, 148, 136, 0.16);
  --att-image-fg: #5ec8bd;
  --att-file-bg: rgba(37, 99, 235, 0.18);
  --att-file-fg: #7ea6f5;
  /* inverse/code 为恒定深色,不在 .dark 重定义 */
}

/* —— 「浅灰页底」的实际取值,**只在移动端断点生效**(见 :root 里 --page-surface 的注释) ——
   `--page-surface` 默认等于 `--canvas`,所以桌面端(web / desktop / admin)拿到的还是纯白,
   它们的「白页 + 灰卡」画法一点没变;只有窄视口(< 48rem,移动端 PWA 的实际运行区间)
   才换成 `#F9FAFC`(2026-10-09 由 #F7F8FA 提亮,见 :root 注释)。
   暗色下两个断点的值相同(都等于 canvas):深色画布里浅灰不成立,
   而「页深卡浅」的层级本来就由 --canvas / --elevated 的明度差承担,不需要另给页底一档。 */
@media (max-width: 47.99rem) {
  /* ⚠️ 必须排除 `.dark`:浅灰页底是**亮色专用**档,暗色下它等于 canvas。
     这里曾经写的是裸 `:root` —— 它与 `:root` 的默认值同特异性、又排在 `.dark` 块之后,
     于是窄视口下**暗色也吃到浅灰**:Board 首页 / Files / Memory / Crons / 频道设置
     这几张 `bg-page` 页在暗色下整页惨白,
     而卡片已经是暗色档 —— 页面看起来就是「只有背景和导航没跟着主题变」(2026-09-25 用户截图)。
     `:not(.dark)` 让亮色档根本不落到暗色上,暗色由上面的 `.dark` 块(未覆写)继承 `:root`
     的 `var(--canvas)` —— 与 design-system §2.1 表里「暗 = canvas」一致。 */
  :root:not(.dark) {
    --page-surface: #f9fafc;
  }
}
