/* =============================================================================
   设计系统 —— 一处定义，全站（含应用页）取用。
   调性是既定的：中性灰的暗墙、金色一个重音、全站无衬线（业主 2026-08-03/08-04；
   墙从暖调改成不偏冷也不偏暖的中性灰是 2026-10-17）。
   这里补的是它上面缺的那层——尺度、层次、密度。三条规矩：
     1. 层级先靠字号和字重，颜色是最后一档，不是第一档；
     2. 表面分四级，卡片是「亮一档的面」而不是「描了一圈的框」；
     3. 强调是稀缺品——一屏至多一个实心金按钮。
   这里只放已经有第二、第三个使用者的东西。一个地方要用的样式写在它自己
   身上，等真的重复了再搬上来——先建框架再等人来用，建出来的是死代码。
   旧名（--card/--control/--field/--control-line）全部保留并指向新值：
   应用包的样式表在用它们，改名会静默地把它们变成未定义（初始值）。
   ========================================================================== */
:root {
  /* --- 表面：由深到浅四级。页底最深，卡片浮起来一档，控件再一档。
         旧的 bg/card 只差 9 个色阶，卡片在暗底上几乎显不出来。

         2026-09-19 整体抬了一档（业主：「现在侧栏和聊天框各处太过于黑了，稍微往
         灰色走一点」）。抬的是明度不是色相——暖调暗墙是 2026-08-03/08-04 定的，
         不动；页底从 L* 5 抬到 11，肉眼上是「从黑变成深灰」这一步。
         **判据是对比度不是眼睛**：文字四档跟着抬了一点点，于是每一对文字/底色
         跟抬之前相差都在 ±0.05 以内（muted 和 faint），fg / fg-soft 富余很多，
         降一点仍在 9 以上。算法和那张表在 `test_design_tokens_contrast`。

         2026-10-17 去掉了色相（业主：「很多位置是偏暖色的……都使用中灰色，不带有冷暖
         偏向」）：每一档换成同亮度的纯灰（三个通道相等），亮度一档没动，所以每一对文字/
         底色的对比度跟换之前一样。五级表面正好落在 28、36、44、52、60——等距的八级一档。
         从此**灰阶这几档只许是纯灰**（`test_design_tokens` 钉着）；有颜色的只有下面那几个
         说话的颜色。

         2026-10-27 每一档再抬 5（业主选了「一整片」：顶栏、竖栏、左栏和正文同一块底）。个人会话的
         对话区 10-24 起就单独是这一套（「右侧聊天部分整体背景太黑了」），顶栏和左栏却还在原来那一套上，
         同一块底做不出来；现在全站都是它，那一份单独的就删了。档与档之间的差一点没变。 --- */
  --surface-0: #212121;
  --surface-1: #292929;
  --surface-2: #313131;
  --surface-3: #393939;
  --surface-4: #414141;
  --surface-sunken: #1a1a1a;

  --bg: var(--surface-0);
  --card: var(--surface-1);
  --control: var(--surface-3);
  --field: var(--surface-sunken);

  /* --- 线条三档：分隔用最轻的，描边用常规的，只有需要被看见时用重的。
         2026-09-14 业主：少用边框线，层次尽量靠背景色，页面才是一整块。
         所以线只做「分隔」（页脚上那一道、表头下那一道），不做「描边」：
         按钮、输入框、卡片、标签、菜单、弹窗都是亮一档或暗一档的面，边留着
         但透明——宽度还在，布局一个像素不动。谁要描边，说明它要的其实是
         再亮一档的面。 --- */
  /* 面抬了一档，线跟着抬同样的一档——不然它们在新的底上就看不见了。 */
  --line-soft: #323232;
  --line: #3e3e3e;
  --line-strong: #4a4a4a;
  --control-line: var(--line-strong);

  /* --- 文字四档。最弱的一档是给机器话（id、哈希、时间戳）留的位置：
         它们必须能查到，但不该跟人写的字争。
         最弱这档原来是 #6e6960：在页底上对比度 3.5、卡片上 3.2，低于读得清的
         4.5，而它偏偏用在 11 像素的时刻和说明上（业主 2026-09-15 设计审查）。
         提到 #8a847a：页底 5.1、卡片 4.7，跟 --muted 仍差出一档。
         2026-09-19 面抬了一档，这三档跟着抬——不抬的话 faint 在页底上从 5.1 掉到
         4.7、在卡片上掉到 4.3，正是当初把它提上来要躲的那条线。最亮的 --fg 不动：
         它富余太多，抬了只会把「最重的字」和「次重的字」压扁。 --- */
  --fg: #e9e9e9;
  --fg-soft: #c8c8c8;
  /* 2026-10-27 面抬了 5，这一档跟着抬 7：最亮那块面（surface-4）上不提就只剩 4.19，低于 4.5 的线
     （`test_design_tokens` 量的）。 */
  --muted: #adadad;
  /* 2026-10-27 底抬了 5，这一档跟着抬 3：卡片（surface-1）上的对比度留在 4.5 以上。 */
  --faint: #929292;

  /* --- 金：全站唯一的重音。实心金只给「这一页要你做的那件事」。 --- */
  --gold: #d4b06a;
  --gold-bright: #e8cb8d;
  --gold-soft: rgba(212, 176, 106, 0.09);
  --gold-wash: rgba(212, 176, 106, 0.16);
  --gold-line: rgba(212, 176, 106, 0.38);
  /* 淡金那两档（soft／wash）只给金色记号旁边那一圈晕，和本身就是记号的那几块：进度条、框选和
     拖放的虚框、搜到的字、选中的字、刚跳到的那一句。**金不铺面**（业主 2026-10-17：「都使用中
     灰色」）——9%～16% 的金叠在灰上就是一块黄褐色的灰。选中的行、开着的会话和标签、我说的话的
     气泡、按下的开关，铺的是下面这两档纯灰的「亮一点」：亮度跟原来那两档淡金叠出来的一样。 */
  --lift-soft: rgba(255, 255, 255, 0.06);
  --lift: rgba(255, 255, 255, 0.1);
  /* 首页装饰系统：图纸角标的金、提亮一档的正文。 */
  --gold-mark: rgba(212, 176, 106, 0.42);
  /* 那张脸的眼睛（voice-face.js 里的 MUSTARD，改一处要一起改）：脸旁边替它说话
     的字用这个色——语音房「在说」的状态、对话页「在画图／在想」那一行（业主
     2026-09-14：「aimy 头像后面跟着的状态文字，使用 aimy 眼睛的那个颜色」）。
     它是脸的色不是页面的重音，所以不并进 --gold。 */
  --face-eye: #fd9d23;

  /* --- 说话的颜色。一个状态一个颜色，Core 和每个应用包都照这张表，不另起（2026-10-17 对过
         一遍：排版台的「在跑」原来借了图表的蓝，几处「做完了」是金、几处是绿，几处提醒是金、
         几处是红——同一件事两种颜色，于是颜色什么也没说）：
           在跑、有新的可以看、要你做的那一下、当前这一项 —— 金（只上字、线、点、圈、实心钮；
             铺面的「选中／开着／当前」是亮一档的灰，见上面 --lift）
           成了（做完、通过、切换成功、已复制这种回执）—— 绿
           出事了、要看一眼、提醒、删掉这类不可退的动作 —— 红
           等着、过去了、不适用 —— 灰（--muted／--faint）
         三个之外不再加：要第四个颜色的时候，先问它是不是这四个词之一。图表的系列色、脸的
         颜色、急停钮的深红各只在自己那一处，不拿来说状态。 --- */
  --red: #cf8177;
  /* 红也需要「铺一层」那一档，跟金的 --gold-soft 同一个比例：整行报警的时候，
     实心红会把行里的字全盖掉。描边那一档还是用 --red 本身，红的边就该看得见。 */
  --red-soft: rgba(207, 129, 119, 0.1);
  /* 蘑菇头急停钮那一档：--red 是「出事了」的字色和描边，铺满一颗 108px 的圆钮
     就成了粉的。站台上那颗是深红加白字，所以这里是深的那一档，只有它一个用处
     ——2026-09-07 业主要「和地铁的急停按钮一样」的时候进来的。 */
  --red-deep: #a8241b;
  --red-deep-bright: #bd2c21;
  /* 红点、红数那一档（业主 2026-10-27：「所有地方的红点，都不够红，使用更醒目的颜色」）：--red 是
     字色和描边那一档，偏粉，铺在 7 像素的一个点上就看不出是红。点和带数的小胶囊（标签上、顶栏、
     项目卡片、看板、各应用里「要看一眼」的那一颗）用这一档正红，数字是白字；红字、红边、删掉的钮
     照旧 --red。 */
  --red-mark: #ff453a;
  --green: #478263;
  /* 绿也有「铺一层」那一档（2026-09-24，模型管理页的切换回执：页顶一条、刚换过的
     那一行一层，同一个颜色指着同一件事）。比例跟 --red-soft 一样。 */
  --green-soft: rgba(71, 130, 99, 0.16);
  /* 「在跑」那一档绿（业主 2026-10-31：「派单那里显示的是黄色点点+数字……我们不如改成绿色，代表健康运转」）：
     派单在跑的灯、任务的数、会话清单里那颗转圈的记号、标签上「在跑」的点。--green 是字色那一档，偏暗，铺在
     一颗点、一枚胶囊上看不出是绿；这一档跟 --red-mark 是一对（暗底上同一套系统色），胶囊上用深字。排队
     还是金——在等，不是在跑。光晕那一层比例跟 --gold-line 一样。 */
  --green-mark: #30d158;
  --green-line: rgba(48, 209, 88, 0.38);
  /* 图表用的四个系列色（2026-09-08，能力页的上下文构成条）：金是 Aimy 自己的，
     其余三个只在读数图里出现，不做按钮、不做文字。相邻两色的区分度跑过校验
     （dataviz 校验器，最差一对 ΔE 16.4，色弱 9.8），顺序就是校验时的顺序，别调换。
     那次校验写的底是 #121110，2026-09-19 页底抬成了 #1e1c1a——**这一项不受影响**：
     量的是四个系列色两两之间的距离，不是它们和底的距离。 */
  --chart-1: var(--gold);
  --chart-2: #6f9be0;
  /* 第三色是灰，2026-10-17 跟着灰阶去掉了暖调（同亮度）。 */
  --chart-3: #c9c9c9;
  --chart-4: #5fb58c;
  --chart-track: var(--line-strong);

  --font-sans: -apple-system, "PingFang SC", "Microsoft YaHei", sans-serif;
  /* 全站无衬线（业主 2026-08-03）；标题靠字重不靠字形。 */
  --font-display: var(--font-sans);
  --font-mono: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;

  /* --- 字号是一条音阶，不是一把散点。以 15px 正文为基准，约 1.22 一档。
         页面只从这里取，不写字面值——散点是层级读不出来的主因。 --- */
  /* 最小一档 12（业主 2026-09-15 设计审查：灰字太淡、字太小）。2xs 这个名字留着，
     三十来处在用；它现在就是 12，跟 xs 同号——比 12 小的字在中文里笔画糊成一团。 */
  --text-2xs: 12px;
  --text-xs: 12px;
  --text-sm: 13px;
  --text-base: 15px;
  --text-md: 17px;
  --text-lg: 20px;
  --text-xl: 25px;
  --text-2xl: 32px;
  --text-3xl: 40px;

  /* PingFang SC 只有 Regular/Medium/Semibold 三个真字重，写 650 会被
     舍进 Semibold——那就直接写 600，省得以为自己拿到了第四档。 */
  --weight-normal: 400;
  --weight-medium: 500;
  --weight-semi: 600;

  --leading-tight: 1.3;
  --leading-snug: 1.5;
  --leading-normal: 1.7;
  --leading-relaxed: 2;
  /* 中文不加字距；这一档只给全大写的西文小标签和字母数字。 */
  --tracking-label: 0.08em;

  --space-1: 4px;
  --space-2: 8px;
  --space-3: 12px;
  --space-4: 16px;
  --space-5: 20px;
  --space-6: 24px;
  --space-8: 32px;
  --space-10: 40px;
  --space-12: 56px;
  --space-16: 80px;

  --radius-xs: 5px;
  --radius-sm: 8px;
  --radius: 12px;
  --radius-lg: 16px;
  /* 输入框这一档：一行高 58 的框配 16 的角还是方的，主流对话产品的框在 24–28。 */
  --radius-xl: 24px;
  --radius-pill: 99px;

  /* 暗底上阴影很弱，层次主要靠亮度差；阴影只用来说「这一层浮在上面」。 */
  --shadow-1: 0 1px 2px rgba(0, 0, 0, 0.4);
  --shadow-2: 0 6px 20px rgba(0, 0, 0, 0.38);
  --shadow-3: 0 18px 48px rgba(0, 0, 0, 0.45);

  /* 动效（业主 2026-09-17：「打开的时候都加上一个舒适的动画，高级感一些」）：一条缓动
     曲线、三档时长，全站的「打开」都从这里取，别各写各的数。舒适＝短、位移小、只有出场
     没有入场式的弹跳；高级感来自一致，不来自更多花样。 */
  --ease-out: cubic-bezier(0.2, 0.7, 0.3, 1);
  --motion-quick: 0.16s;
  --motion-base: 0.24s;
  --motion-slow: 0.32s;

  --container-width: 1280px;
}

/* 纸（业主 2026-11-01「方案二更一致。而且用户的感知会很清晰，在项目的语境说话」）：主页上点一件事情，它就地
   长成一大张纸，纸里就是这件事情的会话页本身（`?embed=1`），不另做一套——只在根上把颜色名换成纸的那一套：
   底是一张浅灰的纸，卡和输入框比它亮一档，线是墨色的淡线，字是墨，金色深一档好在浅底上看得清。全站只用这些名字
   上色，所以一页换了名字就整页是纸；哪一处还写死了深色，在这张纸上会露出来，就地改成名字。同晚业主「颜色不要那么
   白，适当调灰色一点，不那么伤眼」：底从 #f2 调到 #e6e6e6，卡和输入框从纯白调到 #f0f0f0，跟主页那张大纸
   （workplace-scene.css 的 --wp-sheet）是同一个灰。纸调灰以后最浅那两档字跟着深下去（11-01 走一圈时量的：--faint
   在纸上只剩 2.8），守深色那套同一条线——test_design_tokens 两套都量。 */
html.paper-skin {
  --surface-0: #e6e6e6;
  --surface-1: #f0f0f0;
  --surface-2: #dddddd;
  --surface-3: #d4d4d4;
  --surface-4: #c9c9c9;
  --surface-sunken: #f0f0f0;
  --line-soft: rgba(21, 21, 21, 0.08);
  --line: rgba(21, 21, 21, 0.14);
  --line-strong: rgba(21, 21, 21, 0.26);
  --fg: #151515;
  --fg-soft: #333333;
  --muted: #545454;
  --faint: #666666;
  --gold: #a87b2c;
  --gold-bright: #8f6420;
  --gold-soft: rgba(168, 123, 44, 0.1);
  --gold-wash: rgba(168, 123, 44, 0.16);
  --gold-line: rgba(168, 123, 44, 0.42);
  --gold-mark: rgba(168, 123, 44, 0.45);
  --lift-soft: rgba(0, 0, 0, 0.04);
  --lift: rgba(0, 0, 0, 0.07);
  --red: #b4483d;
  --red-soft: rgba(180, 72, 61, 0.1);
  --green: #2f7d4f;
  --green-soft: rgba(47, 125, 79, 0.12);
  --chart-3: #555555;
  --shadow-1: 0 1px 2px rgba(0, 0, 0, 0.12);
  --shadow-2: 0 6px 20px rgba(0, 0, 0, 0.12);
  --shadow-3: 0 18px 48px rgba(0, 0, 0, 0.16);
  background: var(--surface-0);
}

* {
  box-sizing: border-box;
}

body {
  margin: 0;
  background: var(--bg);
  color: var(--fg);
  font: var(--text-base) / var(--leading-normal) var(--font-sans);
  /* 暗底上的细字会显得毛躁；抗锯齿调薄一档，字形边缘才干净。 */
  -webkit-font-smoothing: antialiased;
}

a {
  color: inherit;
  text-decoration: none;
}

/* 全站的图标（icons.js 那一张表，`_icon.html` 和 aimyIcons 画的都是它）：颜色跟着字走，大小
   由各处的 width/height 给。在 flex 里不许被压扁；在一行字里跟字的中线对齐。 */
.aimy-icon {
  flex: none;
  vertical-align: middle;
}

/* --- 点的地方不会被「选中」（业主 2026-09-26：「正常交互会出现元素变成蓝色选中状态
   的问题，显得非常不专业」）。浏览器把连点两下当成「选一个词」，于是点两下「应用」
   开合菜单，面板里的应用名就蓝成一片；侧栏、标签、按钮、菜单都是同一回事。
   这些是操作用的东西，不是读的内容：它们整块不可选。正文、消息、文件名照旧能选、
   能复制——那是人要拿走的字。输入框必须写回 text，不然有的内核连光标都放不进去。
   老内核不认 user-select 就是回到原来的样子，不影响布局，所以只是增强。 */
button,
summary,
.button,
[role="button"],
[role="tab"],
[role="menuitem"],
.topbar,
.railbar,
.chat-side,
.topbar-menu-panel,
.apps-tile {
  -webkit-user-select: none;
  -ms-user-select: none;
  user-select: none;
}

input,
textarea,
select,
[contenteditable="true"] {
  -webkit-user-select: text;
  -ms-user-select: text;
  user-select: text;
}

/* 真要选的字（正文、消息）选中了也不是系统蓝，是这一页自己的金——一层淡金底、
   字不变色，跟「当前这一间」同一种说法。 */
::selection {
  background: var(--gold-wash);
  color: var(--fg);
}

/* 手机上一点，整个可点的块闪一下蓝（WebKit 的点按高亮）。点到了由各自的按下样式说，
   不要这一闪。
   这一套只有暗色，在根上说一次（业主 2026-09-30「所有的滚动条使用符合黑色主题的」）：
   浏览器自己画的东西——Mac 接了鼠标就常驻的滚动条（视口的、左栏的、每个能滚的块）、
   原生下拉、原生日期——都照暗色画。原来只有对话页和「文档」各自说了，任务页上的滚动条
   就还是白的（业主 2026-10-24）。页底由 body 的底色铺，不受它影响；Windows 上那条
   ::-webkit-scrollbar 画的照旧。老内核不认就是原样。 */
html {
  -webkit-tap-highlight-color: transparent;
  color-scheme: dark;
}

/* 鼠标点过的按钮不留一圈框：焦点框只给键盘（下面 :focus-visible 那条金框）。老内核
   不认 :focus-visible，这一条整条丢掉，那里照旧是浏览器自己的框——宁可有框也别让
   键盘用户看不见自己在哪儿。 */
:focus:not(:focus-visible) {
  outline: none;
}

/* 标题拉开真正的差距：以前 26/18 挨着正文 15，三档挤在一起谁也不像标题。 */
h1 {
  margin: 0 0 var(--space-3);
  font-size: var(--text-xl);
  font-weight: var(--weight-semi);
  line-height: var(--leading-tight);
  letter-spacing: -0.01em;
}

h2 {
  margin: 0 0 var(--space-3);
  font-size: var(--text-md);
  font-weight: var(--weight-semi);
  line-height: var(--leading-snug);
}

h3 {
  margin: 0 0 var(--space-2);
  font-size: var(--text-base);
  font-weight: var(--weight-semi);
  line-height: var(--leading-snug);
}

.display {
  font-family: var(--font-display);
  font-weight: var(--weight-semi);
  letter-spacing: -0.01em;
}

.sub,
.muted,
.hint {
  color: var(--muted);
  font-size: var(--text-sm);
}

/* --- 按钮分级（业主看到的每一页都按这个分）：
       描边 = 默认，平级的动作长这样；
       安静 = 导航和退路，平时不占视觉重量；
       实心金 = 这一页要你做的那件事，一屏至多一个——目前只有网页私聊的
       「发送」是，就写在它自己身上，等出现第二个再提取成类。
       以前所有按钮长得一模一样、hover 一律描金，于是「克隆成副本」和
       「批准」在页面上一样重。 --- */
/* display 故意不写。页面上有一批 <button> 是当容器用的（任务卡、筛选药丸），
   它们自己声明了 flex 布局；在这里给整个 button 家族加 inline-flex + 居中，
   会把那些卡片的内容挤出卡外——改完第一眼就看见了。

   按钮只有三种高（业主 2026-09-15 设计评审第二批「统一」：全站量出来 15、18、22、
   24、26、33、34、42、44 九种）：小 28（行内、卡片上的次要动作）、中 32（默认）、
   大 40（一页里要你做的那件事、输入框旁的主键）。高度由上下内边距 + 18 的行高 +
   上下各 1 的透明边凑出来，不写 height——当容器用的 <button> 自己定内边距，不被
   一个死高度压扁。只画图标的钮是同高的正方形（.button-icon）。 */
:root {
  --control-sm: 28px;
  --control-md: 32px;
  --control-lg: 40px;
  /* 顶栏有多高。几个页面要减掉它才算得出「剩下多少」（作图台的画布、讲述的
     播放画面、文件库那一屏），2026-09-18 把栏从 64 压到 48 时发现它们各自把
     栏高抄了一份写死在 calc() 里，抄的还是更早的 69——栏改了它们不会跟着改，
     多出来的空白也不会有人报错。一处定义，谁用谁减。 */
  --topbar-h: 48px;
  /* 左侧栏有多宽（业主 2026-09-19：导航挪进侧栏）。240 是对话页那份会话清单量
     出来的下限——一条不折行的标题在更窄的栏里只剩两三个字。收起来是整条藏起来
     （2026-10-14 晚；原来缩成一条 56 宽的窄轨）。 */
  /* 272：会话名要放得下（业主 2026-09-26 方案 C 的稿子就是这个宽）。 */
  --rail-w: 272px;
  /* 最左边那一条竖栏有多宽（业主 2026-10-14：「按方案 1 执行」）。左侧栏排在它右边，正文再往右——
     两处要加它（.has-dock 那几条）。2026-10-28 从 64 收到 56（业主：「图标大小感觉可以往小调整。并且
     整个左侧栏的大小，以及图标在其中的位置都应该优化」）：只有记号的格子是 40 见方、两边各留 8；带名字
     的格子（打开着的应用）48 宽，「模型管理」四个 12 号字正好 48，两边各留 4。 */
  --dock-w: 56px;
  /* 竖栏里每一枚记号多大。10-24 先放到 28、又退到 24（「24吧，现在又太大了」）；2026-10-28 再收到
     20——跟顶栏、左栏的图标一样大。10-31 回到 24、笔画也粗一档（业主：「这样的话，左侧栏更重要了，
     我希望图标能大一点，粗一点」——会话、主页两格搬进来以后，去哪儿全在这一条上）。只有记号的那几格、
     应用格的记号、没有左栏时空着的那一格都从它算。 */
  --dock-icon: 24px;
  /* 桌面端窗口里栏的左内衬（业主 2026-09-19 晚）：macOS 是 92——红绿灯占掉的 68，加一个
     栏自己的边距（见 .is-desktop-mac .topbar）；Windows 是 6。浏览器不读它，那儿是宽屏那一段
     写的 8。原来还有第二个人减它：「对话」那一颗的宽度是「栏宽减掉这一段」，好跟左侧栏对齐；
     2026-10-13 那一颗改成「个人会话」、跟别的标签一样宽。 */
  --bar-left: 0px;
}

/* 桌面端 macOS 的窗口：红绿灯那一段。挂在 body 上（.is-desktop-mac 也在 body
   上），所以栏和标签都继承得到。 */
.is-desktop-mac {
  --bar-left: 92px;
  /* 客户端放大缩小时，整页（连这条栏）按倍数变，红绿灯不变：这一段按倍数反着除，
     在屏幕上就永远是那 92（业主 2026-09-24：缩小时「对话」撞到灯）。倍数是
     shell.js 写在 body 上的 --bar-zoom，没写就是 1。上一行是站得住的旧写法。 */
  --bar-left: calc(92px / var(--bar-zoom, 1));
}

/* 全屏：灯藏起来了，那一段就不存在了，留下的是栏自己的边距——跟浏览器里一样的 8，最左边那颗
   「个人会话」跟底下左侧栏里一行一行的底块左边对齐（2026-10-13 之前这里是 0：那时最左边是跟
   左侧栏同宽的「对话」，它要顶到边）。壳只报一句「我全屏了」（window.js 的
   enter/leave-full-screen → chrome.onChange），shell.js 只挂一个类，多宽多窄全在这一行里算
   ——「壳报事实，页面定版面」。 */
.is-desktop-mac.is-desktop-fullscreen {
  --bar-left: 8px;
  --bar-left: var(--space-2);
}

/* Windows 的窗口：左端没有系统的东西要让，但一颗标签紧贴着窗口边缘长出来也不像
   一件产品（业主 2026-09-28，第一台 Windows 真机：「对话标签按钮和应用左侧边缘
   直接重合了，没有任何边距，看起来不太专业」）。留一个栏自己的边距（2026-10-13 起
   最左边是 Aimy 的头像，这条缝照旧）。它随放大缩小一起变（不像 Mac 的灯
   是固定的屏幕像素），所以不除倍数；全屏也不归零——这里没有灯要让、没有东西要
   顶到边。浏览器里仍是 0：那儿窗口自己有一圈边。
   第一版给了 12，业主看了真机说「太大了，改成一半，有就行了」——所以是 6，不凑
   哪个间距 token：它就是「有一条缝」，不是版面里的一格。 */
.is-desktop-win {
  --bar-left: 6px;
}

button,
.button {
  padding: 6px 12px;
  border: 1px solid transparent;
  border-radius: var(--radius-sm);
  background: var(--control);
  color: var(--fg-soft);
  /* Form controls don't inherit the page font; without this a native
     <button> renders smaller than an <a class="button"> beside it. */
  font: inherit;
  font-size: var(--text-sm);
  font-weight: var(--weight-medium);
  line-height: 18px;
  cursor: pointer;
  transition:
    color 0.15s ease,
    border-color 0.15s ease,
    background 0.15s ease;
}

button:hover,
.button:hover {
  border-color: transparent;
  background: var(--surface-4);
  color: var(--fg);
}

/* 退路、次级导航、行内小动作：平时只是一行字。 */
.button-quiet {
  border-color: transparent;
  background: transparent;
  color: var(--muted);
}

.button-quiet:hover {
  border-color: transparent;
  background: var(--surface-2);
  color: var(--fg);
}

/* 小 28：4 + 18 + 4 + 两道 1 的边。 */
.button-sm {
  padding: 4px 10px;
  font-size: var(--text-xs);
  line-height: 18px;
}

/* 大 40：10 + 18 + 10 + 两道 1 的边。 */
.button-lg {
  padding: 10px 16px;
  font-size: var(--text-base);
  line-height: 18px;
}

/* 只画图标的钮：跟同档的字钮一样高的正方形，图标用 flex 居中（图标是画的不是
   打的，见 icons.js）。默认中档，配 .button-sm / .button-lg 换档。 */
.button-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: var(--control-md);
  height: var(--control-md);
  padding: 0;
}

.button-icon.button-sm {
  width: var(--control-sm);
  height: var(--control-sm);
}

.button-icon.button-lg {
  width: var(--control-lg);
  height: var(--control-lg);
}

.button-icon[hidden] {
  display: none;
}

button:focus-visible,
.button:focus-visible,
a:focus-visible,
input:focus-visible,
textarea:focus-visible,
select:focus-visible,
summary:focus-visible {
  outline: 2px solid var(--gold);
  outline-offset: 3px;
}

button:disabled,
.button[aria-disabled="true"] {
  cursor: wait;
  opacity: 0.58;
}

/* textarea/select were missed here once and rendered as the browser's white
   boxes on this dark page (owner screenshot 2026-08-04) — style the family,
   not the one member a page happened to use first. */
/* 输入框是「亮一档的井」，不是描了边的洞：以前 --field 比页底只深 4 个色阶，
   全靠那一圈线才看得见。 */
input,
textarea,
select {
  padding: 8px 10px;
  border: 1px solid transparent;
  border-radius: var(--radius-sm);
  background: var(--surface-2);
  color: var(--fg);
  font: inherit;
  transition:
    border-color 0.15s ease,
    background 0.15s ease;
}

::placeholder {
  color: var(--faint);
}

textarea {
  resize: vertical;
}

/* 勾选框和单选钮是仅有的两个没被管起来的控件：系统原生画法在暗底上是
   一块刺眼的白方块（作图首页「只看我的」实录）。自己画，勾号用 SVG
   而不是字符——字符自带基线边距，永远不居中。 */
input[type="checkbox"],
input[type="radio"] {
  -webkit-appearance: none;
  appearance: none;
  flex: none;
  width: 16px;
  height: 16px;
  padding: 0;
  border: 1px solid transparent;
  border-radius: var(--radius-xs);
  background: var(--surface-3);
  vertical-align: -3px;
  cursor: pointer;
}

input[type="radio"] {
  border-radius: 50%;
}

input[type="checkbox"]:hover,
input[type="radio"]:hover {
  background: var(--surface-4);
}

input[type="checkbox"]:checked {
  border-color: var(--gold);
  background: var(--gold)
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M3.5 8.5l3 3 6-6.5' fill='none' stroke='%23121110' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E")
    center / 100% no-repeat;
}

input[type="radio"]:checked {
  border-color: var(--gold);
  background: radial-gradient(circle, var(--gold) 0 3.5px, var(--surface-3) 4.5px);
}

/* 卡片是「亮一档的面」，没有边。以前它是「描了一圈的框」，
   于是全站每样东西——读数、列表、正文、空状态——都长成同一个框。
   边留一像素透明的：页面上有一批规则在 hover 时改 border-color，宽度不在
   的话它们一亮就把布局挤一个像素。 */
.card {
  border: 1px solid transparent;
  border-radius: var(--radius);
  background: var(--card);
}

.badge {
  display: inline-flex;
  align-items: center;
  border: 1px solid transparent;
  border-radius: var(--radius-pill);
  background: var(--surface-3);
  padding: 2px 9px;
  font-size: var(--text-2xs);
  line-height: 1.5;
}

.pill {
  border-radius: var(--radius-pill);
  padding: 4px 9px;
  font-size: var(--text-xs);
}

/* 「副本」签：克隆的群、自测会话。记录页 2026-08-28 就有这一枚，任务页
   2026-09-04 也要——住在这里而不是各页一份，是因为两页上长得不一样的话，
   分辨它就成了新的困惑，而分辨正是它存在的理由。方括号不描粗边：它是
   注脚不是状态，状态那一列自有自己的记号。 */
.sandbox-tag {
  display: inline-block;
  margin-right: var(--space-2);
  padding: 0 0.4em;
  border: 1px solid transparent;
  border-radius: 3px;
  background: var(--surface-3);
  font-size: var(--text-xs);
  font-weight: 600;
  color: var(--muted);
  vertical-align: middle;
}
/* `display` 写在类上，就压过了浏览器自带的 `[hidden] { display: none }`——
   自带样式表属于 user-agent 来源，任何作者规则都赢它。任务页详情抬头那一枚签
   是靠 `hidden` 开关的，少了这一条，真群的任务详情会顶着「副本」两个字，
   正好把要消除的困惑反过来造一遍（2026-09-04 探针量出来的）。 */
.sandbox-tag[hidden] { display: none; }

/* 一条栏，48 高（业主 2026-09-18）。桌面端原来在它上面还画了一条自己的标签栏，
   两条摞起来像「把网页装在盒子里」；标签搬进了这一条里（.topbar-tabs），所以
   网页端和桌面端从此是同一份模板、同一份样式，天然一致。

   2026-09-19 业主把导航挪进了左侧栏，顶栏于是只在三种情形下还是一条栏：
   手机（640 以下）、应用页、以及桌面端那条只装标签的窄条。收法在文件末尾
   min-width:641 那一段——这里定义的仍是「一条完整的顶栏长什么样」。

   颜色（业主 2026-10-14：「最左侧竖栏、顶栏，应该一个背景色。会话列表区域，一个颜色，聊天区域一个
   颜色」——之前从左往右是深浅深，「看起来不好看」）：顶栏和最左边那条竖栏是 surface-2，左侧栏
   surface-1，聊天区 surface-0（10-20 从 sunken 抬上来：「深色背景调整的稍微灰色一点」）——从框到
   正文一档比一档深，最亮的是外面那一圈。
   字不在这里选，这条栏上是一排标签和几样小东西，拖着它挪窗口时不该把字选中（桌面端）。 */
.topbar {
  min-height: 48px;
  padding: 0 var(--space-6);
  display: flex;
  align-items: center;
  gap: var(--space-4);
  /* 顶栏、竖栏、左栏和正文是同一块底（业主 2026-10-27 选的「一整片」：「所有的元素尽量的柔和」）——
     原来是五六档灰各占一块，块和块的边又硬又多。地方靠选中那一颗的亮底分，不靠栏自己的颜色。 */
  background: var(--bg);
  -webkit-user-select: none;
  user-select: none;
  /* 钉在窗口顶上（业主 2026-09-19：「顶栏是用来方便切换的，不能随着页面滚动，
     要固定在顶部」）。会滚的页面——任务、能力、用量——原来一滚就把它带走了，
     桌面端连标签都跟着没影，而标签正是用来切换的那个东西。
     用 sticky 不用 fixed：sticky 留着自己那一格，不用在每种页上再补一截
     padding（对话页是 100vh 的 flex 列，补了就撑破）。老内核（AGENTS.md）不认
     sticky，那里它退回今天这样——跟着滚，是可以接受的退化，不是坏掉。
     z-index 比正文高一档，但低于管理菜单面板（20）和弹窗（80）。 */
  position: sticky;
  top: 0;
  z-index: 10;
}

/* 招牌拆成两半（业主 2026-08-29）：头像是「Aimy 是什么」的门，
   「Aimy」是回对话的页签。所以「Aimy」不再是一个更重的招牌，它就是
   页签——跟它右边那几个是同一类东西，长同一个样子最诚实。 */
.topbar-avatar-link {
  flex: none;
  display: inline-flex;
  border-radius: var(--radius-sm);
}

.topbar-avatar-link:hover {
  opacity: 0.85;
}

.topbar-avatar {
  width: 28px;
  height: 28px;
  display: block;
}

/* 页签里唯一一个字重高一档的：它是这套东西的名字，也是回家的路。 */
.topbar-nav-link.topbar-home {
  font-weight: var(--weight-medium);
}

.topbar-nav:empty {
  display: none;
}

.topbar-nav {
  flex: 1;
  display: flex;
  align-items: center;
  gap: var(--space-1);
  flex-wrap: wrap;
}

/* Aimy 自己的页签和管理菜单装在这一格里（业主 2026-09-19）。装进一格是为了
   应用页：那儿整格靠 hidden 收着，桌面端的 shell.js 把属性去掉就放出来——
   一份渲染、一个开关，不是两份模板各画一遍。撑满剩下的地方，好让管理菜单的
   margin-left:auto 仍然把自己顶到右端。 */
.topbar-nav-core {
  flex: 1;
  display: flex;
  align-items: center;
  gap: var(--space-1);
  flex-wrap: wrap;
}

/* 凡是给自己设了 display 的类，必须自带这一条：浏览器自己的 [hidden]{display:none}
   住在用户代理层，输给任何作者声明（2026-09-04「副本」签实录）。少了它，网页端的
   应用页顶上会挂着本该收起来的那一排。 */
.topbar-nav-core[hidden] {
  display: none;
}

/* 管理贴住右端；页签跟着品牌走左边。order 让它排在最后——它是这一格里唯一一个
   「不管后面再放什么都该在末尾」的东西。 */
.topbar-nav .topbar-menu {
  order: 1;
  margin-left: auto;
}

/* --- 桌面端的一排标签（业主 2026-09-18） --------------------------------------
   网页端不长这个东西——浏览器自己有标签，所以模板把它 hidden 着送出去，只有
   桌面端的 shell.js 认出 window.aimyDesktop 之后才把标签画进去。

   它排在整条栏的最前面（业主 2026-09-19）。原来跟在导航后面：导航在对话页上
   有五项、在应用页上只有一句「← 回 Aimy」，于是同一排标签在两种页上差了四百
   像素，切一下就横着跳。标签是窗口的东西，不是这一页的东西，所以它的位置只跟
   窗口有关——左边只有 macOS 的红绿灯。

   各自独立、不共底（业主 2026-09-19：「这一排现在没有其他元素并列了，可以单独
   拆成明显的独立标签，不要挤在一起，宽一些，容易点击。这个原来用来统一的黑色
   背景也不要了」）。09-18 它们是嵌在一个深一档的槽里的一串，那时右边紧挨着导航，
   需要一道界线说清「这边是开着的东西，那边是去哪儿」；当天下午导航搬进了左侧栏，
   这条栏上只剩标签，界线就没有另一边可分——槽于是只剩下把几颗钮挤在一起这一个
   作用。 */
.topbar-tabs {
  flex: none;
  display: flex;
  align-items: center;
  gap: var(--space-2);
}

/* 凡是给自己设了 display 的类，必须自带这一条：浏览器自己的 [hidden]{display:none}
   住在用户代理层，输给任何作者声明（理由同 .topbar-alarm[hidden]）。少了它，
   网页端每一页顶栏上都会挂着一个空槽。 */
.topbar-tabs[hidden] {
  display: none;
}

/* 一颗标签就是一颗钮，而且要一眼看得出能点（业主 2026-09-19：「宽度不够，样式也
   不够明显，没有选中的标签也要有背景色区分，不要完全融于背景。要做成人很喜欢点击
   的样子」）。三档底色：没选中 surface-2、鼠标停上去 surface-3、选中 surface-4，
   一档比一档亮，每一颗都浮在栏（surface-1）上面。
   2026-09-26 再抬一档、加一圈边（业主：「对话、任务，这些背景色不够明显，有时候
   看不出是按钮」）：surface-2 跟栏只差一个色阶，桌面端的栏还是半透明的，底下是
   亮一点的桌面时它就融进去了。现在没选中 surface-3 带一圈 --line、手一过去和选中
   都是 surface-4 带一圈 --line-strong——少用边框线（09-14）管的是页面里的块，这一
   排是按钮，按钮得看得出边。
   2026-10-24 边全撤了（业主指着顶栏「个人／项目」、项目标签和「+」：「这些元素的边框线都移除，
   只留下背景色」）：标签只靠底色跟栏分开，选中靠更亮的底和加粗的字。

   `line-height: 1.4` 是那一点点裁切的解（业主同日：「顶部的标签有轻微裁切文字」）：
   名字那一段 `overflow: hidden`，行高写 1 时行盒只有字号那么高，中文的字形比这
   高出半成，上下就各被削掉一点——放大到字号 15 之后更看得出来。 */
.topbar-tab {
  flex: none;
  min-width: 120px;
  max-width: 260px;
  height: 36px;
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding: 0 var(--space-4);
  border: 0;
  border-radius: var(--radius);
  background: transparent;
  color: var(--fg-soft);
  font-family: inherit;
  font-size: var(--text-base);
  line-height: 1.4;
  cursor: pointer;
  transition:
    background var(--motion-quick) var(--ease-out),
    color var(--motion-quick) var(--ease-out);
}

.topbar-tab:hover {
  background: var(--lift-soft);
  color: var(--fg);
}

/* 选中的那一颗：一圈淡金的整框（业主 2026-10-13 第二轮：「顶栏的页签选中状态不好看，可以使用
   全框，不要使用底部半框（ai 味道太重）」），里面铺一层看得出来的亮底（同日第三轮：「选中状态，
   颜色不够明显……背景色明显一点」——那一版的底只比没选中的亮一档灰，几乎分不出来）。底是
   surface-4 上再叠一层 --lift，叠出来是实色，不跟着底下的东西变。10-13 起叠的是一层淡金，
   2026-10-17 换成纯灰（业主：「都使用中灰色」）：亮度跟淡金那一版一样，明显的是亮，不是颜色。老内核不认叠层就退回前一行
   的 surface-4。2026-10-24 那圈淡金的框跟别的边一起撤了（「只留下背景色」）：你站在哪儿，就是
   最亮的那一颗、字加粗。2026-10-27「一整片」：没选中的标签不再铺灰底，选中的就是唯一亮起来的一块
   （--lift），字重从加粗收到中等——柔和，但站在哪儿一眼还是看得出来。 */
.topbar-tab.is-active {
  background: var(--lift);
  color: var(--fg);
  font-weight: var(--weight-medium);
}

/* 「半亮」：任务、技能、管理这些页不是一个地方，可左栏照着上一个地方画——那个地方的标签只亮一圈
   淡金的框，不铺亮底、字不加粗（业主 2026-10-14 晚，走查第 1 条：顶栏哪颗都不亮，左栏列的是谁的
   会话看不出来）。原来是选中那一圈框、不铺亮底；2026-10-24 框撤了，它是手停上去那一档底
   （surface-4），比没选中的亮一档、比选中的暗一档，字不加粗。 */
.topbar-tab.is-origin {
  background: var(--lift-soft);
}

/* 「看一眼」那一颗（任务、技能、一份文件）原来是斜体带一只眼睛；业主 2026-09-26
   「移除眼睛」——它长得和别的标签一样，只是没有记号。 */

/* --- 顶栏的两组（业主 2026-10-13，方案 A：「可以，执行」）--------------------------
   左边是「地方」：个人会话、项目、开着的每个项目——它们决定左栏显示什么，长得像标签（实心
   的底），站在哪儿哪颗亮、一圈淡金的框。右边是「工具」：技能、任务、应用一排浅色的「记号＋
   字」，没有底也没有框；打开的应用页（文档……）是挨着工具的小标签。地方那一组吃掉中间所有的
   空，所以工具总是钉在右边：左边开、关多少个项目，右边一动不动。

   原来「对话」那一颗跟左侧栏同宽、右边缘对齐栏的右缘（09-19、09-26）；它改叫「个人会话」
   以后跟别的标签一样宽（业主同日：「改成跟其它标签一样宽」）——一排里要放得下好几个项目。 */
.topbar-places {
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  align-items: center;
  gap: var(--space-2);
  overflow: hidden;
}

/* 开着的项目：底浅一档，名字太长就省略；挤了先一起变窄，再挤就从最早开的
   收进「+N」（shell.js 量）。正站在里面的那一颗不收。最窄 128：再窄名字只剩一两个字（960 宽上
   量过 88 那一版，「长…」「广…」认不出是哪个项目），认不出的标签不如收进单子里。 */
.topbar-projects {
  flex: 0 1 auto;
  min-width: 0;
  display: flex;
  align-items: center;
  gap: var(--space-2);
}

.topbar-projects[hidden] {
  display: none;
}

/* 个人会话那一颗（2026-10-26）跟开着的项目同一个样子——同一排里的「地方」，记号不同（气泡），没有 ×，
   所以右边的内衬跟左边一样。 */
.topbar-tab.is-project,
.topbar-tab.is-session {
  flex: 0 1 auto;
  min-width: 128px;
  max-width: 200px;
  height: 32px;
  padding: 0 var(--space-2) 0 var(--space-3);
  background: transparent;
  font-size: var(--text-sm);
}

.topbar-tab.is-session {
  padding: 0 var(--space-3);
}

/* 名字最宽 148（200 减两边内衬 24、记号 20、间距 8），这颗标签本来的宽度就不过它的最宽 200。会话名常是
   一整句话，本来宽三四百：挤的时候按本来宽度分摊、又被最宽 200 卡住，它一点不让，挤压全落在项目标签上
   （820 宽量过：它 200，「深圳湾…」只剩三个字）。 */
.topbar-tab.is-session .topbar-tab-title {
  max-width: 148px;
}

.topbar-tab.is-project:hover,
.topbar-tab.is-session:hover {
  background: var(--lift-soft);
}

/* 开着的项目那几颗自己写了底（比上面两颗浅一档），权重比 .topbar-tab.is-active 高——选中的底
   在这里得再写一遍，不然它压回灰的。 */
.topbar-tab.is-project.is-active,
.topbar-tab.is-session.is-active {
  background: var(--lift);
}

/* 「半亮」那一颗同理：它的底（上面 .topbar-tab.is-origin）在这里也得再写一遍。 */
.topbar-tab.is-project.is-origin,
.topbar-tab.is-session.is-origin {
  background: var(--lift-soft);
}

/* 标签上那个点：红＝有事等你，绿＝在跑（10-31 起绿，原来金；跟左栏切换器里同一个点，marks.js 实时改）。 */
.topbar-tab .chat-space-mark {
  flex: none;
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--green-mark);
}

.topbar-tab .chat-space-mark.is-alert {
  background: var(--red-mark);
}

/* 灰＝只有新消息（10-25：红只留给要你动手的，新消息只亮一个小点）。 */
.topbar-tab .chat-space-mark.is-news {
  background: var(--fg-soft);
}

.topbar-tab .chat-space-mark[hidden] {
  display: none;
}

.topbar-places-more {
  flex: none;
  height: 28px;
  display: flex;
  align-items: center;
  gap: 2px;
  padding: 0 var(--space-2);
  border: 0;
  border-radius: var(--radius-pill);
  background: var(--lift-soft);
  color: var(--fg-soft);
  font-size: var(--text-xs);
  cursor: pointer;
}

.topbar-places-more[hidden] {
  display: none;
}

/* 「+N」跟标签一样没有边（2026-10-24），底比栏亮一档才看得出是一颗钮——栏自己就是 surface-2。 */
.topbar-places-more:hover,
.topbar-places-more[aria-expanded="true"] {
  background: var(--lift);
  color: var(--fg);
}

/* 「再开一个项目」（业主 2026-10-15：改成开关以后「用户可能不清楚点击项目按钮可以继续打开多个项目」）：
   开着的项目标签后面一颗「+」，跟浏览器标签后面那颗一个意思；高跟项目标签一样 32，正方形，一排还是一排。
   原来跟「应用」那一枚一样是空心的——一圈描边、没有底；2026-10-24 描边撤了（业主：「这些元素的边框线都
   移除，只留下背景色」），它跟没选中的项目标签同一档底，手一过去亮一档。 */
.topbar-places-new {
  flex: none;
  width: 32px;
  height: 32px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: var(--radius);
  background: transparent;
  color: var(--muted);
  transition:
    background var(--motion-quick) var(--ease-out),
    color var(--motion-quick) var(--ease-out);
}

.topbar-places-new:hover {
  background: var(--lift-soft);
  color: var(--fg);
  text-decoration: none;
}

.topbar-places-new[hidden] {
  display: none;
}

/* 「+N」点开的单子：fixed（shell.js 按那颗钮的位置摆），不被地方那一组的 overflow 裁掉。 */
.topbar-places-menu {
  position: fixed;
  z-index: 70;
  min-width: 220px;
  max-width: 320px;
  padding: 6px;
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  background: var(--surface-2);
  box-shadow: var(--shadow-2);
}

.topbar-places-menu[hidden] {
  display: none;
}

.topbar-places-item {
  width: 100%;
  display: flex;
  align-items: center;
  gap: 10px;
  padding: var(--space-2) var(--space-3);
  border: 0;
  border-radius: var(--radius-sm);
  background: transparent;
  color: var(--fg-soft);
  font: inherit;
  font-size: var(--text-sm);
  text-align: left;
  cursor: pointer;
}

.topbar-places-item:hover {
  background: var(--surface-3);
  color: var(--fg);
}

/* 单子里的字是 13 号，记号留在原来的 16（栏上的标签 10-24 起是 20，配的是 15 号的字）。 */
.topbar-places-item .topbar-tab-face {
  width: 16px;
  height: 16px;
}

.topbar-places-item > span {
  min-width: 0;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}

/* 打开的那几颗：站在哪一个里，那一颗的记号是金的。地方那几颗不参加——它们亮的是亮底和
   一圈淡金的框（见上面「选中的那一颗」）。 */
.topbar-tab.is-app.is-active .topbar-tab-face {
  color: var(--gold);
}

/* 一类一个记号（业主 2026-09-19）。三枚同一个尺寸、同一个颜色，颜色跟着标签走
   ——没选中的淡、选中的亮，记号和名字一起变，不另设一档。
   20 见方（业主 2026-10-24：「顶部的个人、项目切换按钮，图标显得小了，可以稍微加大」）：这套记号画在
   20 的格子里、四周留着空，16 见方时人形只有 11 高，比旁边 15 号的字矮一截；20 时跟字一样高。
   「个人 / 项目」开关和后面开着的项目标签用的是这同一份（10-16「尽量使用一样的大小」），一起变。 */
.topbar-tab-face {
  flex: none;
  width: 20px;
  height: 20px;
  display: block;
  color: inherit;
}

/* 名字吃掉多出来的宽度，关闭钮才会贴着标签的右边缘。不这么写，一颗比 min-width
   还短的标签（「Aimy」「作图」）会把名字、数字、叉都堆在左半边，右半边空着，
   看上去像没画完。min-width:0 是让 ellipsis 在 flex 里生效的那一条。 */
.topbar-tab-title {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  text-align: left;
}

.topbar-tab-badge {
  flex: none;
  min-width: 16px;
  height: 16px;
  padding: 0 var(--space-1);
  border-radius: var(--radius-pill);
  background: var(--red-mark);
  color: var(--fg);
  font-size: var(--text-2xs);
  font-weight: var(--weight-semi);
  line-height: 16px;
  text-align: center;
}

/* 只有新回话、没有等你点头的：不写数，一个灰点（10-25：红数只数要你动手的件数）。 */
.topbar-tab-badge.is-news {
  min-width: 0;
  width: 7px;
  height: 7px;
  padding: 0;
  background: var(--fg-soft);
}

/* 同上：没有未读的时候这枚数字靠 hidden 收着。 */
.topbar-tab-badge[hidden] {
  display: none;
}

/* 标签长大了，叉也跟着：20 见方的落点，图形还是 11。它自己 stopPropagation，
   所以这 20 像素是「关掉」，标签剩下的都是「切过去」——两个动作离得开。 */
.topbar-tab-close {
  flex: none;
  width: 20px;
  height: 20px;
  margin-right: -4px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: var(--radius-xs);
  color: var(--muted);
}

.topbar-tab-close:hover {
  background: var(--lift);
  color: var(--fg);
}

.topbar-tab-close svg {
  width: 14px;
  height: 14px;
  display: block;
}

/* 「应用」那一枚（业主 2026-09-19 晚：「把『应用』放到会话按钮后面，hover 就能
   看到应用，点击就能打开应用」）。它由 shell.js 挪进托盘的第二位，排在「对话」
   之后——也就是横向一跨过左侧栏那一列就是它。
   **它是三种里唯一空心的那一个**：一圈描边、没有底。理由在上面那段长注释里——
   它是一扇门，不是一个地方，按下去出来的是菜单而不是一页。高和圆角跟标签一样，
   所以这一排还是一排；不一样的只有「实心／空心」这一件事。
   宽度不设 min-width：标签有，是因为里头是长短不一的名字；这一枚永远是两个字。
   选择器写全 `.topbar-menu > summary.topbar-apps-button`，不是图好看：下面那条
   给所有菜单写的 `.topbar-menu > summary` 权重比单个类高，又排在后面，光写类名
   的话 padding 会被它的 10px 顶掉。权重压过去，两条的先后就不用记了。
   三角由那条公共规则收（list-style + ::-webkit-details-marker 各一条，两个内核
   收法不一样），这里不再抄一遍。 */
.topbar-menu > summary.topbar-apps-button {
  flex: none;
  height: 36px;
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding: 0 var(--space-4);
  /* 2026-10-27「一整片」：描边撤了，一层很薄的底说它是一颗钮；开着的时候亮一档。 */
  border: 0;
  border-radius: var(--radius);
  background: var(--lift-soft);
  color: var(--fg-soft);
  font-size: var(--text-base);
  line-height: 1.4;
  white-space: nowrap;
  cursor: pointer;
  transition:
    background var(--motion-quick) var(--ease-out),
    border-color var(--motion-quick) var(--ease-out),
    color var(--motion-quick) var(--ease-out);
}

/* 手一过去、或者菜单正开着：填上底，描边让位。空心变实心就是「这扇门开了」。 */
.topbar-menu > summary.topbar-apps-button:hover,
.topbar-apps[open] > summary.topbar-apps-button {
  background: var(--lift);
  color: var(--fg);
}

.topbar-apps-face {
  flex: none;
  display: block;
  color: inherit;
}

/* details 默认是块级，在栏里（和被挪进托盘之后）都是一个 flex 项：不写 flex:none
   它会跟着伸缩，「应用」两个字就被压扁。 */
.topbar-apps {
  flex: none;
}

/* 地方那几颗是链接不是钮，把链接的下划线和颜色收回来。宽屏的侧栏只管这个地方里的东西：
   「去哪儿」那一组（.railbar-go）在宽屏上收起，只在手机的抽屉里还有——手机顶栏放不下一排标签。 */
a.topbar-tab,
a.topbar-tab:hover {
  text-decoration: none;
}

/* 跟 .topbar-tab-face 一个数（10-24 起 20）：开着的项目标签和前面「个人 / 项目」开关的记号一样大。 */
.topbar-tab > svg {
  flex: none;
  width: 20px;
  height: 20px;
  display: block;
}

.topbar-tab > .live-count {
  margin-left: var(--space-1);
}

/* --- 活的应用标签（业主 2026-09-27 晚，live_tab.js）-------------------------------
   对话页上这间会话有某个应用的东西在（一份文档在排、刚改好一页），那个应用的标签就在
   栏上，哪怕人从来没点开过它。样子就是一颗打开的应用标签（.topbar-tab.is-app），多一个
   点：呼吸＝正在做，金＝有新的可以看（看过清单就灭），红＝要看一眼。 */
.topbar-live {
  flex: none;
  display: flex;
  align-items: center;
  gap: var(--space-2);
}

.topbar-live[hidden],
.topbar-tab[hidden] {
  display: none;
}

.topbar-live-dot {
  flex: none;
  width: 8px;
  height: 8px;
  display: block;
  border-radius: 50%;
  background: var(--muted);
}

.topbar-live-dot[hidden] {
  display: none;
}

.topbar-live-dot.is-working {
  background: var(--fg-soft);
}

.topbar-live-dot.is-ready {
  background: var(--gold);
}

.topbar-live-dot.is-attention {
  background: var(--red-mark);
}

/* 点开的那张小清单：不是一页，是栏底下浮着的一块，跟管理菜单面板同一个样子。
   一行整行是链接（业主 2026-09-28：原来只有「打开」两个字能点，太小）：左边那一份的
   小图、两行标题、状态小标加一句话、右边箭头；每行不低于 72px，手机上拇指够得着。 */
.topbar-live-panel {
  position: fixed;
  z-index: 60;
  width: 372px;
  max-width: calc(100vw - 16px);
  max-height: 70vh;
  overflow-y: auto;
  padding: 6px;
  border: 1px solid var(--line);
  border-radius: 14px;
  background: var(--surface-2);
  box-shadow: var(--shadow-2);
}

.topbar-live-row {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  min-height: 72px;
  padding: 10px;
  border-radius: var(--radius-sm);
  color: var(--fg);
  text-decoration: none;
}

.topbar-live-row:hover,
.topbar-live-home:hover {
  background: var(--surface-3);
}

.topbar-live-row:focus-visible,
.topbar-live-home:focus-visible {
  outline: none;
  box-shadow: inset 0 0 0 1px var(--gold);
}

/* 左边那格：76×44 的框，图按高度放进去（16:9 占满，A4 竖着居中），没图是一格虚框。 */
.topbar-live-pic {
  flex: none;
  width: 76px;
  height: 44px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 4px;
  overflow: hidden;
  background: var(--surface-1);
}

.topbar-live-pic img {
  display: block;
  height: 44px;
  width: auto;
  max-width: 76px;
  border-radius: 3px;
}

.topbar-live-pic.is-blank {
  border: 1px dashed var(--line);
  background: transparent;
}

.topbar-live-body {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 4px;
}

/* 标题给两行；三行以上才截。老内核认 -webkit-line-clamp（Edge 17+），认不出就是不截，
   只是行高多一点。 */
.topbar-live-title {
  color: var(--fg);
  font-size: 14px;
  font-weight: var(--weight-medium);
  line-height: 1.4;
  overflow: hidden;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
}

.topbar-live-meta {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  min-width: 0;
  color: var(--muted);
  font-size: var(--text-xs);
}

/* 状态小标带一颗点，颜色跟标签上那颗一致：呼吸＝在改，金＝有新的，红＝要看。 */
.topbar-live-state {
  flex: none;
  display: inline-flex;
  align-items: center;
  gap: 5px;
}

.topbar-live-state::before {
  content: "";
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--muted);
}

.topbar-live-state.is-working {
  color: var(--fg-soft);
}

.topbar-live-state.is-working::before {
  background: var(--fg-soft);
}

.topbar-live-state.is-ready {
  color: var(--gold);
}

.topbar-live-state.is-ready::before {
  background: var(--gold);
}

.topbar-live-state.is-attention {
  color: var(--red);
}

.topbar-live-state.is-attention::before {
  background: var(--red-mark);
}

.topbar-live-words {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  color: var(--fg-soft);
}

.topbar-live-chevron {
  flex: none;
  width: 20px;
  height: 20px;
  color: var(--muted);
}

.topbar-live-row:hover .topbar-live-chevron,
.topbar-live-home:hover .topbar-live-chevron {
  color: var(--gold);
}

/* 最底下「文档首页」：也是整行，跟上面隔一条线。 */
.topbar-live-home {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  min-height: 44px;
  margin-top: 4px;
  padding: 0 12px;
  border-top: 1px solid var(--line-soft);
  border-radius: 0 0 var(--radius-sm) var(--radius-sm);
  color: var(--gold);
  font-size: var(--text-sm);
  text-decoration: none;
}

.topbar-live-home:hover {
  color: var(--gold-bright);
}

.topbar-live-home .topbar-tab-face {
  width: 18px;
  height: 18px;
}

.topbar-live-home-word {
  flex: 1;
}

.topbar-live-open {
  flex: none;
  color: var(--gold);
  font-size: var(--text-sm);
  text-decoration: none;
}

.topbar-live-open:hover {
  color: var(--gold-bright);
}

/* 有东西落定时顶栏底下滑出来的那一行。一行、可关、八秒自己收起，从不是弹窗。 */
.topbar-live-toast {
  position: fixed;
  z-index: 60;
  top: 56px;
  top: calc(var(--topbar-h) + 8px);
  left: 50%;
  max-width: 92vw;
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-2) var(--space-3) var(--space-2) var(--space-4);
  border: 1px solid var(--gold-line);
  border-radius: var(--radius-pill);
  background: var(--surface-3);
  box-shadow: var(--shadow-2);
  color: var(--fg);
  font-size: var(--text-sm);
  -webkit-transform: translateX(-50%);
  transform: translateX(-50%);
}

.topbar-live-toast.is-attention {
  border-color: var(--red);
}

.topbar-live-toast .topbar-live-pic {
  width: 52px;
  height: 30px;
}

.topbar-live-toast .topbar-live-pic img {
  height: 30px;
  max-width: 52px;
}

.topbar-live-toast-words {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.topbar-live-toast-close {
  flex: none;
  width: 24px;
  height: 24px;
  padding: 0;
  border: 0;
  border-radius: var(--radius-xs);
  background: transparent;
  color: var(--muted);
  font: inherit;
  cursor: pointer;
}

.topbar-live-toast-close:hover {
  background: var(--surface-4);
  color: var(--fg);
}

/* 动画全是装饰：关掉之后点照样在、颜色照样对、那一行照样出来。 */
@keyframes aimy-live-breathe {
  0%,
  100% {
    opacity: 1;
  }
  50% {
    opacity: 0.35;
  }
}

@keyframes aimy-live-pulse {
  0%,
  100% {
    -webkit-transform: scale(1);
    transform: scale(1);
  }
  40% {
    -webkit-transform: scale(1.06);
    transform: scale(1.06);
  }
}

@keyframes aimy-live-drop {
  from {
    opacity: 0;
    -webkit-transform: translate(-50%, -8px);
    transform: translate(-50%, -8px);
  }
}

@media (prefers-reduced-motion: no-preference) {
  .topbar-live-dot.is-working {
    animation: aimy-live-breathe 1.8s ease-in-out infinite;
  }

  .topbar-live-tab.is-pulse {
    animation: aimy-live-pulse 0.7s ease-out 2;
  }

  .topbar-live-toast {
    animation: aimy-live-drop 0.24s ease-out;
  }
}

/* 手机：托盘那一排收着，这一颗留着——文档从这里找得到。窄一点，排到「应用」旁边，跟「任务」
   「应用」同高（32）：标签自己的 36 会把 48 高的栏顶成 52，文档一出现整条栏就往下跳 4 像素。 */
@media (max-width: 640px) {
  .topbar-live {
    order: 2;
  }

  .topbar-live .topbar-tab {
    min-width: 0;
    padding: 0 var(--space-2);
  }

  body:not(.is-desktop) .topbar-live .topbar-tab {
    height: 32px;
  }
}

/* 写成 `.railbar .railbar-go`：`.railbar-go` 自己的 display 写在文件后面，同权重的话后写的赢。 */
@media (min-width: 641px) {
  .railbar .railbar-go {
    display: none;
  }
}

/* 手机顶栏上的「任务」（业主 2026-09-22 晚）。宽屏上它不出现——那儿每一页的侧栏上都有
   「任务」那一行；样子写在文件末尾 640 以下那一段，跟「应用」那一格同一路。 */
.topbar-tasks {
  display: none;
}

.topbar-tasks[hidden] {
  display: none;
}

/* 桌面壳给「画不出栏的页面」（PDF、图片的原始字节）戴的那一条就是这一页
   （templates/shell_strip.html，业主 2026-09-19：「顶部栏保持应该有的标签」）。
   它只有一条栏，没有正文——所以这里只管把页面本身收干净，栏的样子照旧走上面
   那几条，一个字都不抄。 */
.shell-strip {
  margin: 0;
  overflow: hidden;
  background: var(--surface-2);
}

/* --- 桌面端：这条栏就是标题栏 -------------------------------------------------
   `is-desktop` 由 shell.js 认出 window.aimyDesktop 之后挂到 body 上，所以这一整段
   在浏览器里一条都不生效。整条栏可以拖窗口，栏里每个能点的东西自己退出拖动区
   ——不退出的话，点它变成拖窗口。退出的只能是**能点的那一颗**，不能是装着它们的那一组：
   地方那一组（.topbar-places）横着撑满整条栏，10-13 把整组写成 no-drag，栏上就几乎没有
   地方能拖了（业主 2026-10-14：「我用 mac 端客户端，顶栏拖拽窗口会失效」）。 */
.is-desktop .topbar {
  -webkit-app-region: drag;
}

.is-desktop .topbar-avatar-link,
.is-desktop .topbar-tab,
.is-desktop .topbar-places-new,
.is-desktop .topbar-places-more,
.is-desktop .topbar-places-menu,
.is-desktop .topbar-nav-link,
.is-desktop .topbar-menu,
.is-desktop .topbar-tabs,
.is-desktop .topbar-live,
.is-desktop .topbar-live-panel,
.is-desktop .topbar-live-toast,
.is-desktop .topbar-tasks,
.is-desktop .topbar-alarm {
  -webkit-app-region: no-drag;
}

/* 整页滚动后逼内核重算拖动区的那一枚（shell.js，2026-10-25）：不占地方、画不出东西，
   滚一下宽度在 0 和 1px 之间换一次——那一下重排才让拖动区跟上钉在顶上的栏。 */
.shell-drag-sync {
  position: absolute;
  top: 0;
  left: 0;
  width: 0;
  height: 0;
  pointer-events: none;
}

.shell-drag-sync.is-flip {
  width: 1px;
}

/* macOS 的红绿灯画在栏的左端：窗口那边从 x=16 起画三颗 12px、间距 8px 的灯
   （window.js 的 TRAFFIC_LIGHTS），最后一颗到 68 结束。留白必须是「68 再加一个
   栏自己的边距」——第一版直接写了 68，等于让头像紧贴着最后一颗灯的边缘长出来，
   业主更新后第一眼就看见它俩糊在一起（2026-09-18）。68 是灯占掉的，不是留白。

   这个数叫 `--bar-left`（见 :root）。**全屏时红绿灯自己藏起来**，那一刻这一段只剩栏
   自己的边距——壳发一句「我全屏了」，shell.js 给 body 挂上 is-desktop-fullscreen，
   :root 底下那一条把它改成 8。 */
.is-desktop-mac .topbar {
  padding-left: 92px;
  padding-left: var(--bar-left);
}

/* Windows 的最小化／最大化／关闭画在栏的右端（titleBarOverlay）。先留一个够用的
   死数，认得 env() 的内核再按它实报的宽度收——旧写法自己站得住。 */
.is-desktop-win .topbar {
  padding-left: 6px;
  padding-left: var(--bar-left);
  padding-right: 148px;
  padding-right: calc(100% - env(titlebar-area-width, 100%) + var(--space-6));
}

/* 应用页那句「← 回 Aimy」在桌面端是重复的：托盘里就有 Aimy 那一颗。 */
.is-desktop .topbar-nav-exit {
  display: none;
}

/* --- 桌面端的下载（desktop-downloads.js）-------------------------------------
   顶栏右端一颗钮，点开垂下一张下载单——浏览器那一套（业主 2026-09-23：「需要一个
   形态完整、体验好的、专业的下载」）。只在客户端里出现，浏览器里这些类一个都
   不会被画出来。钮跟「应用」那一格同高同圆角同一档底色，因为它们排在同一条栏上。 */
.aimy-dl-button {
  position: relative;
  flex: none;
  width: 36px;
  height: 36px;
  margin-left: auto;
  padding: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  border: 1px solid transparent;
  border-radius: var(--radius-sm);
  background: transparent;
  color: var(--fg-soft);
  cursor: pointer;
  -webkit-app-region: no-drag;
  transition:
    background var(--motion-quick) var(--ease-out),
    color var(--motion-quick) var(--ease-out);
}
.aimy-dl-button[hidden] {
  display: none;
}

/* 「有新版本」（desktop-update.js，客户端 0.9.0 起）：排在「下载」左边。它在的时候
   由它把右边那一截推到栏尾，「下载」紧跟着它。下载中那一格底下走一层进度，下好了
   整颗变金——那是唯一一颗点了会退出程序的钮，看得出来它不一样。 */
.aimy-update-button {
  position: relative;
  flex: none;
  height: 32px;
  margin-left: auto;
  padding: 0 14px;
  display: flex;
  align-items: center;
  overflow: hidden;
  border: 1px solid var(--control-line);
  border-radius: var(--radius-pill);
  background: transparent;
  color: var(--fg-soft);
  font: inherit;
  font-size: var(--text-sm);
  white-space: nowrap;
  cursor: pointer;
  -webkit-app-region: no-drag;
}
.aimy-update-button[hidden] {
  display: none;
}
/* 只在「有新版本」真的画出来时才把「下载」挪到它旁边。`+` 只认 DOM 相邻，不认
   显不显示：0.9.0 起那颗钮一直在 DOM 里、大多数时候 hidden，光写 `+` 就把
   「下载」自己的 margin-left:auto 盖掉，钮于是贴着标签站在栏中间而不是栏尾
   （业主 2026-09-24 截图）。 */
.aimy-update-button:not([hidden]) + .aimy-dl-button {
  margin-left: 8px;
}
.aimy-update-button:hover {
  background: var(--surface-3);
  color: var(--fg);
}
/* 桌面端的「刷新」（desktop-reload.js，业主 2026-10-17）：有竖栏的页上它是点头像弹开的那张菜单里的
   最后一行（业主 2026-10-24，下面 .aimy-menu-reload）；这几条只管没有竖栏的页，那里它还是栏尾最右
   一颗，跟「下载」同一个尺寸、同一种安静。前面那两颗露出来时它跟着它们站，不再自己去抢栏尾——两个 margin-left:auto 会把
   空白对半分，钮就站到栏中间去了（09-24 那一次的同一个道理）。 */
.aimy-reload-button {
  flex: none;
  width: 36px;
  height: 36px;
  margin-left: auto;
  padding: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  border: 1px solid transparent;
  border-radius: var(--radius-sm);
  background: transparent;
  color: var(--fg-soft);
  cursor: pointer;
  -webkit-app-region: no-drag;
}
.aimy-reload-button[hidden] {
  display: none;
}
.aimy-reload-button:hover {
  background: var(--surface-3);
  color: var(--fg);
}
.aimy-update-button:not([hidden]) ~ .aimy-reload-button,
.aimy-dl-button:not([hidden]) ~ .aimy-reload-button {
  margin-left: 4px;
}
/* 菜单里那一行是一颗按钮，长得跟上面那几行链接一样：去掉按钮自己的框、底和字体，字靠左。 */
.aimy-menu-reload {
  width: 100%;
  border: 0;
  font-family: inherit;
  text-align: left;
  cursor: pointer;
}
.aimy-update-button.is-busy {
  cursor: default;
}
.aimy-update-button.is-busy:hover {
  background: transparent;
  color: var(--fg-soft);
}
.aimy-update-button.is-ready {
  border-color: transparent;
  background: var(--lift);
  color: var(--gold);
}
.aimy-update-button.is-ready:hover {
  color: var(--gold-bright);
}
.aimy-update-fill {
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  width: 0;
  background: var(--gold-wash);
  transition: width var(--motion-base) var(--ease-out);
}
.aimy-update-word {
  position: relative;
}
.aimy-dl-button:hover,
.aimy-dl-button.is-open {
  background: var(--surface-3);
  color: var(--fg);
}
/* 刚下完一份、单子还没打开过：箭头亮成金色，打开就灭。 */
.aimy-dl-button.is-fresh {
  color: var(--gold);
}
.aimy-dl-face {
  position: relative;
  display: flex;
}
/* 外圈进度：只在有东西在下的时候出现。 */
.aimy-dl-ring {
  position: absolute;
  top: 0;
  left: 0;
  width: 36px;
  height: 36px;
  display: none;
  fill: none;
  stroke-width: 2.4;
}
.aimy-dl-button.is-busy .aimy-dl-ring {
  display: block;
}
.aimy-dl-button.is-busy {
  color: var(--gold);
}
.aimy-dl-ring-track {
  stroke: var(--chart-track);
}
.aimy-dl-ring-fill {
  stroke: var(--gold);
  stroke-linecap: round;
  transition: stroke-dashoffset var(--motion-base) var(--ease-out);
}
/* 不知道总大小的时候，那一圈转着走一段，不装作有个百分比。 */
.aimy-dl-button.is-unknown .aimy-dl-ring-fill {
  stroke-dashoffset: 70;
  transform-origin: 18px 18px;
  animation: aimy-dl-spin 1.1s linear infinite;
}
@keyframes aimy-dl-spin {
  to {
    transform: rotate(270deg);
  }
}

.aimy-dl-panel {
  position: fixed;
  top: 56px;
  right: 16px;
  z-index: 30;
  width: 420px;
  max-width: 92%;
  max-height: 520px;
  max-height: calc(100vh - 80px);
  display: flex;
  flex-direction: column;
  box-sizing: border-box;
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  background: var(--surface-2);
  box-shadow: var(--shadow-3);
  overflow: hidden;
}
.aimy-dl-panel[hidden] {
  display: none;
}
.aimy-dl-head {
  flex: none;
  display: flex;
  align-items: center;
  padding: 12px 10px 10px 16px;
  border-bottom: 1px solid var(--line-soft);
}
.aimy-dl-title {
  flex: 1;
  margin: 0;
  color: var(--fg);
  font-size: var(--text-base);
  font-weight: var(--weight-semi);
}
.aimy-dl-link {
  margin-left: 2px;
  padding: 4px 8px;
  border: 0;
  border-radius: var(--radius-sm);
  background: transparent;
  color: var(--muted);
  font: inherit;
  font-size: var(--text-xs);
  cursor: pointer;
}
.aimy-dl-link:hover {
  background: var(--surface-3);
  color: var(--fg);
}
.aimy-dl-link:disabled {
  color: var(--faint);
  background: transparent;
  cursor: default;
}
.aimy-dl-list {
  flex: 1;
  margin: 0;
  padding: 6px;
  overflow-y: auto;
  list-style: none;
}
.aimy-dl-empty {
  margin: 0;
  padding: 28px 16px 32px;
  color: var(--muted);
  font-size: var(--text-sm);
  text-align: center;
}
.aimy-dl-empty[hidden] {
  display: none;
}

.aimy-dl-row {
  display: flex;
  align-items: center;
  padding: 10px;
  border-radius: var(--radius);
}
.aimy-dl-row:hover {
  background: var(--surface-3);
}
.aimy-dl-row.is-openable {
  cursor: pointer;
}
.aimy-dl-icon {
  flex: none;
  width: 32px;
  height: 32px;
  margin-right: 12px;
  display: flex;
  align-items: center;
  justify-content: center;
}
.aimy-dl-icon-img {
  display: block;
  width: 32px;
  height: 32px;
}
/* 没有系统图标时的那块牌子：扩展名。 */
.aimy-dl-badge {
  box-sizing: border-box;
  width: 28px;
  height: 32px;
  padding-top: 13px;
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-xs);
  background: var(--surface-1);
  color: var(--fg-soft);
  font-size: 8px;
  font-weight: var(--weight-semi);
  letter-spacing: 0.02em;
  line-height: 1;
  text-align: center;
}
.aimy-dl-body {
  flex: 1;
  min-width: 0;
}
.aimy-dl-name {
  overflow: hidden;
  color: var(--fg);
  font-size: var(--text-sm);
  line-height: 1.4;
  white-space: nowrap;
  text-overflow: ellipsis;
}
/* 这一句不截：还剩多久是人最想读的那几个字，宁可折一行（2026-09-24 实测，
   380 宽时「还剩 4 分钟」被截成「还剩 4 …」）。 */
.aimy-dl-status {
  margin-top: 2px;
  color: var(--muted);
  font-size: var(--text-xs);
  line-height: 1.4;
  font-variant-numeric: tabular-nums;
}
.aimy-dl-row.is-interrupted .aimy-dl-status,
.aimy-dl-row.is-missing .aimy-dl-status {
  color: var(--red);
}
.aimy-dl-row.is-cancelled .aimy-dl-name,
.aimy-dl-row.is-missing .aimy-dl-name {
  color: var(--muted);
  text-decoration: line-through;
}
.aimy-dl-track {
  height: 3px;
  margin-top: 7px;
  overflow: hidden;
  border-radius: var(--radius-pill);
  background: var(--chart-track);
}
.aimy-dl-track[hidden] {
  display: none;
}
.aimy-dl-fill {
  width: 0;
  height: 100%;
  border-radius: var(--radius-pill);
  background: var(--gold);
  transition: width var(--motion-base) var(--ease-out);
}
.aimy-dl-row.is-paused .aimy-dl-fill,
.aimy-dl-row.is-interrupted .aimy-dl-fill {
  background: var(--muted);
}
/* 不知道总大小：一小段来回走，不装作有个百分比。 */
.aimy-dl-track.is-unknown .aimy-dl-fill {
  width: 30%;
  animation: aimy-dl-slide 1.2s ease-in-out infinite alternate;
}
@keyframes aimy-dl-slide {
  from {
    margin-left: 0;
  }
  to {
    margin-left: 70%;
  }
}
.aimy-dl-acts {
  flex: none;
  display: flex;
  margin-left: 8px;
}
.aimy-dl-act {
  width: 28px;
  height: 28px;
  margin-left: 2px;
  padding: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  border: 0;
  border-radius: var(--radius-sm);
  background: transparent;
  color: var(--muted);
  cursor: pointer;
}
.aimy-dl-act:hover {
  background: var(--surface-4);
  color: var(--fg);
}
/* 完成了的那几行：钮平时收着，手一过去才出来——一张全是钮的单子读不出名字。
   在下的、停着的、断了的，钮一直在：那几行正等人拿主意。 */
.aimy-dl-row.is-completed .aimy-dl-act,
.aimy-dl-row.is-cancelled .aimy-dl-act {
  opacity: 0;
}
.aimy-dl-row.is-completed:hover .aimy-dl-act,
.aimy-dl-row.is-cancelled:hover .aimy-dl-act,
.aimy-dl-row .aimy-dl-act:focus {
  opacity: 1;
}

@media (prefers-reduced-motion: reduce) {
  .aimy-dl-button.is-unknown .aimy-dl-ring-fill,
  .aimy-dl-track.is-unknown .aimy-dl-fill {
    animation: none;
  }
}

/* --- 左侧栏 -----------------------------------------------------------------
   业主 2026-09-19：「把 aimy 头像、应用、任务，都放到左侧栏。取消顶部栏。」
   一份骨架，Aimy 的每一页共用（模板 aimy_base.html）：上面是头像和几项导航，
   中间是这一页自己的东西（{% block rail %}），底下是「你是谁」和管理菜单。

   只有 641 以上才有，跟对话页清单变抽屉的断点是同一个数（对话页那份样式表）——不另发明
   一个断点。640 以下这一条整条不出现：导航仍在顶栏，各页自己的抽屉仍归各页自己。
   应用页也没有：它保持 2026-08-14 定的最简头部（模板里连 .railbar 都不渲染）。

   position: fixed 而不是 sticky。栏要从窗口顶贴到窗口底；sticky 在老内核上掉了
   就是一条跟着长页面滚走的栏——整套导航在第二屏就不见了。占位交给 .shell-body
   的 padding-left，两个写法全内核都认。

   **z-index 必须写**（业主 2026-09-19 报「后台管理菜单被裁切」，探针定的案）。
   建这条栏时这里写着「不设 z-index，免得它自己开了层叠上下文把菜单面板关在栏里」
   ——那句话把规矩记反了：`position: fixed` **本来就无条件开一个层叠上下文**，
   z-index 写不写都一样。于是面板那个 z-index:20 只在栏内部排序，而整条栏以
   「z-index: auto 的定位元素」参与根上下文，按 DOM 顺序排在 `<main>` 前面——
   `.chat-shell`（position: relative）于是盖在面板上，菜单从栏的右边缘（240）
   起整块被遮住。实测：面板 x=196 宽 144，在 x=336 那一点 `elementsFromPoint`
   回来的第一个是 `.chat-shell`，第二个才是面板。
   取 50：压过正文和手机抽屉（30），让给灯箱（60）和弹窗（80）。 */
.shell-body {
  display: block;
}

.railbar {
  display: none;
  position: fixed;
  top: 0;
  bottom: 0;
  left: 0;
  z-index: 50;
  width: var(--rail-w);
  flex-direction: column;
  /* 顶上不留空：栏里第一样就是「新会话」那一行，它自己的块带 8 的内衬（业主 2026-10-24：「位置有点
     靠下，顶部有一点空间浪费了」——原来这里 16，加上块的 8 和 2，那一行离栏顶 26）。 */
  padding: 0 0 var(--space-3);
  /* 跟会话清单同一个底（业主 2026-09-26：「aimy 那里的背景色不用搞特殊，保持一致」）；2026-10-27 起跟
     顶栏、正文也是同一块底，跟正文之间只留一道最轻的线。 */
  background: var(--bg);
  border-right: 1px solid var(--line-soft);
}

/* 自己设了 display 的类自带这一条（2026-09-04「副本」签实录）。 */
.railbar[hidden] {
  display: none;
}

/* 收起左栏的把手只在宽屏上有（641 以上那一段里的 .rail-edge）：手机上清单是抽屉，栏退成一个零宽的
   壳（chat.css），把手挂在它上面就会浮在对话左边。 */
.rail-edge {
  display: none;
}

/* 栏头只在没有会话清单的页上有：一行「Aimy」，靠左。 */
.railbar-head {
  flex: 0 0 auto;
  padding: 0 var(--space-3);
  display: flex;
  align-items: center;
  gap: var(--space-2);
}

.railbar-head > .railbar-brand {
  flex: 1 1 auto;
  min-width: 0;
}

/* 头像 + 名字，点开是「Aimy 是什么」——跟顶栏上那一枚同一扇门。 */
.railbar-brand {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-1) var(--space-2);
  border-radius: var(--radius-sm);
  color: var(--fg);
  font-size: var(--text-md);
  font-weight: var(--weight-medium);
}

.railbar-brand:hover {
  opacity: 0.85;
}

.railbar-brand-name {
  min-width: 0;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}

/* 「去哪儿」那一组：技能库、任务（业主 2026-09-22 晚：任务从管理菜单「拿出来（并且加上
   任务状态的显示，比如有几个在跑）」）。每一张带侧栏的页都有它——用量、会话这些页左边
   原来是空的，去任务页得先回对话再点。模板在 _rail_go.html：没有会话清单的页画在栏头
   底下，带清单的页画在清单顶上（手机上清单是对话页的抽屉，这两行得跟着进去）。

   行的样子跟清单里「新会话」「搜索」那两行（对话页样式表的 .chat-side-action）是同一
   套数：同高、同内衬、同字号、同一档 hover——它们在对话页上排成一摞，得一样大。这里
   另抄一份，因为任务页、用量页不带那份样式表。容器的内衬和行距也照 .chat-side-actions
   写，两处画出来是同一个位置；底下多 2px，是跟下面那一摞之间照旧隔 2px。 */
.railbar-go {
  flex: 0 0 auto;
  display: flex;
  flex-direction: column;
  padding: 0 var(--space-2) 2px;
}

.railbar-go[hidden] {
  display: none;
}

/* 行距用外边距，不用 flex 的 gap——老内核不认后者（AGENTS.md）。 */
.railbar-go-link + .railbar-go-link {
  margin-top: 2px;
}

/* 字跟会话那几行一个颜色（业主 2026-10-13 第二轮：左栏的字不再分强弱）。 */
.railbar-go-link {
  display: flex;
  align-items: center;
  padding: var(--space-2) var(--space-3);
  border-radius: var(--radius-sm);
  color: var(--fg-soft);
  font-size: var(--text-base);
  text-decoration: none;
}

.railbar-go-link > svg {
  flex: none;
  display: block;
  margin-right: 10px;
}

.railbar-go-link:hover {
  background: var(--surface-2);
  color: var(--fg);
  text-decoration: none;
}

/* 站在这一页上：跟会话清单里「当前这一间」同一种说法（对话页样式表的
   .chat-session.is-current）——铺一层看得出来的亮底（10-13 第三轮；10-17 起是纯灰），字跟别的行一样。
   写在 hover 后面，手一过去也不退成灰底。 */
.railbar-go-link[aria-current="page"] {
  background: var(--lift);
}

.railbar-go-link > .live-count {
  margin-left: auto;
}

/* 「应用」那一行（业主 2026-09-26 从顶栏搬进来，点开往右弹）。它是一张菜单，所以是
   <details>：summary 长得跟上面两行一样。权重写到 `.railbar-apps > summary.railbar-go-link`，
   压过给所有菜单写的 `.topbar-menu > summary`（inline-flex、左右 10 的内衬）。开着的时候
   跟手停在上面同一档底——这扇门此刻开着。 */
.railbar-apps {
  margin-top: 2px;
}

.railbar-apps > summary.railbar-go-link {
  display: flex;
  padding: var(--space-2) var(--space-3);
  cursor: pointer;
}

.railbar-apps[open] > summary.railbar-go-link {
  background: var(--surface-2);
  color: var(--fg);
}

/* 「几件在跑」：转圈、绿字、带数（10-31 起绿，原来金）。跟会话清单每一行的派单记号（对话页样式表的
   .chat-session-tasks）是同一个样子，数的范围不同——那个是自己的一间会话，这个是
   任务板。栏上那一行和手机顶栏那一格用的是它。 */
.live-count {
  display: inline-flex;
  flex: 0 0 auto;
  align-items: center;
  padding: 0 6px;
  border-radius: var(--radius-pill);
  background: var(--lift);
  color: var(--green-mark);
  font-size: var(--text-2xs);
  font-weight: var(--weight-normal);
  line-height: 18px;
  font-variant-numeric: tabular-nums;
}

.live-count[hidden] {
  display: none;
}

/* 一层 span 包着那一圈 svg（_rail_go.html）：转的是这一层。 */
.live-count-spin {
  flex: none;
  display: block;
  width: 11px;
  height: 11px;
  margin-right: 3px;
}

.live-count-spin > svg {
  display: block;
}

/* 中间这一格是这一页自己的（对话页放它的会话清单）。没人往里放东西时它就是
   一块会伸缩的空白，把底下那一格顶到栏底。 */
.railbar-page {
  flex: 1 1 auto;
  min-height: 0;
  display: flex;
  flex-direction: column;
}

/* --- 最左边那一条竖栏（业主 2026-10-14：「按方案 1 执行」——像企业微信左边那一列）-----------
   任务、应用排在上面，急停、管理和「你」压在底下（「你」和管理原来是左侧栏底下那一行；桌面端管理
   上面多一颗刷新，10-20 从顶栏尾搬来，desktop-reload.js）。
   一格一个入口，52 宽：任务、应用、管理只有记号（10-14 晚管理，10-20 任务和应用：「文字移除，
   只保留图标」），打开着的应用是记号在上、名字在下；站在那一页上铺跟选中的标签、开着的会话同一种看得
   出来的亮底（10-13 第三轮）。底跟顶栏同一个颜色（surface-2，业主 2026-10-14：「最左侧竖栏、顶栏，
   应该一个背景色」），比左侧栏亮一档。位置在文件末尾 641 那一段（宽屏才有）；手机上整条不出现。
   字不让选：拖窗口、来回点的时候，「技能」「任务」那几个字不该被选成一块一块的。
   格与格之间的空用外边距：老内核不认 flex 的 gap（AGENTS.md）。 */
.shell-dock {
  display: none;
  -webkit-user-select: none;
  user-select: none;
}

.shell-dock > * + * {
  margin-top: var(--space-1);
}

.dock-item {
  position: relative;
  box-sizing: border-box;
  width: 48px;
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: var(--space-2) 0 6px;
  border: 0;
  border-radius: var(--radius);
  background: transparent;
  color: var(--muted);
  font: inherit;
  font-size: var(--text-2xs);
  line-height: 16px;
  text-align: center;
  text-decoration: none;
  cursor: pointer;
}

.dock-item:hover {
  background: var(--lift-soft);
  color: var(--fg);
  text-decoration: none;
}

/* 站在那一页上（技能、任务、管理里的哪一页、打开着的哪个应用），或者那张菜单开着：跟顶栏选中的
   标签同一种底——surface-4 上叠一层 --gold-wash，叠出来是实色；老内核不认叠层就是前一行的
   surface-4。 */
.dock-item.is-active,
.shell-dock-menu[open] > summary.dock-item {
  background: var(--lift);
  color: var(--fg);
}

/* 打开着的应用（2026-10-14：「打开的具体应用，也是在左侧栏往下显示更合理」）：「应用」底下一道
   细线，一个应用一格，跟上面那几格同一个样子。对话页上「活」的那几格（.dock-live）跟在后面，
   跟它们之间不再画第二道线。 */
.shell-dock .dock-tabs,
.shell-dock .dock-live {
  width: 48px;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0;
  margin-top: var(--space-2);
  padding-top: var(--space-3);
  /* 上面那组和打开着的应用之间：中间一小截 20 宽的淡线，不再是通栏一道（2026-10-28）。 */
  background: linear-gradient(var(--line), var(--line)) center top / 20px 1px no-repeat;
}

.shell-dock .dock-tabs[hidden],
.shell-dock .dock-live[hidden] {
  display: none;
}

.shell-dock .dock-tabs:not([hidden]) + .dock-live {
  margin-top: 0;
  padding-top: 0;
  background: none;
}

.dock-tabs > * + *,
.dock-live > * + * {
  margin-top: var(--space-1);
}

.dock-tab[hidden] {
  display: none;
}

/* 名字放不下就省略，全名在悬停里。 */
.dock-tab > .dock-label {
  max-width: 44px;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* 应用自己的记号（应用菜单里那一枚）；没给记号的是名字头一个字。 */
.dock-tab-face {
  width: var(--dock-icon);
  height: var(--dock-icon);
  margin-bottom: 4px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: var(--text-base);
  line-height: 1;
}

.dock-tab-face > svg {
  display: block;
  width: var(--dock-icon);
  height: var(--dock-icon);
}

/* 关掉那一颗：手停上去（或者键盘落在这一格上）才露出来，在这一格的右上角。 */
.dock-tab-close {
  position: absolute;
  top: 2px;
  right: 2px;
  width: 16px;
  height: 16px;
  display: none;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  background: var(--surface-4);
  color: var(--fg-soft);
}

.dock-tab-close > svg {
  width: 9px;
  height: 9px;
  display: block;
}

.dock-tab:hover > .dock-tab-close,
.dock-tab:focus > .dock-tab-close {
  display: flex;
}

.dock-tab-close:hover {
  background: var(--surface-1);
  color: var(--fg);
}

/* 「活」的那一格上的点：在记号的右上角。 */
.dock-tab > .topbar-live-dot {
  position: absolute;
  top: 6px;
  left: 50%;
  margin-left: 8px;
}

.dock-item > svg {
  display: block;
  width: var(--dock-icon);
  height: var(--dock-icon);
  margin-bottom: 4px;
}

.dock-label {
  display: block;
  white-space: nowrap;
}

/* 菜单那两格（应用、管理）是 <details>：`.topbar-menu > summary` 给所有菜单写的是横排、左右 10
   的内衬，这里压回一格的样子。 */
.shell-dock-menu > summary.dock-item {
  display: flex;
  padding: var(--space-2) 0 6px;
}

/* 只有记号、不写字的格子：管理（业主 2026-10-14 晚：「这里保留图标就行，不用写管理两个字」）、
   任务和应用（10-20：「文字移除，只保留图标。这样更加清爽」）。上下
   一样的内衬，记号在格子正中，比带字的格子矮一截（40）。应用、管理那两格是菜单的 summary，上一条
   的权重比 .dock-item 高，所以两种写法都列上。 */
.dock-item.dock-icon,
.shell-dock-menu > summary.dock-item.dock-icon {
  /* 40 见方、记号在正中（2026-10-28）：原来是 52 宽、上下各 8 的一条，记号 24 时格子是扁的。 */
  width: 40px;
  height: 40px;
  padding: 0;
  justify-content: center;
}

.dock-item.dock-icon > svg {
  margin-bottom: 0;
}

/* 竖栏的记号粗一档（2026-10-31，同上）。表里是 Phosphor 的 regular 一档，线宽 16（256 格）；这里沿着图形的
   边描一圈 8，里外各长 4，正好是它 bold 一档的 24——跟 bold 的图形并排画过，看不出差别，就不在表里再存
   一套。描边从 <svg> 传进 <use> 里的图形；自己写了 stroke 的那几枚（看板、小幽灵）照旧是细的，这一条
   上没有它们。弹出来的应用菜单里的方块不在这两种格子里，不跟着变。
   只描这张表自己的记号（.aimy-icon）：应用自带的记号不在 256 格上（画廊的是 24 格、自带线宽），同一个 8
   在那儿把整枚涂成一块（业主当天：「应用里的图标都炸了」）。 */
.dock-item > svg.aimy-icon,
.dock-tab-face > svg.aimy-icon {
  stroke: currentColor;
  stroke-width: 8;
  stroke-linejoin: round;
}

/* 任务图标角上那个数：在跑几件，绿底深字的一小颗（10-31 起绿：健康运转；转圈那一枚在这儿太挤，收起）。
   没在跑的时候整颗收着（.live-count[hidden]）。 */
.dock-item > .live-count {
  position: absolute;
  top: 2px;
  left: 50%;
  min-width: 16px;
  height: 16px;
  margin-left: 6px;
  padding: 0 4px;
  box-sizing: border-box;
  justify-content: center;
  background: var(--green-mark);
  color: var(--surface-0);
  font-size: 10px;
  font-weight: var(--weight-semi);
  line-height: 16px;
}

.dock-item > .live-count .live-count-spin {
  display: none;
}

/* 「会话」「主页」角上的数（2026-10-31，从顶栏那个开关搬来）：跟任务的数同一个角。红色数字是要你动手的
   件数——会话里等你点头的卡片、等你的事情；只有新消息时是一颗灰点，不写数。 */
.dock-item > .topbar-tab-badge {
  position: absolute;
  top: 2px;
  left: 50%;
  margin-left: 6px;
  box-sizing: border-box;
}

.dock-item > .topbar-tab-badge.is-news {
  position: absolute;
  top: 6px;
  left: 50%;
  margin-left: 9px;
}

/* 地方（会话、主页）和工具（任务、技能、应用）之间：中间一小截 20 宽的淡线，跟打开着的应用上面那一道
   同一种。 */
.dock-rule {
  display: block;
  width: 20px;
  height: 1px;
  margin: var(--space-2) 0 var(--space-1);
  background: var(--line);
}

.shell-dock > .dock-rule + * {
  margin-top: var(--space-2);
}

/* 上面三格和底下那几格之间的空：把急停、管理、「你」压到栏底。 */
.dock-gap {
  flex: 1 1 auto;
}

/* 急停中：跟顶栏那枚铃同一个类、同一份开关（急停页一次拨全部），在这儿站成一格；没按的时候
   收着。`.topbar-alarm` 写了横排的一颗胶囊，这里压回一格；自带 [hidden] 那一条（理由同铃）。 */
.shell-dock .dock-alarm {
  display: flex;
  gap: 0;
  padding: var(--space-2) 0 6px;
  border: 0;
  border-radius: var(--radius-sm);
  font-size: var(--text-2xs);
  font-weight: var(--weight-semi);
  line-height: 16px;
}

.shell-dock .dock-alarm[hidden] {
  display: none;
}

.shell-dock .dock-alarm > .topbar-alarm-dot {
  margin: 6px 0 8px;
}

/* 「你」：名字的头一个字，圆的；全名在悬停里。 */
.dock-me {
  width: 30px;
  height: 30px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  background: var(--surface-4);
  color: var(--fg);
  font-size: var(--text-sm);
}

.shell-dock > .dock-me {
  margin-top: var(--space-2);
}

/* 一格一个应用，小方块（业主 2026-09-19：「每一个应用做成一个小方块」）。
   三个一行；不用 grid 也不用 flex 的 gap——两样在老内核上都靠不住（AGENTS.md），
   间距改成每颗自己带 4 的外边距、容器倒扣 4，这个写法哪儿都认。 */
.apps-panel {
  min-width: 0;
  padding: var(--space-3);
}

.apps-panel-grid {
  width: 252px;
  margin: -4px;
  display: flex;
  flex-wrap: wrap;
}

.apps-tile {
  flex: none;
  width: 76px;
  margin: 4px;
  padding: 10px 4px;
  display: flex;
  flex-direction: column;
  align-items: center;
  border-radius: 10px;
  color: var(--fg-soft);
  text-align: center;
  text-decoration: none;
  transition: background var(--motion-quick) var(--ease-out);
}

.apps-tile:hover {
  background: var(--surface-4);
  color: var(--fg);
  text-decoration: none;
}

.apps-tile.is-current {
  background: var(--surface-4);
  color: var(--gold);
}

/* 方块本身。里面是应用自己画的记号（`WebSurface.icon`，业主 2026-09-26：图标是
   画的不是打的）；没给记号的应用仍然用名字头一个字。 */
.apps-tile-face {
  flex: none;
  width: 40px;
  height: 40px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 12px;
  background: var(--surface-1);
  color: var(--gold);
  font-size: 19px;
  font-weight: var(--weight-semi);
  line-height: 1;
}

.apps-tile-face svg {
  display: block;
}

.apps-tile:hover .apps-tile-face,
.apps-tile.is-current .apps-tile-face {
  background: var(--surface-0);
}

/* 名字最多两行，高度写死——长短不一的名字不该把一行方块推得高低不齐。 */
.apps-tile-name {
  margin-top: 6px;
  height: 2.8em;
  overflow: hidden;
  font-size: var(--text-xs);
  line-height: 1.4;
}

/* 页头读数条（业主 2026-08-14：会话、任务、能力的顶部信息都按能力页那条来）。
   它是仪表不是内容，所以不穿卡片的外框——那会让它读成"又一栏内容"；只留一条
   细线把它和下面的主体分开。不写 display，各页自己决定里面怎么排。 */
.page-gauge {
  padding: 0 0 var(--space-5);
  margin-bottom: var(--space-6);
  border: 0;
  border-bottom: 1px solid var(--line-soft);
  border-radius: 0;
  background: none;
}

/* --- 「诊断」开关（_diagnostics.html，2026-09-15 设计评审第二批）：工程读数折进这里，
       只给管理员。折着是一行小灰字，跟页面的人话不抢；展开后读数自己排。 --- */
.diag-panel {
  margin: var(--space-2) 0;
  color: var(--muted);
  font-size: var(--text-xs);
}

.diag-summary {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 2px var(--space-2) 2px 6px;
  border-radius: var(--radius-pill);
  color: var(--faint);
  cursor: pointer;
  list-style: none;
  user-select: none;
}

.diag-summary::-webkit-details-marker {
  display: none;
}

.diag-summary:hover,
.diag-panel[open] > .diag-summary {
  background: var(--surface-2);
  color: var(--muted);
}

.diag-icon {
  display: block;
  flex: 0 0 auto;
}

.diag-body {
  margin-top: var(--space-2);
  padding: var(--space-3) var(--space-4);
  border-radius: var(--radius-sm);
  background: var(--surface-1);
}

/* --- 页头：这一页叫什么，以及一句话说清它是干嘛的。几页原本一进来就是
       内容，没有任何东西先说一句「你在哪」。 --- */
.page-head {
  margin-bottom: var(--space-8);
}

.page-head h1 {
  margin: 0 0 var(--space-2);
}

.page-head-sub {
  margin: 0;
  max-width: 58ch;
  color: var(--muted);
  font-size: var(--text-sm);
  line-height: var(--leading-normal);
}

/* --- 读数格：小标签在上、大数字在中、一行注脚在下（2026-09-08）。
       读数格是一个数、一个词，再多一行注脚，把这个数的构成或来历写在它
       底下——「20 会话」底下写「群聊 8 · 私聊 12」，数就不用再拆成三个并排的
       数了。能力页先长成这个样子（业主看过三轮），会话页、任务页跟上，第三次
       出现就提到这里，三页一个形状。大数字用比例宽度：单个大数不需要对齐列，
       等宽反而让 1 和 0 一样肥；注脚里的数才用等宽。 --- */
.meter-row {
  display: flex;
  align-items: flex-start;
  flex-wrap: wrap;
  gap: var(--space-4) var(--space-8);
}

.meter {
  display: block;
  min-width: 0;
}

.meter-label {
  display: block;
  color: var(--muted);
  font-size: var(--text-xs);
  white-space: nowrap;
}

.meter-figure {
  display: block;
  margin-top: 2px;
  color: var(--fg);
  font-size: var(--text-xl);
  font-weight: var(--weight-semi);
  letter-spacing: -0.02em;
  line-height: 1.2;
  white-space: nowrap;
}

.meter-figure small {
  margin-left: 2px;
  color: var(--muted);
  font-size: var(--text-xs);
  font-weight: var(--weight-medium);
}

/* 主读数：这一排最该看的那个数，金色。一排只有一个。 */
.meter-lead .meter-figure {
  color: var(--gold);
}

.meter-sub {
  display: block;
  margin-top: var(--space-1);
  color: var(--fg-soft);
  font-size: var(--text-xs);
  font-variant-numeric: tabular-nums;
}

@media (max-width: 640px) {
  /* 手机上不出标签：一排标签在这个宽度里挤掉的正是导航本身。桌面壳不会跑到这个
     宽度来（窗口最小 420 但那是桌面），所以这一条只挡网页。
     **收的是标签，不是整个托盘**：应用菜单被 shell.js 挪进了托盘里，整条藏掉会
     连它一起藏，而 `/apps` 页删了之后它是手机上唯一的应用入口。第一版就是整条
     藏的，探针在 500 宽上量出「应用」那一格 0×0——这一条的代价看不见，所以只有
     量得出来。
     那道竖线跟标签一起走：它是「托盘｜其余」的界线，标签不在就没有一边可分。
     它靠 hidden 属性开关，而脚本现在在网页上也跑了，所以得在这儿明写。 */
  body:not(.is-desktop) .topbar-places,
  body:not(.is-desktop) .topbar-places-menu,
  body:not(.is-desktop) .topbar-tabs > .topbar-tab {
    display: none;
  }

  /* 手机上「应用」排在这条栏的最右端，不跟着导航那一段走。它 2026-09-19 之前
     是导航里的第一项（紧跟招牌），这一版换了位置：`/apps` 那一页删掉之后，它
     是手机上**唯一**的应用入口，而导航那一段放不下时是自己横着滑的——会滑走的
     地方不该放唯一的门。两条都写：脚本跑过了它在托盘里（按托盘排），没跑它还是
     栏的第二个孩子（按自己排）。 */
  body:not(.is-desktop) .topbar-tabs,
  .topbar-apps {
    order: 2;
  }
}

/* --- 分节标题。以前是一行几乎看不见的小灰字，于是「更早」「还没跑过」
       这些分组等于不存在。给它字重和一条延伸到底的细线。 --- */
.section-head {
  display: flex;
  align-items: center;
  gap: var(--space-4);
  margin: var(--space-10) 0 var(--space-4);
  color: var(--fg-soft);
  font-size: var(--text-sm);
  font-weight: var(--weight-semi);
}

.section-head:first-child {
  margin-top: 0;
}

.section-head::after {
  content: "";
  flex: 1;
  height: 1px;
  background: var(--line-soft);
}

.section-head .muted {
  color: var(--muted);
  font-size: var(--text-xs);
  font-weight: var(--weight-normal);
}

/* --- 空状态。以前是一行灰字贴在左上角，页面看起来像没加载完。 --- */
.empty {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-16) var(--space-5);
  border-radius: var(--radius-lg);
  background: var(--surface-1);
  color: var(--muted);
  font-size: var(--text-sm);
  text-align: center;
}

.empty-title {
  color: var(--fg-soft);
  font-size: var(--text-base);
  font-weight: var(--weight-medium);
}

/* 页签是字，不是框（业主 2026-09-18）。原来当前页是一个带底色的圆角块，一排
   药丸让顶栏读成「一排待办的动作」；现在没选中的是灰字，当前页是金字加一档
   字重——层级先靠字重和颜色，不靠又多一个面。 */
.topbar-nav-link {
  padding: 6px var(--space-2);
  border-radius: var(--radius-sm);
  background: transparent;
  color: var(--muted);
  /* 正文那一档，不是小一档（业主 2026-08-29：顶栏的字偏小）。页签是一直在
     那儿要被认出来的东西，不是注解。 */
  font-size: var(--text-base);
  font-weight: var(--weight-medium);
  line-height: 1;
  transition: color 0.15s ease;
}

.topbar-nav-link:hover {
  color: var(--fg);
}

.topbar-nav-link.is-current {
  color: var(--gold);
  font-weight: var(--weight-semi);
}

/* 应用页顶栏上唯一那一条：回 Aimy 的出口，贴右端，安静一点——它是备用出口，
   不是这一页要你点的东西（业主 2026-08-14）。桌面端不显示它，托盘里就有
   Aimy 那一颗（见下面 .is-desktop 那一段）。 */
.topbar-nav-exit {
  margin-left: auto;
}

/* 急停铃：全体停手开着的时候，每一页顶栏右端挂的这一枚（业主 2026-09-07：
   「开关隐藏太深」）。顶栏上唯一一处红——正因为它只在出事时出现，才不必再喊得
   更大声。页签平时只是一行字；这一枚有红的底、红的字、一个点，跟它们
   一眼分得开。 */
.topbar-alarm {
  flex: none;
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  padding: 5px 11px;
  border: 1px solid transparent;
  border-radius: var(--radius-pill);
  background: var(--red-soft);
  color: var(--red);
  font-size: var(--text-sm);
  font-weight: var(--weight-semi);
  line-height: 1.2;
  white-space: nowrap;
}

/* 自己设了 display 的类必须自带这一条：浏览器的 [hidden]{display:none} 住在
   用户代理层，输给任何作者声明——不写这一句，关着的急停铃会一直挂在顶栏上，
   那是比没有铃更糟的一种谎（2026-09-04「副本」签实录）。 */
.topbar-alarm[hidden] {
  display: none;
}

.topbar-alarm:hover {
  background: var(--red);
  color: var(--surface-0);
}

.topbar-alarm-dot {
  flex: none;
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: currentColor;
}

/* 铃在呼吸，慢到不烦人又不至于被当成一枚静止的标签。纯装饰：动画关掉之后
   它仍然是红的、仍然在那儿。 */
@keyframes aimy-alarm-pulse {
  0%,
  100% {
    opacity: 1;
  }
  50% {
    opacity: 0.4;
  }
}

@media (prefers-reduced-motion: no-preference) {
  .topbar-alarm-dot {
    animation: aimy-alarm-pulse 1.8s ease-in-out infinite;
  }
}

/* The gallery lights its works on a dark wall; the front door is lit the same
   way. The wash sits behind everything (the page background paints on the
   canvas, below any negative layer) and is the page's only flourish. */
.home::before {
  content: "";
  position: fixed;
  /* 四边写全不用 inset 简写：旧内核不认，光晕会整个消失。 */
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  z-index: -1;
  background: radial-gradient(
    58% 46% at 22% 40%,
    var(--lift),
    var(--lift-soft) 42%,
    transparent 72%
  );
  pointer-events: none;
}

/* 四周一圈很轻的暗角：中央的光晕更聚，画更亮。 */
.home::after {
  content: "";
  position: fixed;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  z-index: -1;
  background: radial-gradient(120% 95% at 50% 30%, transparent 58%, rgba(0, 0, 0, 0.4));
  pointer-events: none;
}

.home-intro {
  max-width: 46ch;
}

/* The showcase is ONE repeating unit — a left-aligned paragraph with its
   drawing under it, 40rem wide, one unit per screenful (owner, 2026-08-04).
   No second composition exists on the page. */
.chapter {
  max-width: 44rem;
  min-height: 84vh;
  margin-inline: auto;
  display: flex;
  flex-direction: column;
  justify-content: center;
}

/* 装饰皆出自一个隐喻——图纸挂在暗墙上：标题前一枚斜方印（头像那张
   歪方脸的角度），画的四角是工程图纸的角标，页面四周一圈暗角聚光。 */
.chapter-head {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  margin: 0 0 var(--space-4);
  font-size: 22px;
  font-weight: 650;
  text-align: left;
}

.chapter-head::before {
  content: "";
  flex: none;
  width: 10px;
  height: 10px;
  background: var(--gold);
  border-radius: 3px;
  transform: rotate(-8.5deg);
}

.chapter-text {
  margin: 0;
  color: var(--fg-soft);
  font-size: 15px;
  line-height: 2;
  text-align: left;
}

.chapter .print {
  position: relative;
  margin-top: 48px;
  padding: var(--space-5);
}

/* 四角各一组 L 形角线，不描整框——图纸钉在墙上的记号。 */
.chapter .print::before {
  content: "";
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  pointer-events: none;
  background:
    linear-gradient(var(--gold-mark), var(--gold-mark)) left top / 18px 1px,
    linear-gradient(var(--gold-mark), var(--gold-mark)) left top / 1px 18px,
    linear-gradient(var(--gold-mark), var(--gold-mark)) right top / 18px 1px,
    linear-gradient(var(--gold-mark), var(--gold-mark)) right top / 1px 18px,
    linear-gradient(var(--gold-mark), var(--gold-mark)) left bottom / 18px 1px,
    linear-gradient(var(--gold-mark), var(--gold-mark)) left bottom / 1px 18px,
    linear-gradient(var(--gold-mark), var(--gold-mark)) right bottom / 18px 1px,
    linear-gradient(var(--gold-mark), var(--gold-mark)) right bottom / 1px 18px;
  background-repeat: no-repeat;
}

.home-signin {
  margin: 96px auto 0;
  color: var(--muted);
  font-size: 13px;
  text-align: center;
}

/* The comics are transparent line art in a warm stroke — drawn straight on
   the dark wall, no white card under them (owner, 2026-08-04). */
.print {
  margin: 0;
}

.print img {
  display: block;
  width: 100%;
  height: auto;
}

.print figcaption {
  margin-top: var(--space-4);
  color: var(--muted);
  font-size: 12px;
  letter-spacing: 0.04em;
  text-align: center;
}

.home-lead {
  margin: var(--space-3) 0 0;
  color: var(--muted);
  font-size: 16px;
}

/* A legend on a hairline; the capabilities page still sections itself with it. */
.topbar-menu > summary {
  list-style: none;
  display: inline-flex;
  align-items: center;
  padding-inline: 10px;
  cursor: pointer;
}

.topbar-menu > summary svg {
  display: block;
}

.topbar-menu > summary::-webkit-details-marker {
  display: none;
}

.topbar-menu[open] > summary {
  color: var(--fg);
}

/* 实底，不透明（业主 2026-09-27：「应用按钮弹出以后背景太透明了，改成不透明，要不然
   看不清应用」——09-19 做的毛玻璃在内容多的页面上压不住底下的字）。一圈描边把它从
   背后分出来。 */
.topbar-menu-panel {
  position: fixed;
  z-index: 20;
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
  min-width: 9rem;
  padding: var(--space-2);
  border-radius: var(--radius);
  border: 1px solid var(--line-soft);
  background: var(--surface-2);
  box-shadow: var(--shadow-2);
}

.topbar-menu-panel .topbar-nav-link {
  display: block;
  padding: var(--space-2) var(--space-3);
  border-radius: var(--radius-sm);
  white-space: nowrap;
}

/* 面板里的那几项仍然是一行行可点的东西，底色是它们唯一的 hover 记号——
   栏上的页签去掉底色之后，这一条得自己写回来。 */
.topbar-menu-panel .topbar-nav-link:hover {
  background: var(--surface-3);
}

/* 管理菜单里「急停」那一项旁边的红字。菜单要打开才看得见，所以它不是警报本身
   ——顶栏那枚铃才是；这一行是「你翻到这里了，就是这一项」。不给自己设 display
   （行内元素本来就是行内的），hidden 才收得住；保险那一条仍然写上。 */
.topbar-menu-alarm {
  margin-left: var(--space-2);
  color: var(--red);
  font-weight: var(--weight-semi);
}

.topbar-menu-alarm[hidden] {
  display: none;
}

/* 只有管理员看得见的那几项，行尾一枚淡色小盾牌（业主 2026-10-25）。靠右对齐，几行的盾牌
   排成一列，字照旧左对齐——不贴在字后面，就不会读成名字的一部分。最淡那一档字色，不写字、
   不带框（09-26 拿掉的是一串带框的「管理员」）。这一行只有管理员会拿到，没有要 hidden 的时候。 */
.topbar-menu-panel .topbar-nav-link.is-admin-only {
  display: flex;
  align-items: center;
}

.topbar-menu-mark {
  flex-shrink: 0;
  margin-left: auto;
  color: var(--faint);
}

/* 人人都有的那段和管理员那段之间的一道细线（业主 2026-10-25「按照分类也重新排序一下」）。
   用 --line 不用面板外框那档 --line-soft：后者跟面板的底只差 1，在面板里面画等于没画。
   左右缩进到字的边，不顶到面板边。 */
.topbar-menu-rule {
  flex-shrink: 0;
  height: 0;
  margin: var(--space-1) var(--space-3);
  border: 0;
  border-top: 1px solid var(--line);
}

.data-table {
  border-collapse: collapse;
  width: 100%;
  font-size: var(--text-sm);
}

.data-table th,
.data-table td {
  border-top: 1px solid var(--line-soft);
  padding: var(--space-3);
  text-align: left;
  vertical-align: top;
}

/* 表头是标尺不是内容：小、轻、跟数据拉开一档，别跟第一行数据长得一样。 */
.data-table th {
  border-top: 0;
  padding-bottom: var(--space-2);
  color: var(--muted);
  font-size: var(--text-xs);
  font-weight: var(--weight-medium);
  letter-spacing: var(--tracking-label);
}

.data-table tbody tr:hover td {
  background: var(--surface-2);
}

/* 数字列上下对齐——一列金额里有一个不对齐，整列就读不成一列。 */
.data-table .num {
  font-variant-numeric: tabular-nums;
  text-align: right;
}

.data-table tr.overdue td {
  background: var(--red-soft);
}

.data-table tr.blocked {
  box-shadow: inset 3px 0 var(--red);
}

/* 版心是版式主干，只用全内核都认的写法：min()/margin-inline 在旧内核里
   整条被丢，版心就静默失效、页面铺满全屏（2026-08-12 前端体检实录）。 */
.container {
  width: 100%;
  max-width: var(--container-width);
  margin-left: auto;
  margin-right: auto;
  padding: var(--space-10) var(--space-6) var(--space-16);
}

/* --- 宽屏：顶栏不在，导航在侧栏（业主 2026-09-19）---------------------------
   断点取 641，跟对话页清单变抽屉的那个断点是同一个数（对话页那份样式表）：一个站点只该
   有一个「这是宽屏了」的说法。 */
@media (min-width: 641px) {
  /* **栏必须排在左侧栏上面**（业主 2026-09-19 晚：「应用弹窗被压住了」——截图上
     应用菜单的左边一列不见了）。探针定的案：面板那两颗方块（x=161 和 x=237，都
     落在侧栏的 0–240 里）正中命中的是 `.chat-side-new` 和 `.chat-side-projects-row`
     ——**不是被裁，是被侧栏盖住了**。
     根因跟 09-19 早些时候那一次是同一条规矩的两面：`position: sticky` 加 z-index
     也开层叠上下文，所以面板那个 z-index:20 只在栏内部排序，整条栏以 10 参加根
     上下文，而侧栏是 50。上一次是面板在侧栏里、被正文盖住，给侧栏写了 50；这一次
     面板搬进了栏里，轮到栏不够高。
     取 55：压过侧栏（50）和正文，让给灯箱（60）和弹窗（80）。只在 641 以上写——
     手机上没有侧栏，那儿的会话抽屉是 30 而且要盖住整屏包括这条栏，栏要是 55 就
     会浮在抽屉上面。

     左内衬 8（2026-10-13）：最左边是「个人会话」那一颗（头像撤了，业主：「顶部栏节省空间」），
     它的左边跟底下左侧栏里一行一行的底块（栏宽里缩进 8）对齐。macOS 和 Windows 的窗口由
     `.is-desktop-mac .topbar`、`.is-desktop-win .topbar` 以更高的权重盖过它。 */
  .topbar {
    padding-left: var(--space-2);
    z-index: 55;
  }

  /* 宽屏上这一条就是导航（业主 2026-09-19 晚：「web 端不再打开新页面，和桌面端
     一样，保持一个顶部栏管理页签，这样两者就同一了」）。栏上只剩三样：标签、
     应用菜单、急停铃——招牌和那一排页签是手机才要的，宽屏上招牌在侧栏头上，
     管理菜单在侧栏底下，再来一份就是同一件事说两遍。
     应用页同理，而且这一次连浏览器一起（业主同日上午只说了桌面端：「最右侧这个
     头像＋应用名称，不要显示了」，那时网页上还留着 08-14 那块门牌）。宽屏的网页
     现在也有那一排标签，上面已经写着「作图」而且是高亮的那一颗，门牌再来一次是
     同一件事说两遍。**手机上那块门牌一个字没动**：640 以下没有标签，同事从聊天
     里点进来看到的唯一一页就是它，那儿还得靠「← 回 Aimy」回去。
     急停铃在应用页上留着——它平时 hidden，停机时是唯一的告示，而应用页没有侧栏
     替它站岗（业主 2026-09-07）。 */
  .shell-rail > .topbar > .topbar-avatar-link,
  .shell-rail > .topbar > .topbar-nav,
  .shell-rail > .topbar > .topbar-alarm,
  .shell-app > .topbar > .topbar-avatar-link,
  .shell-app > .topbar > .topbar-nav,
  .has-dock > .topbar > .topbar-apps,
  .has-dock > .topbar > .topbar-alarm,
  .has-dock > .topbar > .topbar-live {
    display: none;
  }

  /* 最左边那一条竖栏（2026-10-14）：从顶栏底下到窗口底，贴着窗口左边。顶栏里的「应用」、急停铃和
     「活」的那一格（手机才用的那一份）在它在的页上收起（上面那一条）：三样都在它身上。层次 51，比左侧栏（50）高一档，往右弹出来的
     菜单才不被左侧栏盖住；应用页上降到 44——作图的全屏看图（45）这些铺满窗口的层得盖住它。 */
  .shell-dock {
    display: flex;
    position: fixed;
    top: var(--topbar-h);
    bottom: 0;
    left: 0;
    z-index: 51;
    width: var(--dock-w);
    box-sizing: border-box;
    flex-direction: column;
    align-items: center;
    /* 顶上 12：第一格（40 高）的中线落在左栏「新会话」那一行的中线上（2026-10-28 量的：都在顶栏下 32）。 */
    padding: var(--space-3) 0 var(--space-3);
    /* 跟顶栏、左栏同一块底，竖栏和左栏之间不画线（2026-10-27「一整片」）。 */
    background: var(--bg);
  }

  .shell-app .shell-dock {
    z-index: 44;
  }

  .has-dock .railbar {
    left: var(--dock-w);
  }

  .has-dock.shell-app .shell-body {
    padding-left: var(--dock-w);
  }

  /* 栏从顶栏底下起，不是从窗口顶起——顶栏这一版留着了（业主 2026-09-19 晚把
     导航搬回了那条栏）。`--topbar-h` 是 :root 上那一个，不在这里再定义一遍：
     09-18 把栏从 64 压到 48 时，栈里好几处各自抄了一份栏高，栏改了它们不会跟着
     改，而多出来的一道空白不会有人报错。 */
  .shell-rail .railbar {
    display: flex;
    top: var(--topbar-h);
  }

  .shell-rail .shell-body {
    padding-left: var(--rail-w);
  }

  /* 有竖栏的页：正文让出竖栏加左侧栏两条的宽。老内核拿不到 calc 里的变量，前面那行死数接住。 */
  .has-dock.shell-rail .shell-body {
    padding-left: 328px;
    padding-left: calc(var(--dock-w) + var(--rail-w));
  }

  /* 收起来：左栏整条藏起来，正文贴着最左边那条竖栏（业主 2026-10-14 晚，走查第 2 条——原来缩成
     一条 56 宽的窄轨，跟竖栏两条窄栏并排）。开关是栏右边缘的把手（下面的 .rail-edge）。
     记号挂在 body 上而不是栏上——栏是 fixed 的，占位的是 .shell-body，两处得一起改，而 CSS 读不到
     孩子的状态。挂它的是 chat-sessions.js，第一帧由母版照着记下的状态先挂上。
     收和展是一段滑动（业主 2026-10-24：「增加收起展开的动画」）：栏往左滑进竖栏底下（竖栏高一层、
     底色不透），正文的左内衬同一个时长跟着走——两样一起动，正文不会先跳过去再等栏。滑完才藏
     （visibility 晚一拍）：藏起来的栏点不到、Tab 也走不进去；展开时一开始就看得见。展开着不写
     translateX(0)：任何 transform 都会让栏变成里面 fixed 元素的定位框，「···」菜单和悬停浮出的日期卡
     就不再按窗口摆了。第一帧就是收着的页不滑——过渡只在样式变了的时候跑。 */
  .shell-rail .railbar {
    transition: transform var(--motion-base) var(--ease-out), visibility 0s;
  }

  .shell-rail.is-rail-folded .railbar {
    visibility: hidden;
    transform: translateX(-100%);
    transition: transform var(--motion-base) var(--ease-out), visibility 0s linear var(--motion-base);
  }

  .shell-rail .shell-body {
    transition: padding-left var(--motion-base) var(--ease-out);
  }

  /* 收起／展开左栏的把手（业主 2026-10-24：「收起左侧栏的按钮，和下面的按钮，语义有所不同」，选了
     「会话栏右边缘的小把手」）。栏的 1 像素右边线外面一条 16 宽的窄边，从栏顶到栏底都能点；挂在栏
     里面，栏滑它就跟着滑，收着的时候正好贴在竖栏右边。展开着平时看不见，手停到这条边上，边的正中
     浮出一枚小把手——一块比左栏亮一档的面，右边两个圆角，像从栏里拉出来的一截；收着的时候它一直露着
     （那是回来的路），面跟竖栏同一档，看上去是竖栏伸出来的。记号是一枚侧栏（2026-10-27，原来是会翻面的箭头）。栏收着是 visibility:
     hidden，这一枚自己写回 visible。 */
  .rail-edge {
    display: flex;
    position: absolute;
    top: 0;
    bottom: 0;
    right: -25px;
    width: 24px;
    align-items: center;
    padding: 0;
    border: 0;
    background: none;
    color: var(--muted);
    cursor: pointer;
    visibility: visible;
  }

  /* 通用的 button:hover 比 .rail-edge 重一档，会给整条窄边铺一层亮底（业主 2026-10-24：「竖着的这一条
     背景色移除，只 hover 出那个小的按钮就行了」）。悬停时亮的只有中间那枚把手。 */
  .rail-edge:hover {
    background: none;
  }

  .rail-edge-tab {
    display: flex;
    width: 24px;
    height: 44px;
    align-items: center;
    justify-content: center;
    border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
    background: var(--surface-2);
    opacity: 0;
    transition:
      opacity var(--motion-quick) var(--ease-out),
      background var(--motion-quick) var(--ease-out),
      color var(--motion-quick) var(--ease-out);
  }

  .rail-edge-tab > svg {
    display: block;
    width: 16px;
    height: 16px;
  }

  .rail-edge:hover .rail-edge-tab,
  .is-rail-folded .rail-edge-tab {
    opacity: 1;
  }

  .rail-edge-tab:hover {
    background: var(--surface-3);
    color: var(--fg);
  }

  /* 用键盘走到它，把手露出来，金色焦点框也画在把手上，不圈整条窄边。单写两条：不认 :focus-visible 的
     老内核只丢它们自己。 */
  .rail-edge:focus-visible {
    outline: none;
  }

  .rail-edge:focus-visible .rail-edge-tab {
    opacity: 1;
    outline: 2px solid var(--gold);
    outline-offset: 2px;
  }

  .shell-rail.is-rail-folded .shell-body,
  .shell-rail.no-rail .shell-body {
    padding-left: 0;
  }

  /* 全部项目那一页没有左栏（业主 2026-10-14 夜：「左侧的列表直接移除」），跟收起来一样只让出竖栏。 */
  .has-dock.shell-rail.is-rail-folded .shell-body,
  .has-dock.shell-rail.no-rail .shell-body {
    padding-left: var(--dock-w);
  }
}

/* 没有悬停的宽屏（平板）上把手一直露着，不然展开着的时候没处收。手机上 .rail-edge 本来就不出现。 */
@media (hover: none) {
  .rail-edge-tab {
    opacity: 1;
  }
}

/* 要少动的人：收和展直接到位，不滑。 */
@media (prefers-reduced-motion: reduce) {
  .shell-rail .railbar,
  .shell-rail.is-rail-folded .railbar,
  .shell-rail .shell-body {
    transition: none;
  }
}

@media (max-width: 820px) {
  .topbar {
    padding-inline: 18px;
  }
}

/* On a phone the nav pills are wider than the bar, which used to push the
   whole document sideways. Give them their own row and let that row scroll. */
@media (max-width: 640px) {
  /* 手机上侧栏那一行跟着清单进了抽屉，而顶栏上已经有「应用」那一格：一页一扇。 */
  .railbar-apps {
    display: none;
  }

  /* 手机上顶栏是一行（业主 2026-09-15 设计审查）：头像和页签排在同一行，页签
     放不下时自己横着滑。原来是两行——头像一行、页签一行——量出来 107 高，
     对话页再加一行标题，第一句话要到 150 像素以下才开始。 */
  .topbar {
    min-height: 0;
    padding: var(--space-2) var(--space-3);
    gap: var(--space-2);
    flex-wrap: nowrap;
  }

  .topbar-avatar {
    width: 32px;
    height: 32px;
  }

  /* 「应用」那一枚在手机上跟头像同高。宽屏上它是 36，因为它排在 36 高的标签
     中间；这里没有标签，而这条栏是「上下各 8 的内衬 + 最高的那个孩子」——
     36 会把 48 顶成 52（探针在 500 宽上量到的）。 */
  body:not(.is-desktop) .topbar-menu > summary.topbar-apps-button {
    height: 32px;
  }

  /* 「任务」一格：跟「应用」同高、同圆角、同一档底色（空心一圈描边，手一过去填上
     surface-3），带着侧栏那一行同一个在跑的数。站在任务页上它就是填上的那个样子——
     跟「应用」菜单开着时同一种说法：这扇门此刻是开着的。
     order 1：排在招牌和管理菜单（order 0）后面、应用（order 2）前面，不进会横着滑的
     导航那一段。 */
  .topbar-tasks {
    order: 1;
    flex: none;
    height: 36px;
    display: flex;
    align-items: center;
    padding: 0 var(--space-4);
    border: 0;
    border-radius: var(--radius);
    background: var(--lift-soft);
    color: var(--fg-soft);
    font-size: var(--text-base);
    line-height: 1.4;
    white-space: nowrap;
    text-decoration: none;
  }

  body:not(.is-desktop) .topbar-tasks {
    height: 32px;
  }

  /* 字和数之间的空，用外边距：老内核不认 flex 的 gap（AGENTS.md）。 */
  .topbar-tasks > svg {
    flex: none;
    display: block;
    margin-right: var(--space-2);
  }

  .topbar-tasks > .live-count {
    margin-left: var(--space-2);
  }

  .topbar-tasks:hover,
  .topbar-tasks[aria-current="page"] {
    background: var(--lift);
    color: var(--fg);
    text-decoration: none;
  }

  /* 页签占住头像右边剩下的地方。挤是被压出来的：flex 子项默认可以收缩到比
     内容还窄，页签就被压成「会/话」竖着排（500px 实拍），所以子项不收缩、
     整排自己滑。 */
  .topbar-nav {
    flex: 1 1 auto;
    min-width: 0;
    gap: 2px;
    flex-wrap: nowrap;
    overflow-x: auto;
    scrollbar-width: none;
  }

  /* 里面那一格跟着一起不换行：滚动的是 .topbar-nav，它只管别把自己的孩子
     压扁——min-width:0 才允许它缩到比内容窄，让外面那条滑起来。 */
  .topbar-nav-core {
    min-width: 0;
    gap: 2px;
    flex-wrap: nowrap;
  }

  .topbar-nav-link {
    flex: none;
    padding: 7px 8px;
    white-space: nowrap;
  }

  .topbar-nav::-webkit-scrollbar {
    display: none;
  }

  /* 急停铃开着时贴在同一行最右端，不被页签挤走——报警的东西不能滑出屏幕。 */
  .topbar-alarm {
    flex: none;
    margin-left: auto;
    padding: 4px 8px;
  }
}

/* --- motion ----------------------------------------------------------------
   **换页是直接换，不做整页的淡出淡入**（业主 2026-09-26 两轮）。第一轮「切换页面的时候
   动态效果不一致，有些闪烁」——当时的整页交叉淡化让新旧两页的字叠 200 毫秒；我改成
   「中间那块先淡出、再淡入」，第二轮业主：「还是闪烁，反而更难看了」——淡出到淡入之间
   那一段中间是空的，那就是一闪。任何让整块内容先变暗再亮起来的换法都是这一闪。

   所以换页不动整页：浏览器在新页画好之前一直留着旧页（同源导航本来就这样），画好了
   一帧换上。左栏和顶栏两页一样，换上去看不出变化；中间那块直接是新内容。
   有动的只是内容自己的出场：列表一行一行浮起来（任务页那一段，业主点名喜欢：「原来
   任务页还有一个逐条显示的渐显动画」）——它动的是新内容里的一行行，不是先把整块
   藏起来。

   view transition 留着，但**一帧都不动**：它在这里只做一件事——新页没画好之前一直
   拿旧页的样子挡着，画好了一刀切过去。去掉它逐帧量过：换页中间会有一整帧白的（新
   文档还没画、画布是默认白底）。时长为零，所以没有淡、没有叠、没有空。 */

@view-transition {
  navigation: auto;
}

::view-transition-group(*),
::view-transition-old(*),
::view-transition-new(*) {
  animation: none;
}

/* 切的那一帧只放新页。动画关掉之后，旧页和新页两张快照会在同一帧里叠着显示：不透明
   时看不出来，毛玻璃下两张半透明叠成一张几乎不透明的——开发版客户端逐帧量到每次换页
   都有这么一帧（透明度 0.84 跳到 0.97 再回来），业主说的「从不透明变得透明」就是它。
   旧页用不着：这一刻新页已经画好了，旧页的样子在此之前一直是真页面自己挡着的。 */
::view-transition-old(*) {
  display: none;
}

@media (prefers-reduced-motion: no-preference) {
  @keyframes menu-pop {
    from {
      opacity: 0;
      transform: translateY(-4px) scale(0.98);
    }
  }

  @keyframes card-in {
    from {
      opacity: 0;
      transform: translateY(10px);
    }
  }

  /* 列表一行一行浮起来（任务页、介绍页）。业主 2026-09-26 第二轮点名要留着它。 */
  .chapter,
  .task-grid > * {
    animation: card-in 0.32s cubic-bezier(0.2, 0.7, 0.3, 1) backwards;
  }

  .task-grid > :nth-child(2) { animation-delay: 0.04s; }
  .task-grid > :nth-child(3) { animation-delay: 0.08s; }
  .task-grid > :nth-child(4) { animation-delay: 0.12s; }
  .task-grid > :nth-child(5) { animation-delay: 0.16s; }
  .task-grid > :nth-child(6) { animation-delay: 0.2s; }
  .task-grid > :nth-child(7) { animation-delay: 0.24s; }
  .task-grid > :nth-child(n + 8) { animation-delay: 0.28s; }

  .topbar-menu[open] .topbar-menu-panel {
    animation: menu-pop 0.16s ease-out;
  }

  /* 「打开」的四个词（2026-09-17）：浮起（面板、折叠段、新出现的一行）、淡入（遮罩）、
     从右滑入（抽屉）、弹窗入场（略缩放的浮起）。只定义出场：关闭走 hidden／display 切换，
     瞬间消失比慢慢退场更轻。名字是 aimy- 前缀的全局关键帧，页面样式表直接引用。 */
  @keyframes aimy-rise {
    from {
      opacity: 0;
      transform: translateY(8px);
    }
  }

  @keyframes aimy-fade {
    from {
      opacity: 0;
    }
  }

  @keyframes aimy-slide-right {
    from {
      opacity: 0;
      transform: translateX(24px);
    }
  }

  /* 「几件在跑」那一圈（.live-count-spin）。纯装饰：动画关掉之后记号和数字都还在。 */
  @keyframes aimy-spin {
    to {
      transform: rotate(360deg);
    }
  }

  .live-count-spin {
    animation: aimy-spin 1.1s linear infinite;
  }

  @keyframes aimy-dialog-in {
    from {
      opacity: 0;
      transform: translateY(10px) scale(0.98);
    }
  }

  .aimy-dialog-back {
    animation: aimy-fade var(--motion-quick) ease-out;
  }

  .aimy-dialog {
    animation: aimy-dialog-in var(--motion-base) var(--ease-out);
  }

  .aimy-panel {
    animation: menu-pop var(--motion-quick) var(--ease-out);
  }
}

/* 弹窗：Core 的一套，页面和应用共用（业主 2026-08-23：浏览器自带的很难用）。
   .aimy-* 前缀属于 Core；应用只调 window.aimyDialog，不重定义这些类。

   2026-10-16 业主看着看板上「新建事情」里弹出的那张白底英文日历：「这些弹窗、日期选择器等等都要
   设计好，统一主题。美观、专业」。所以弹窗里的每一样都是自己画的，一套样子：
   - 浮层一条规矩：比它底下那一层亮一档，一圈极淡的白边加一层影子说「浮在上面」。弹窗是
     surface-2（底下是遮罩），弹窗里拉开的单子、日历是 surface-3（底下是弹窗）。
   - 要填的地方是比弹窗深一档的井（--field），40 高；停上去显出边，在填的那一格描金、外面一圈淡金。
   - 选一个人、选一关：一张浮起来的单子，选中的那一行后面一个金勾，项多了顶上带搜索。
   - 日期：一张中文的、周一开头的日历；今天是金字带一个小点，选中的那天是实心金；底下一排
     「今天、明天、本周五、下周一」。
   - 按钮跟看板上一样：实心金只给「这一下要你做的那件事」，取消是一行安静的字。 */
:root {
  /* 浮层那一圈边：用 box-shadow 画，不占宽度，所以 hover 改它不会挤动布局。 */
  --edge-float: 0 0 0 1px rgba(255, 255, 255, 0.07);
  /* 实心金上的字：最深的那一档，跟看板上的金钮一个颜色。 */
  --on-gold: var(--surface-sunken);
}

.aimy-dialog-back {
  position: fixed;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  z-index: 80;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 16px;
  background: rgba(10, 10, 10, 0.66);
}

.aimy-dialog {
  width: 100%;
  max-width: 400px;
  max-height: 100%;
  overflow-y: auto;
  box-sizing: border-box;
  padding: 22px 22px 18px;
  border-radius: var(--radius-lg);
  background: var(--surface-2);
  box-shadow: var(--shadow-3), var(--edge-float);
}

.aimy-dialog.is-form,
.aimy-dialog.is-choose {
  max-width: 440px;
}

/* panel：页面交给它的一张卡（2026-10-17，用量页一个人的习惯卡）。没有按钮，右上角一个安静的「×」。 */
.aimy-dialog.is-panel {
  position: relative;
  max-width: 440px;
  padding: 24px;
}

.aimy-dialog-close {
  position: absolute;
  top: 16px;
  right: 16px;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  padding: 0;
  border: 0;
  border-radius: var(--radius-pill);
  background: transparent;
  color: var(--faint);
  cursor: pointer;
}

.aimy-dialog-close[hidden] {
  display: none;
}

.aimy-dialog-close:hover {
  background: var(--surface-3);
  color: var(--fg);
}

.aimy-dialog-title {
  margin: 0 0 18px;
  color: var(--fg);
  font-size: var(--text-md);
  font-weight: var(--weight-semi);
  line-height: var(--leading-tight);
}

/* 标题底下有一段说明时，说明贴着标题，跟下面的东西隔开。 */
.aimy-dialog-title.has-body {
  margin-bottom: 6px;
}

.aimy-dialog-body {
  margin: 0 0 18px;
  color: var(--muted);
  font-size: var(--text-sm);
  line-height: var(--leading-snug);
  word-break: break-word;
  white-space: pre-wrap;
}

/* 问一句、告诉一声：那一段话就是要读的正文，亮一档、大一号。表单、选一项里它只是提示。 */
.aimy-dialog.is-confirm .aimy-dialog-body,
.aimy-dialog.is-alert .aimy-dialog-body {
  color: var(--fg-soft);
  font-size: 14px;
  line-height: 1.6;
}

/* aimyDialog.form：一格一行，字在井上面。 */
.aimy-dialog-field {
  display: block;
  margin: 0 0 14px;
}

.aimy-dialog-label {
  display: block;
  margin: 0 0 6px;
  color: var(--muted);
  font-size: var(--text-sm);
  line-height: 18px;
}

.aimy-dialog-input {
  display: block;
  width: 100%;
  height: var(--control-lg);
  box-sizing: border-box;
  margin: 0 0 14px;
  padding: 0 12px;
  border: 1px solid transparent;
  border-radius: var(--radius-sm);
  background: var(--field);
  color: var(--fg);
  font: inherit;
  font-size: var(--text-base);
  font-weight: var(--weight-normal);
  line-height: 38px;
  transition:
    border-color var(--motion-quick) ease,
    box-shadow var(--motion-quick) ease;
}

.aimy-dialog-field .aimy-dialog-input {
  margin: 0;
}

.aimy-dialog-input:hover {
  border-color: var(--line-strong);
  background: var(--field);
  color: var(--fg);
}

/* 在填的那一格：描金，外面一圈淡金。全站那条 2px 的焦点框在这里让给它。 */
.aimy-dialog-input:focus,
.aimy-dialog-input:focus-visible,
.aimy-pick[aria-expanded="true"] {
  border-color: var(--gold-line);
  outline: none;
  box-shadow: 0 0 0 3px var(--gold-soft);
}

.aimy-dialog-textarea {
  height: auto;
  min-height: 104px;
  padding: 10px 12px;
  line-height: var(--leading-snug);
  resize: vertical;
}

/* 选人、选日期的那一格：跟输入框同一口井，右端一个小记号（下拉是 ⌄，日期是日历）。 */
.aimy-pick {
  display: flex;
  align-items: center;
  text-align: left;
  cursor: pointer;
}

.aimy-pick-text {
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}

.aimy-pick.is-empty .aimy-pick-text {
  color: var(--faint);
}

.aimy-pick-icon {
  display: flex;
  flex: none;
  margin-left: 8px;
  color: var(--muted);
  transition: transform var(--motion-quick) var(--ease-out);
}

.aimy-pick[aria-expanded="true"] .aimy-pick-icon.is-turn {
  transform: rotate(180deg);
}

/* 弹窗里拉开的那一层：单子、日历。它挂在遮罩上（不被弹窗的滚动裁掉），位置由脚本按那一格算。 */
.aimy-panel {
  position: fixed;
  z-index: 81;
  box-sizing: border-box;
  padding: 6px;
  border-radius: var(--radius);
  background: var(--surface-3);
  box-shadow: var(--shadow-3), var(--edge-float);
}

.aimy-list {
  display: flex;
  flex-direction: column;
  max-height: 304px;
}

.aimy-list-search {
  flex: none;
  width: 100%;
  height: 34px;
  box-sizing: border-box;
  margin: 0 0 6px;
  padding: 0 10px;
  border: 1px solid transparent;
  border-radius: var(--radius-sm);
  background: var(--field);
  color: var(--fg);
  font: inherit;
  font-size: var(--text-sm);
}

.aimy-list-search:focus,
.aimy-list-search:focus-visible {
  border-color: var(--gold-line);
  outline: none;
}

.aimy-list-rows {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
}

.aimy-list-row {
  display: flex;
  align-items: center;
  min-height: 34px;
  padding: 0 10px;
  border-radius: var(--radius-sm);
  color: var(--fg-soft);
  font-size: var(--text-sm);
  line-height: 18px;
  cursor: pointer;
}

/* 低一级的项（某一关底下的成果）缩进一格。 */
.aimy-list-row.is-indented {
  padding-left: 26px;
}

.aimy-list-row.is-active {
  background: var(--surface-4);
  color: var(--fg);
}

.aimy-list-row.is-chosen {
  color: var(--fg);
  font-weight: var(--weight-medium);
}

/* 底下还挂着缩进项的那一行（一关）：字重一档，读得出是一组的头。 */
.aimy-list-row.is-group {
  color: var(--fg);
  font-weight: var(--weight-medium);
}

.aimy-list-label {
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}

.aimy-list-note {
  flex: none;
  margin-left: 10px;
  color: var(--faint);
  font-size: var(--text-xs);
  font-weight: var(--weight-normal);
}

.aimy-list-tick {
  display: flex;
  flex: none;
  margin-left: 10px;
  color: var(--gold);
}

.aimy-list-empty {
  padding: 8px 10px;
  color: var(--faint);
  font-size: var(--text-sm);
}

/* 日历：七列，一格 36×34，周一开头。格子用 flex 折行排，老内核也认。 */
.aimy-cal {
  width: 276px;
  padding: 12px;
}

.aimy-cal-head {
  display: flex;
  align-items: center;
  margin: 0 0 6px;
  padding: 0 0 0 8px;
}

.aimy-cal-title {
  flex: 1 1 auto;
  color: var(--fg);
  font-size: var(--text-base);
  font-weight: var(--weight-semi);
  font-variant-numeric: tabular-nums;
}

.aimy-cal-nav {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  margin: 0 0 0 2px;
  padding: 0;
  border: 0;
  border-radius: var(--radius-sm);
  background: transparent;
  color: var(--muted);
}

.aimy-cal-nav:hover {
  background: var(--surface-4);
  color: var(--fg);
}

.aimy-cal-grid {
  display: flex;
  flex-wrap: wrap;
  width: 252px;
}

.aimy-cal-weekday {
  width: 36px;
  height: 26px;
  color: var(--faint);
  font-size: var(--text-xs);
  line-height: 26px;
  text-align: center;
}

.aimy-cal-day {
  position: relative;
  width: 36px;
  height: 34px;
  margin: 0;
  padding: 0;
  border: 0;
  border-radius: var(--radius-sm);
  background: transparent;
  color: var(--fg-soft);
  font: inherit;
  font-size: var(--text-sm);
  font-weight: var(--weight-normal);
  font-variant-numeric: tabular-nums;
  line-height: 34px;
  text-align: center;
  cursor: pointer;
}

.aimy-cal-day:hover,
.aimy-cal-day.is-focus {
  background: var(--surface-4);
  color: var(--fg);
}

.aimy-cal-day.is-past,
.aimy-cal-day.is-out {
  color: var(--faint);
}

.aimy-cal-day.is-out {
  opacity: 0.55;
}

/* 今天：金字，底下一个小点。 */
.aimy-cal-day.is-today {
  color: var(--gold);
  font-weight: var(--weight-semi);
}

.aimy-cal-day.is-today::after {
  content: "";
  position: absolute;
  bottom: 5px;
  left: 50%;
  width: 4px;
  height: 4px;
  margin-left: -2px;
  border-radius: 50%;
  background: var(--gold);
}

.aimy-cal-day.is-chosen,
.aimy-cal-day.is-chosen:hover {
  background: var(--gold);
  color: var(--on-gold);
  font-weight: var(--weight-semi);
  opacity: 1;
}

.aimy-cal-day.is-chosen::after {
  background: var(--on-gold);
}

/* 键盘挪到的那一格：一圈金线，跟鼠标停着的那一格分得开。 */
.aimy-cal-day.is-focus {
  box-shadow: inset 0 0 0 1px var(--gold-line);
}

.aimy-cal-foot {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  margin: 8px 0 0;
  padding: 10px 0 0;
  border-top: 1px solid var(--line);
}

.aimy-cal-quick {
  height: 26px;
  margin: 0 6px 0 0;
  padding: 0 10px;
  border: 0;
  border-radius: var(--radius-pill);
  background: var(--surface-4);
  color: var(--fg-soft);
  font-size: var(--text-xs);
  font-weight: var(--weight-normal);
  line-height: 26px;
}

.aimy-cal-quick:hover {
  background: var(--lift);
  color: var(--gold-bright);
}

.aimy-cal-clear {
  height: 26px;
  margin: 0 0 0 auto;
  padding: 0 6px;
  border: 0;
  background: transparent;
  color: var(--muted);
  font-size: var(--text-xs);
  font-weight: var(--weight-normal);
  line-height: 26px;
}

.aimy-cal-clear:hover {
  background: transparent;
  color: var(--fg);
}

/* aimyDialog.choose：一项一整行，名字一行、底下一行小字说它是什么；点一项就是回答，项多了在框里滚。 */
.aimy-dialog-choices {
  max-height: 50vh;
  margin: 0 -10px 12px;
  overflow-y: auto;
}

.aimy-dialog-choice {
  display: block;
  width: 100%;
  box-sizing: border-box;
  margin: 0;
  padding: 10px 12px;
  border: 0;
  border-radius: var(--radius-sm);
  background: transparent;
  color: var(--fg);
  font-size: var(--text-base);
  font-weight: var(--weight-medium);
  line-height: var(--leading-tight);
  text-align: left;
}

.aimy-dialog-choice:hover,
.aimy-dialog-choice:focus-visible {
  outline: none;
  background: var(--surface-3);
  color: var(--fg);
}

.aimy-dialog-choice + .aimy-dialog-choice {
  margin-top: 2px;
}

.aimy-dialog-choice-detail {
  display: block;
  margin: 4px 0 0;
  color: var(--muted);
  font-size: var(--text-xs);
  font-weight: var(--weight-normal);
  line-height: var(--leading-snug);
}

/* 底下一排钮：取消是一行安静的字，确定是实心金（要删东西时是实心红）。 */
.aimy-dialog-row {
  display: flex;
  justify-content: flex-end;
  margin: 8px 0 0;
}

.aimy-dialog-row > * + * {
  margin-left: 8px;
}

.aimy-dialog-cancel,
.aimy-dialog-ok {
  min-width: 76px;
  height: var(--control-md);
  padding: 0 16px;
  border: 0;
  border-radius: var(--radius-sm);
  font-size: var(--text-sm);
  line-height: var(--control-md);
}

.aimy-dialog-cancel {
  background: transparent;
  color: var(--muted);
  font-weight: var(--weight-medium);
}

.aimy-dialog-cancel:hover {
  background: var(--surface-3);
  color: var(--fg);
}

.aimy-dialog-ok {
  background: var(--gold);
  color: var(--on-gold);
  font-weight: var(--weight-semi);
}

.aimy-dialog-ok:hover {
  background: var(--gold-bright);
  color: var(--on-gold);
}

.aimy-dialog-ok.is-danger,
.aimy-dialog-ok.is-danger:hover {
  background: var(--red);
  color: var(--on-gold);
}

/* 弹窗一打开焦点就在「确定」上：用跟输入框一样的一圈淡金，不用全站那条 2px 的粗框。 */
.aimy-dialog-ok:focus-visible,
.aimy-dialog-cancel:focus-visible {
  outline: none;
  box-shadow: 0 0 0 3px var(--gold-wash);
}

/* --- 滚动条：全站一个样子 -------------------------------------------------------
   对话正文那一条（10-10 定的：系统细条，滑块压到 --surface-3，轨道不画）给每个能滚的块，
   视口自己那条也算。业主 2026-10-24 看着左栏：「有点复杂，滚动条左右还有两条竖线一样。
   和右边的聊天框滚动条不一致。要改成右侧聊天框的同款」——浏览器自己画的暗色那条带一条
   轨道，轨道两边各一道线。轨道透明，放在哪一层底色上都不露边。
   只用标准写法说颜色和粗细，Mac 的悬浮／常驻偏好照旧由系统定。:where() 让这一条不占
   权重，哪个块自己写了（顶栏那一排 scrollbar-width: none）照旧算它的。Windows 不走这条：
   标准写法一写，下面那套 09-28 业主点过头的 ::-webkit-scrollbar 就全不算了。
   老内核不认 :where()，整条丢掉，就是浏览器自己的暗色滚动条（根上的 color-scheme）。 */
:where(html:not(.is-win)),
:where(html:not(.is-win)) * {
  scrollbar-color: var(--surface-3) transparent;
  scrollbar-width: thin;
}

/* --- 滚动条（只在 Windows 上）---------------------------------------------------
   Windows 的内核画的是白底、带上下箭头的粗滚动条，深色页面上像贴了一条胶带
   （业主 2026-09-28，第一台 Windows 真机：「太难看，和黑色主题不融合」）。换成一条
   透明轨道上的圆头细滑块，没有箭头，颜色取分割线那一档，停上去亮一档。
   只挂在 html.is-win 底下（aimy_base.html 开头按 User-Agent 挂的）：Mac 用的是系统
   的悬浮细条，本来就不露；而一旦给 ::-webkit-scrollbar 写了样式，悬浮条就变成常驻
   的，所以那边一条都不能碰。两种写法并列：`.is-win::-webkit-scrollbar` 是视口自己
   那一条（html 不是自己的后代），带空格那条是页面里每个能滚的块。
   老内核不认这些伪元素，整条丢掉就是它原来的样子，没有更坏。 */
.is-win::-webkit-scrollbar,
.is-win ::-webkit-scrollbar {
  width: 10px;
  height: 10px;
}
.is-win::-webkit-scrollbar-track,
.is-win ::-webkit-scrollbar-track,
.is-win::-webkit-scrollbar-corner,
.is-win ::-webkit-scrollbar-corner {
  background: transparent;
}
.is-win::-webkit-scrollbar-thumb,
.is-win ::-webkit-scrollbar-thumb {
  background: var(--line-strong);
  border-radius: 999px;
  /* 透明的边让滑块比轨道窄一圈、离内容留一线；background-clip 让底色不铺到边上。 */
  border: 3px solid transparent;
  background-clip: padding-box;
}
.is-win::-webkit-scrollbar-thumb:hover,
.is-win ::-webkit-scrollbar-thumb:hover {
  background: var(--muted);
  background-clip: padding-box;
}
.is-win::-webkit-scrollbar-button,
.is-win ::-webkit-scrollbar-button {
  width: 0;
  height: 0;
  display: none;
}
