/* wechat-typeset 工具外壳。
   设计系统：和 content-studio 工作台同一套语言（黑白两色 + 黑块 =「你在这儿」
   + 标记黄 =「我圈中的」 + 暖色只给内容 + 点阵母题 + `//` 眉标 + 思源黑体）。
   理念和每条规则的来由在 content-studio/workbench/docs/design-system.md，
   改样式前先读那份；本文件只记落地方式和 typeset 自己的例外。

   为什么要统一：typeset 已经被 iframe 嵌进工作台当「排版」页
   （workbench 的 server/routes/tools.mjs + pages/Typeset.jsx）。侧栏点进来
   之后字体一换、蓝色一冒出来，就是「跳进了另一个软件」——这不是审美偏好，
   是在修一处已经存在的接缝。

   三层 token，组件只准用「语义层」和「组件层」，不准直接用原始色阶：
     原始层  --ink-* / --line-* / --paper / --white / --sunken / --accent-*
             --mark-yellow / --emph / --band / --tidy(-on/-line/-del/-bar) / --ok / --warn / --danger
     语义层  --canvas / --surface / --border / --text-* / --ring ...
     组件层  --h-ctl / --r-ctl / --r-surface / --ease
   换主题只换原始层和少数几个语义值，组件样式一行都不用动。
   典型的兑现时刻就是这次换皮：语义层的名字一个没改，两千行组件规则原样留着。

   主题解析在 index.html 的 <head> 里同步完成，documentElement 上永远带着
   data-theme="light" 或 "dark"（已解析过的值，不会是 "system"），所以这里
   只需要一条 :root[data-theme="dark"] 覆盖，不需要再写 prefers-color-scheme。

   布局由 .main 上的 data-view 驱动：split / preview / style 三态，
   见下面「视图布局」一节。

   注意：本文件只管工具界面。预览内容的样式全部由 styles.js 写成内联 style，
   这里不得样式化 #preview-content 内部的裸标签，否则预览与复制结果会不一致。
   预览纸张 .paper 和它里面的公众号外壳（.wx-*）恒为白纸配色，用 --paper-*
   这组「不参与主题」的固定值，且外壳必须留在 #preview-content 外面。 */

/* ============================================================
   字体：本地副本，断网可用，不引任何 CDN

   三套，各管一件事（和工作台完全同款，两边并排看时字形一致）：
     Noto Sans SC   正文。用的是 chinese-simplified subset，它自带拉丁字形，
                    所以中英文都走它，不需要 unicode-range 分栈
     Space Grotesk  display 标题和眉标。只有拉丁字形，中文由栈里的 Noto 兜住
     JetBrains Mono 真·机读小字（字数、375px、路径）。同样只有拉丁字形

   ⚠️ 等宽栈里必须夹一层 Noto Sans SC，见下面 --font-mono 那条注释。

   ⚠️ **Geist Mono 还留着，别顺手删掉它的 @font-face。** 界面已经不用它了，
   但它是 styles.js 的 WCT_NUM_FONTS 里五种「大编号字体」之一，要拿来往
   canvas 上画数字。少了 @font-face 不会报任何错——ctx.font 会静静地回落到
   系统等宽字体，然后**把回落的字形烤进 PNG**，而那种错画进图之后就看不出来了。
   （Geist Sans 才是真的没人引用了，留在 vendor 里只是还没决定删不删。）
   ============================================================ */

@font-face {
  font-family: "Noto Sans SC";
  src: url("../vendor/fonts/NotoSansSC-400.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}

/* ⚠️ **500 和 600 共用一个文件，这是有意的，别再拆回两个。**
   一个中文字重就是 1.15MB，而思源黑体的 Medium 和 SemiBold 在 11–14px 的界面
   文字上肉眼分不出来——为这点差别多下一整份字库，在国内的网络条件下是净亏。
   `font-weight: 500 600` 是个区间，浏览器在整个区间里都用这一个文件，
   不会去合成假粗体（合成的中文假粗体很难看）。

   保留的是 **500（Medium）不是 600**：600 用在激活态（tab / pill / 磁贴 /
   主按钮），而那些本来就有实心黑块托底，字重是第二信号；500 用在静息态，
   保留它才守得住「收起态轻、展开态重」。反过来保留 600 会让整个界面变重一档，
   小字号的中文还会发糊。 */
@font-face {
  font-family: "Noto Sans SC";
  src: url("../vendor/fonts/NotoSansSC-500.woff2") format("woff2");
  font-weight: 500 600;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: "Space Grotesk";
  src: url("../vendor/fonts/SpaceGrotesk-500.woff2") format("woff2");
  font-weight: 500;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: "Space Grotesk";
  src: url("../vendor/fonts/SpaceGrotesk-700.woff2") format("woff2");
  font-weight: 700;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: "JetBrains Mono";
  src: url("../vendor/fonts/JetBrainsMono-400.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: "JetBrains Mono";
  src: url("../vendor/fonts/JetBrainsMono-500.woff2") format("woff2");
  font-weight: 500;
  font-style: normal;
  font-display: swap;
}

/* 不是界面字体：大编号那条轴的第五个选项，只用来往 canvas 上画数字。
   font-display 必须是 block —— 和 num/ 里那四个同理，
   字体没加载完就栅格化，烤进 PNG 的会是回退字体。 */
@font-face {
  font-family: "Geist Mono";
  src: url("../vendor/fonts/GeistMono-Variable.woff2") format("woff2");
  font-weight: 100 900;
  font-style: normal;
  font-display: block;
}

/* 大编号用的数字字体。全部裁到只剩 0-9，每个约 1.2KB。
   它们只在**作者这台机器上**用来把编号画进 canvas —— 产物是 PNG，
   所以读者手机上没有这些字体也照样显示。因此这里不需要考虑中文回退。 */

@font-face {
  font-family: "Questrial";
  src: url("../vendor/fonts/num/Questrial-digits.woff2") format("woff2");
  font-weight: 400;
  font-display: block;
}

@font-face {
  font-family: "Michroma";
  src: url("../vendor/fonts/num/Michroma-digits.woff2") format("woff2");
  font-weight: 400;
  font-display: block;
}

@font-face {
  font-family: "Afacad";
  src: url("../vendor/fonts/num/Afacad-digits.woff2") format("woff2");
  font-weight: 700;
  font-display: block;
}

@font-face {
  font-family: "Inter";
  src: url("../vendor/fonts/num/Inter-digits.woff2") format("woff2");
  font-weight: 700;
  font-display: block;
}

/* ============================================================
   Token：浅色
   ============================================================ */

:root {
  color-scheme: light;

  /* --- 原始层 --- */
  --paper: #fafafa;
  --white: #ffffff;
  --sunken: #f4f4f5;

  --ink-900: #0a0a0a;
  --ink-600: #52525b;
  /* 辅助灰。**这个值是量出来的，不是挑出来的。** 它管着提示、页脚、元信息、
     placeholder，也就是「除了正文之外你要读的所有字」；在三种底色上分别是
     5.05 / 5.27 / 4.79，全部过 WCAG AA，而灰的层次一点没丢。 */
  --ink-400: #6b6b75;

  --line-1: #ececee;
  --line-2: #dcdce0;

  /* 点缀色就是「纸的反面」——近黑，**没有第二个颜色**。彩色点缀会和内容里
     真正需要颜色的东西抢注意力；黑白只靠字重、留白和实心块分层次。
     当前视图、选中的样式、主按钮一律是**实心黑块**——黑白配色下淡色底几乎看不出来。 */
  --accent: #0a0a0a;
  --accent-strong: #000000;
  --accent-soft: #c4c4c8;
  --accent-wash: #f0f0f1;
  /* 实心黑块上的字色。暗色下 --accent 翻成近白，白字压上去就没了，必须单独有个 token。 */
  --on-accent: #ffffff;

  /* 「不引入第二个颜色」针对的是**装饰性**用色。下面三个是**功能色**，是有意的例外。 */

  /* 例外 1 · 标记黄：选区。它必须能压在任意文字上、一眼看见、又不盖掉底下的字。
     纯反白（黑底白字）试过，一整段变成一块黑砖，反而看不清选中的是什么。 */
  --mark-yellow: rgba(250, 204, 21, 0.34);

  /* 例外 2 · 正文的暖色强调。理由是**中文的加粗太弱**：字重 400→700 在中文字面上
     的差别远不如西文，一屏扫过去抓不住重点。
     ⚠️ 在 typeset 里它**只准出现在编辑区的语法着色上**——编辑区显示的是用户的正文，
     那是内容；工具外壳是骨架，骨架也染上同一个暖色，内容里的暖色就不再意味着
     「这里被强调了」。（工作台那边给元信息行上过暖色，做出来看图撤了。）
     --emph 在白底上是 3.1:1，这是**有意选的观感，不是疏忽**——觉得读着费劲先动它。 */
  --emph: #de7802;
  --band: rgba(244, 72, 64, 0.35);

  /* 例外 3 · 校对改过的地方。它和上面两个一样只出现在编辑区（那是内容），
     绿是因为它说的是「这儿已经改好了」——真要否掉的话点它就能改回。
     不能借 --mark-yellow：那是选区色，用户一拖选就分不清哪块是哪块了；
     也不能借 --band：那是标题底衬，同一屏里两种意思。
     ⚠️ **光靠底色不够。** 编辑区本来就有标题底衬和加粗暖色，再来一块彩色底
     等于三种意思挤在同一条视觉通道上，一篇长稿里那两三处改动根本找不着。
     所以标记额外画一条实心下划线（--tidy-line）——底衬是纯填充没有线，
     两者一眼分得开。 */
  --tidy: rgba(22, 163, 74, 0.22);
  --tidy-on: rgba(22, 163, 74, 0.46);
  --tidy-line: #16a34a;
  /* 气泡里「改之前」那一半。红绿对照是 diff 的通用语汇，用在一个专门用来
     比对两串字的气泡里最省解释成本。⚠️ 它**只出现在气泡里**——编辑区正文上
     不准出现红底，那会读成「这里有错」，而改动是已经改好的 */
  --tidy-del: rgba(220, 38, 38, 0.26);
  /* 审阅条整条的底。比标记淡一半：它是一整条 46px 的带子，
     用标记那个浓度会把下面的正文压住 */
  --tidy-bar: rgba(22, 163, 74, 0.1);

  --ok: #16a34a;
  --warn: #d97706;
  --danger: #dc2626;
  --danger-wash: #fef2f2;
  /* 只给「已复制 ✓」那一下和开关的勾。--ok 配白字只有 3.3:1，撑不住一整块实心底；
     这个值两套主题下都是 5.1:1，所以不跟着暗色翻。 */
  --ok-solid: #15803d;

  /* --- 语义层 --- */
  --canvas: var(--paper);
  --surface: var(--white);
  --surface-2: var(--sunken);
  --surface-sunken: var(--sunken);
  /* 预览区的「画布」：白纸浮在上面，所以要比纸明显深一档，
     否则浅色下纸和底同为近白，纸读不出是一个独立的东西，
     周围的留白就显得像是没排满，而不是画布 */
  --canvas-preview: #e8e8ea;

  --border: var(--line-1);
  --border-hover: var(--line-2);
  --border-strong: var(--accent-soft);
  --hairline: var(--line-1);

  /* hover / active 走 alpha 底，不换实色底——alpha 在浅暗两套下自动成立 */
  --hover-bg: rgba(10, 10, 10, 0.04);
  --active-bg: rgba(10, 10, 10, 0.07);

  /* 可读文字只有两档：text-1 主要、text-2 次要，层级靠字号和字重拉开。
     text-3 是量过的辅助灰（5:1 左右），给提示、页脚、元信息、placeholder，
     这些都是要真读进去的；text-4 只给 disabled。 */
  --text-1: var(--ink-900);
  --text-2: var(--ink-600);
  --text-3: var(--ink-400);
  --text-4: var(--accent-soft);

  --solid: var(--accent);
  --on-solid: var(--on-accent);

  /* 焦点环跟着点缀色走，不再是蓝的——界面上没有第二个颜色 */
  --ring: var(--accent);
  /* 选区是暖色蒙版，**字保持原色**，和编辑区里的标题底衬是同一套语言 */
  --select-bg: var(--mark-yellow);
  --scrim: rgba(0, 0, 0, 0.36);

  --danger-bg: var(--danger-wash);

  --shadow-card: 0 1px 2px rgba(10, 10, 10, 0.04);
  --shadow-pop: 0 8px 30px rgba(10, 10, 10, 0.06),
    0 1px 2px rgba(10, 10, 10, 0.04);
  --shadow-modal: 0 24px 60px rgba(10, 10, 10, 0.09),
    0 1px 2px rgba(10, 10, 10, 0.04);

  /* --- 编辑区语法着色 ---
     编辑区显示的是**用户的正文**，所以这里是全工具唯一一处「内容」——
     暖色强调只准出现在这儿（见 --emph 那条注释）。

     关键的一条：记号本身（`#` `**` `>` `-`）压到 text-3。记号和内容同色的话，
     一屏 Markdown 就是一堵字符墙，那正是纯 textarea 难看的根源。

     ⚠️ 镜像层只准改 color / background / text-decoration。工作台那边靠字号字重
     拉开标题层级，这里**照搬不了**——font-* 和 letter-spacing 会让镜像的字宽和
     textarea 里的真实文本对不上，光标当场漂移。所以标题改用工作台的另一条规则：
     一块贴着字的底衬（--band），背景不改变字体度量。 */
  --syn-mark: var(--text-3);
  --syn-h: var(--text-1);
  --syn-h-band: var(--band);
  --syn-quote: var(--text-2); /* 引用里的是正文，要读，不能用 disabled 那一档 */
  --syn-code: var(--text-2);
  --syn-strong: var(--emph);
  --syn-em: var(--text-2);
  --syn-link: var(--text-2);
  --syn-bullet: var(--text-3); /* 只作用于符号本身，不是正文 */
  --syn-table: var(--text-2);
  --syn-tidy: var(--tidy);           /* 校对改过的那一小段 */
  --syn-tidy-on: var(--tidy-on);     /* 当前正在看的那一处 */
  --syn-tidy-line: var(--tidy-line); /* 标记下面那条线 */

  /* --- 预览纸张：恒定值，不参与主题 --- */
  --paper-bg: #ffffff;
  --paper-border: rgba(0, 0, 0, 0.08);
  --paper-shadow: 0 1px 2px rgba(0, 0, 0, 0.04),
    0 8px 24px -12px rgba(0, 0, 0, 0.12);
  --wx-title: #1a1a1a;
  --wx-link: #576b95;
  --wx-meta: #9a9a9a;
  --wx-line: #ececec;

  /* --- 组件层 --- */
  --h-ctl: 34px;
  --h-ctl-lg: 40px;
  --r-ctl: 6px;
  --r-md: 11px;
  --r-surface: 14px;
  --r-lg: 22px;
  --r-full: 9999px;

  --font-sans: "Noto Sans SC", system-ui, -apple-system, "Segoe UI",
    "PingFang SC", "Microsoft YaHei", sans-serif;
  --font-display: "Space Grotesk", "Noto Sans SC", system-ui, sans-serif;
  /* ⚠️ **等宽栈里必须夹一层 Noto Sans SC。** JetBrains Mono 没有中文字形，
     套了等宽的中文会掉进系统默认字体（Windows 上是微软雅黑）——同一行里数字是
     JetBrains、汉字是雅黑，字重字宽全对不上。这是工作台那边栽过五六次才收敛出来的
     一条，别把它删掉。
     但这只是兜底：**内容是中文的地方仍然该用正文字体**，等宽只留给时间戳、
     路径、`375px` 这类真·机读信息。 */
  --font-mono: "JetBrains Mono", "Noto Sans SC", ui-monospace, Consolas,
    Menlo, monospace;

  --ease: cubic-bezier(0.22, 1, 0.36, 1);

  /* 编辑区：默认无衬线 + 不显示行号 + 固定 760px 栏宽。
     目标用户写中文文章，不写代码——等宽字体在中文下本来就是假的
     （汉字会 fallback 到非等宽字体），白白带来一身代码味。
     --edit-w 是分屏时编辑区那一栏的宽度，切设备时它不变。 */
  --font-editor: var(--font-sans);
  --size-editor: 15px;
  --gutter-w: 0px;
  --edit-w: 760px;
  --topbar-h: 52px;
}

body[data-edfont="mono"] {
  --font-editor: var(--font-mono);
  --size-editor: 13.5px;
}

body[data-gutter="on"] {
  --gutter-w: 46px;
}

body[data-width="wide"] {
  --edit-w: 1000px;
}

/* ============================================================
   Token：暗色（只覆盖原始层 + 少数语义值）
   ============================================================ */

:root[data-theme="dark"] {
  color-scheme: dark;

  --paper: #0d0d10;
  --white: #151518;
  --sunken: #1d1d22;

  --ink-900: #f4f4f5;
  --ink-600: #b4b4bd;
  /* **暗色要单独量**：同一个灰在深底上的对比度和在浅底上完全是两回事。
     #8e8e99 在三种底上是 5.29~5.99，浅色那个值搬过来只有 4.0 出头。 */
  --ink-400: #8e8e99;

  --line-1: #26262c;
  --line-2: #35353d;

  --accent: #f4f4f5;
  --accent-strong: #ffffff;
  --accent-soft: #4a4a52;
  --accent-wash: #26262c;
  --on-accent: #0d0d10;

  /* 蒙版要更透一点，否则压在深色文字上会糊成一团 */
  --mark-yellow: rgba(250, 204, 21, 0.26);
  /* 底衬取的是**浅粉**那一头：把浅色那个 rgba(244,72,64) 原样搬过来，
     在近黑底上会压成一块暗红。字色同理要往亮里翻，#de7802 在深底上偏闷。 */
  --band: rgba(251, 191, 188, 0.16);
  --emph: #f59a3c;
  /* 同理往亮里翻：深底上 rgba(22,163,74) 压出来是一块墨绿，看不出是标记 */
  --tidy: rgba(74, 222, 128, 0.2);
  --tidy-on: rgba(74, 222, 128, 0.42);
  --tidy-line: #4ade80;
  --tidy-del: rgba(248, 113, 113, 0.3);
  --tidy-bar: rgba(74, 222, 128, 0.1);

  --ok: #4ade80;
  --warn: #fbbf24;
  --danger: #f87171;
  --danger-wash: #2a1214;

  --hover-bg: rgba(255, 255, 255, 0.06);
  --active-bg: rgba(255, 255, 255, 0.10);

  /* 画布是最沉的一档，卡片面抬到 --white，层级靠色阶不靠阴影 */
  --canvas: var(--paper);
  --surface: var(--white);
  --surface-2: var(--sunken);
  --surface-sunken: var(--paper);
  --canvas-preview: #000000;

  --scrim: rgba(0, 0, 0, 0.62);

  /* 深底上文档给的阴影等于不存在，加深一档，层级仍主要靠边框 */
  --shadow-card: 0 1px 2px rgba(0, 0, 0, 0.4);
  --shadow-pop: 0 8px 30px rgba(0, 0, 0, 0.34), 0 1px 2px rgba(0, 0, 0, 0.4);
  --shadow-modal: 0 24px 60px rgba(0, 0, 0, 0.44), 0 1px 2px rgba(0, 0, 0, 0.4);

  /* 白纸浮在深底上：亮边勾轮廓 + 深阴影托住 */
  --paper-border: rgba(0, 0, 0, 0.2);
  --paper-shadow: 0 0 0 1px rgba(255, 255, 255, 0.07),
    0 16px 40px -12px rgba(0, 0, 0, 0.8);
}

/* ============================================================
   基础
   ============================================================ */

* {
  box-sizing: border-box;
}

html,
body {
  height: 100%;
  margin: 0;
}

body {
  font-family: var(--font-sans);
  font-size: 14px;
  color: var(--text-1);
  background: var(--canvas);
  display: flex;
  flex-direction: column;
  overflow: hidden;
  -webkit-font-smoothing: antialiased;
}

/* 选区要**看得见，但不能是块黑砖**。低饱和暖色蒙版，字保持原色。
   （`::selection` 只是浏览器画的 UI，不会进复制产物，所以给它开全局是安全的。） */
::selection {
  background: var(--select-bg);
  color: inherit;
}

/* 数字要对齐：步进器改值、字数增长时不能左右跳 */
.pane-foot b,
.stepper span,
.doc-row-meta,
.ml-n {
  font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum" 1;
}

/* 眉标：小灰字压在大黑字上面 = 层次。跟标题同色的话两行会互相抢。
   ⚠️ 它是**英文**小标题才成立（`// TYPESET`）——中文套等宽 + 大写字距只会
   把字距拉散，而 text-transform 对中文本来就是空操作。 */
.eyebrow {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-family: var(--font-mono);
  font-size: 10.5px;
  font-weight: 500;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--text-3);
}

.eyebrow::before {
  content: "//";
  color: var(--border-strong);
}

/* 真·机读小字：时间戳、路径、`375px`、字数。中文一律不进这里（见 --font-mono） */
.mono {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
}

kbd {
  display: inline-flex;
  align-items: center;
  height: 18px;
  padding: 0 5px;
  border: 1px solid var(--border);
  border-radius: 4px;
  background: var(--surface-2);
  color: var(--text-2);
  font-family: var(--font-sans);
  font-size: 11px;
  line-height: 1;
}

/* 焦点环：内圈用所在面的颜色垫出 2px 空隙，外圈才是 ring 色 */
.brand:focus-visible,
.btn:focus-visible,
.icon-btn:focus-visible,
.tb-btn:focus-visible,
.tab:focus-visible,
.pill:focus-visible,
.tile:focus-visible,
.color-chip:focus-visible,
.swatch-btn:focus-visible,
.swatch-input:focus-visible,
.seg button:focus-visible,
.stepper button:focus-visible,
.doc-trigger:focus-visible,
.doc-pick:focus-visible,
.doc-del:focus-visible,
.doc-menu-head button:focus-visible,
.menu-item:focus-visible,
.combo-act button:focus-visible,
.group-head:focus-visible,
.start-card:focus-visible,
.wx-profile:focus-visible,
.palette-item:focus-visible,
.gal-preview:focus-visible,
select:focus-visible,
/* 命令面板的搜索框除外：整个弹层就是焦点所在，再套一圈环反而像出错了 */
input[type="text"]:not(#palette-input):focus-visible {
  outline: none;
  box-shadow: 0 0 0 2px var(--surface), 0 0 0 4px var(--ring);
  z-index: 1;
  position: relative;
}

/* ============================================================
   顶栏：只留高频的三件事（切视图 / 调排版 / 复制），其余进 ⋯ 菜单
   ============================================================ */

.topbar {
  display: flex;
  align-items: center;
  gap: 12px;
  height: var(--topbar-h);
  padding: 0 12px 0 16px;
  border-bottom: 1px solid var(--border);
  background: var(--surface);
  flex-shrink: 0;
  z-index: 10;
}

/* 品牌区是个按钮：点它回到分屏视图。要清掉 button 的 UA 样式，
   并且给一层 hover 底——不给的话没人知道它能点 */
.brand {
  display: flex;
  align-items: center;
  gap: 9px;
  flex-shrink: 0;
  height: var(--h-ctl);
  padding: 0 8px 0 4px;
  margin-left: -4px;
  border: none;
  border-radius: var(--r-ctl);
  background: transparent;
  color: inherit;
  font-family: var(--font-sans);
  cursor: pointer;
  transition: background 150ms;
}

.brand:hover { background: var(--hover-bg); }
.brand:active { background: var(--active-bg); }

/* 顶栏放的是**横排字标**（大 T + ypeset），不是「图标 chip + 中文名」。
   它是填充图形不是线稿，靠 currentColor 跟着主题走：浅色下近黑、暗色下近白，
   所以不需要那块深色底 chip —— 字标自己就是 logo，再套一个黑方块是两层品牌。

   ⚠️ 高度写死、宽度 auto：viewBox 的宽高比是 1.813，给了宽度反而会把它压变形。
   28px 是量出来的下限 —— 这个字标里 T 占了六分之五的高度，「ypeset」本身很小，
   再矮一档那几个字母就糊了。 */
.brand-logo {
  height: 28px;
  width: auto;
  display: block;
  flex-shrink: 0;
  color: var(--text-1);
}

/* 保存状态：三档各有各的颜色，不是一个永远绿着的装饰点 */
.save-chip {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 12px;
  color: var(--text-2);
  white-space: nowrap;
}

.save-chip .dot {
  width: 6px;
  height: 6px;
  border-radius: var(--r-full);
  background: var(--text-4);
  flex-shrink: 0;
  transition: background 150ms;
}

.save-chip[data-state="saving"] .dot { background: var(--warn); }
.save-chip[data-state="saved"] .dot { background: var(--ok); }
.save-chip[data-state="error"] .dot { background: var(--danger); }
.save-chip[data-state="error"] { color: var(--danger); }

.topbar-spacer {
  flex: 1;
}

.toolbar {
  display: flex;
  align-items: center;
  gap: 4px;
}

/* ============================================================
   按钮：三级层级，一律药丸形

   主按钮是**实心黑块**——黑白配色下淡色底几乎看不出来，而「复制到公众号」
   是这一屏最该一眼看到的东西。
   ============================================================ */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  height: var(--h-ctl);
  padding: 0 14px;
  border: 1px solid transparent;
  border-radius: var(--r-full);
  font-family: var(--font-sans);
  font-size: 13px;
  font-weight: 500;
  line-height: 1;
  cursor: pointer;
  white-space: nowrap;
  text-decoration: none;
  transition: background 150ms, border-color 150ms, color 150ms;
}

/* ⚠️ `.btn` 自带 display:inline-flex，会盖掉 UA 的 `[hidden]`，必须显式写回来
   （跟 `.field[hidden]` / `.main[hidden]` 同一个坑，这已经是第三次踩了）。
   踩中的表现是「藏起来的按钮还在那儿」，而藏它的那行代码看着完全正确 */
.btn[hidden] { display: none; }

.btn-ghost {
  background: transparent;
  color: var(--text-2);
}

.btn-ghost:hover {
  background: var(--hover-bg);
  color: var(--text-1);
}

.btn-ghost:active { background: var(--active-bg); }

/* 排版模式开着时按钮要看得出是「按下去的」，不只是 hover 那一档 */
.btn.is-on {
  background: var(--active-bg);
  border-color: var(--border-strong);
  color: var(--text-1);
}

.btn-secondary {
  background: var(--surface);
  color: var(--text-1);
  border-color: var(--border);
}

.btn-secondary:hover {
  border-color: var(--border-hover);
  background: var(--hover-bg);
}

.btn-primary {
  background: var(--solid);
  color: var(--on-solid);
  border-color: var(--solid);
  font-weight: 600;
}

.btn-primary:hover {
  background: var(--accent-strong);
  border-color: var(--accent-strong);
}

/* 复制成功后按钮就地反馈，比底部提示离视线近 */
.btn-primary.is-done {
  background: var(--ok-solid);
  border-color: var(--ok-solid);
  color: #fff;
}

.btn-block {
  width: 100%;
  margin-top: 8px;
}

.icon-btn {
  display: flex;
  align-items: center;
  justify-content: center;
  width: var(--h-ctl);
  height: var(--h-ctl);
  padding: 0;
  border: 1px solid transparent;
  border-radius: var(--r-full);
  background: transparent;
  color: var(--text-3);
  cursor: pointer;
  flex-shrink: 0;
  transition: background 150ms, color 150ms;
}

.icon-btn:hover {
  background: var(--hover-bg);
  color: var(--text-1);
}

.icon-btn-sm {
  width: 28px;
  height: 28px;
}

/* ============================================================
   下拉菜单（⋯ / 草稿箱共用外观）
   ============================================================ */

.more-picker,
.doc-picker {
  position: relative;
  flex-shrink: 0;
}

.menu,
.doc-menu {
  position: absolute;
  top: calc(100% + 6px);
  min-width: 200px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-surface);
  box-shadow: var(--shadow-pop);
  z-index: 40;
  overflow: hidden;
}

.menu {
  right: 0;
  padding: 5px;
}

.menu[hidden],
.doc-menu[hidden] {
  display: none;
}

.menu-item {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  width: 100%;
  height: 32px;
  padding: 0 9px;
  border: none;
  border-radius: var(--r-ctl);
  background: transparent;
  color: var(--text-1);
  font-family: var(--font-sans);
  font-size: 13px;
  text-align: left;
  cursor: pointer;
  transition: background 150ms;
}

.menu-item:hover {
  background: var(--hover-bg);
}

.menu-val {
  color: var(--text-2);
  font-size: 12px;
}

.menu-sep {
  height: 1px;
  margin: 5px 4px;
  background: var(--hairline);
}

/* ============================================================
   常驻排版条
   高频微调横排在顶栏下面。⚠️ 这里曾经是个从顶栏垂下来的浮层，改成常驻
   是有原因的：浮层正好盖住预览的上半截，而调排版时最要紧的就是边调边看。
   条上这几项在排版面板里不再出现，一个东西只有一个地方能改。
   ============================================================ */

/* 排版条开着的时候它是实心黑块 —— 这套语言里「实心 = 你在这儿」，
   而且顶栏那三个描边按钮（校对 / 快调 / 排版）长得一模一样，
   不给快调一个明确的开关态就看不出它跟另外两个不是一回事。 */
#quick-btn { gap: 5px; }

#quick-btn[aria-expanded="true"] {
  background: var(--solid);
  color: var(--on-solid);
  border-color: var(--solid);
  font-weight: 600;
}

#quick-btn[aria-expanded="true"]:hover { background: var(--solid); }

/* 图标里那两个小圆是「挖空」的，底色一变就得跟着变，否则黑底上是白洞 */
#quick-btn[aria-expanded="true"] circle { fill: var(--solid); }

.btn-chev {
  opacity: 0.55;
  transition: transform 150ms var(--ease);
}

#quick-btn[aria-expanded="true"] .btn-chev {
  opacity: 0.8;
  transform: rotate(180deg);
}

/* 审阅期间「校对」也是实心黑块，同一条规则：实心 = 你在这儿。
   顶栏那三个描边按钮长得一模一样，不给开关态就看不出自己正在审阅。 */
#format-btn[aria-pressed="true"] {
  background: var(--solid);
  color: var(--on-solid);
  border-color: var(--solid);
  font-weight: 600;
}

#format-btn[aria-pressed="true"]:hover { background: var(--solid); }

/* 控件**均分整条宽度**，不是挤在左边。挤在左边时右侧空出一大片，看着像
   这条栏没写完；而且它和下面编辑区那条工具栏都变成「左上角一堆按钮」，
   两条横条读起来像一堵 90px 高的控件墙。铺开之后每一组各占一段，
   跟下面那条一眼就分得开。 */
.stylebar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  height: 46px;
  padding: 0 12px 0 16px;
  /* ⚠️ **压一档，不要跟顶栏一样白。** 顶栏和编辑区都是 --surface，这条也白的话
     三层叠在一起只剩两条发丝线，读不出这是一个独立的工具区。
     沉下来之后「白 / 灰 / 白」自然分层，一点颜色都不用加 —— 常驻外壳不能上色，
     那会破坏「不引入第二个颜色」（临时的审阅条才可以，见 .review-bar）。 */
  background: var(--surface-2);
  border-bottom: 1px solid var(--border);
  flex-shrink: 0;
  overflow-x: auto;
  scrollbar-width: none;
}

/* 窄屏放不下时退回左对齐 + 横向滚动：均分会把控件压成一团 */
@media (max-width: 1180px) {
  .stylebar { justify-content: flex-start; gap: 20px; }
}

.stylebar::-webkit-scrollbar { height: 0; }

body[data-stylebar="off"] .stylebar,
body[data-empty="1"] .stylebar { display: none; }

/* 组内挨着（18px），组与组之间由 space-between 拉开 */
.sb-group {
  display: flex;
  align-items: center;
  gap: 18px;
  flex-shrink: 0;
}

.sb-item {
  display: flex;
  align-items: center;
  gap: 7px;
  flex-shrink: 0;
}

/* 标签压到 text-3 小一号：九组「标签 + 控件」如果两半一样重，这条栏读起来
   就是十八个并列的东西。压下去之后一眼看到的是九个**控件**，标签退成注解 */
.sb-label {
  font-size: 11px;
  color: var(--text-3);
  white-space: nowrap;
}

.sb-item select {
  flex: none;
  max-width: none;
  min-width: 104px;
}



/* 排版条上只有一颗色点，点开才是色板（见下面 .accent-pop）。
   条上不摆方阵：12 个色块会把别的控件挤没 */
.sb-color {
  display: inline-flex;
  width: 26px;
  height: 26px;
  padding: 2px;
  border: 1px solid var(--border);
  border-radius: var(--r-full);
  background: var(--surface);
  cursor: pointer;
  flex-shrink: 0;
  transition: border-color 150ms;
}

.sb-color:hover,
.sb-color[aria-expanded="true"] { border-color: var(--border-strong); }

.sb-color-dot {
  width: 100%;
  height: 100%;
  border-radius: var(--r-full);
  background: var(--solid);
}

/* ==== 主题色色板 ====
   上一版这里只有一颗原生 <input type="color">：换一次颜色就要开一次系统
   取色面板、再从整个色域里找回上次那个色。而九成情况用户要的就是
   「上次那个」或者内置那几个——所以把这两件事摆到最前面，
   系统取色器退成方阵最后一格（它仍然在，只是不再是唯一入口）。

   挂在 body 上并 position:fixed，理由和 .tile-pop 一样：
   .stylebar 是 overflow-x:auto 的，挂在它内部会被裁掉 */
.accent-pop {
  position: fixed;
  z-index: 60;
  width: 216px;
  padding: 12px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-surface);
  box-shadow: var(--shadow-pop);
}

.accent-pop[hidden] { display: none; }

.accent-sec { margin-bottom: 12px; }

.accent-label {
  display: block;
  margin-bottom: 8px;
  font-size: 11px;
  color: var(--text-3);
}

.accent-grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 8px;
  justify-items: center;
}

/* ⚠️ 每个色块外面套一圈发丝环。没有它的话「墨黑」`#1a1a1a` 压在暗色面板上
   基本看不见，方阵第一格看着像是空的 */
.accent-grid .swatch-btn:not(.active) { box-shadow: 0 0 0 1px var(--border); }

/* 方阵最后一格「更多」：原生取色器，彩虹环表明它是整个色域而不是某个色 */
.swatch-more {
  display: inline-flex;
  width: 25px;
  height: 25px;
  padding: 2px;
  border-radius: var(--r-full);
  background: conic-gradient(#f43f5e, #f59e0b, #22c55e, #06b6d4,
    #6366f1, #d946ef, #f43f5e);
  cursor: pointer;
}

.swatch-more input[type="color"] {
  width: 100%;
  height: 100%;
  padding: 0;
  border: none;
  border-radius: var(--r-full);
  background: none;
  opacity: 0;
  cursor: pointer;
}

.accent-hex {
  display: flex;
  align-items: center;
  gap: 6px;
}

.accent-hash {
  font-family: var(--font-mono);
  font-size: 12px;
  color: var(--text-3);
}

#accent-hex {
  flex: 1;
  min-width: 0;
  height: var(--h-ctl);
  padding: 0 10px;
  font-family: var(--font-mono);
  font-size: 12px;
  color: var(--text-1);
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: var(--r-full);
}

#accent-hex:focus {
  outline: none;
  border-color: var(--border-strong);
  background: var(--surface);
}

#accent-ok { height: var(--h-ctl); padding: 0 14px; }

/* 显示当前值的按钮，点开才是磁贴方阵。做成按钮而不是原生 select，
   是因为「双色线」「水印编号」这类名字光看文字想不出来长什么样，图示不能丢 */
.sb-pick {
  display: inline-flex;
  align-items: center;
  justify-content: space-between;
  gap: 6px;
  min-width: 92px;
  height: var(--h-ctl);
  padding: 0 8px 0 10px;
  border: 1px solid var(--border);
  border-radius: var(--r-ctl);
  background: var(--surface);
  color: var(--text-1);
  font-family: var(--font-sans);
  font-size: 12px;
  cursor: pointer;
  flex-shrink: 0;
  transition: border-color 150ms, background 150ms;
}

.sb-pick:hover { border-color: var(--border-hover); }

.sb-pick[aria-expanded="true"] {
  border-color: var(--border-strong);
  background: var(--hover-bg);
}

.sb-pick svg { opacity: 0.5; flex: none; }

.tile-pop {
  position: fixed;
  z-index: 60;
  width: 306px;
  max-height: min(70vh, 520px);
  overflow-y: auto;
  padding: 10px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-surface);
  box-shadow: var(--shadow-pop);
}

.tile-pop[hidden] { display: none; }

.sb-toggle {
  display: grid;
  place-items: center;
  width: 26px;
  height: 26px;
  border: none;
  border-radius: var(--r-full);
  background: transparent;
  color: var(--text-3);
  cursor: pointer;
  flex-shrink: 0;
  transition: background 150ms, color 150ms;
}

.sb-toggle:hover {
  background: var(--hover-bg);
  color: var(--text-1);
}

/* ============================================================
   草稿箱下拉
   ============================================================ */

.doc-trigger {
  display: flex;
  align-items: center;
  gap: 5px;
  height: 28px;
  max-width: 240px;
  padding: 0 10px;
  border: 1px solid transparent;
  border-radius: var(--r-full);
  background: transparent;
  color: var(--text-1);
  font-family: var(--font-sans);
  font-size: 13px;
  font-weight: 500;
  cursor: pointer;
  transition: background 150ms, color 150ms;
}

.doc-trigger:hover { background: var(--hover-bg); }
.doc-trigger[aria-expanded="true"] { background: var(--active-bg); }

.doc-trigger > span {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.doc-trigger svg { color: var(--text-3); flex-shrink: 0; }

.doc-menu {
  left: 0;
  width: 288px;
  max-height: 400px;
  display: flex;
  flex-direction: column;
}

.doc-menu-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 10px 12px;
  font-size: 12px;
  font-weight: 600;
  color: var(--text-1);
  border-bottom: 1px solid var(--hairline);
}

.doc-menu-act {
  display: flex;
  gap: 4px;
}

.doc-menu-head button {
  height: 26px;
  padding: 0 8px;
  border: 1px solid var(--border);
  border-radius: var(--r-ctl);
  background: var(--surface);
  color: var(--text-2);
  font-family: var(--font-sans);
  font-size: 11px;
  font-weight: 500;
  cursor: pointer;
  transition: background 150ms, border-color 150ms, color 150ms;
}

.doc-menu-head button:hover {
  background: var(--hover-bg);
  border-color: var(--border-hover);
  color: var(--text-1);
}

#doc-list {
  overflow-y: auto;
  padding: 6px;
}

.doc-rename {
  margin-bottom: 6px;
  padding-bottom: 8px;
  border-bottom: 1px solid var(--hairline);
}

.doc-rename label {
  display: block;
  margin: 2px 2px 5px;
  font-size: 11px;
  color: var(--text-2);
}

.doc-rename input { width: 100%; }

.doc-row {
  display: flex;
  align-items: stretch;
  gap: 2px;
  border-radius: var(--r-ctl);
  margin-bottom: 2px;
}

.doc-row:hover { background: var(--hover-bg); }
.doc-row.active { background: var(--active-bg); }

.doc-pick {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 2px;
  padding: 7px 8px;
  border: none;
  border-radius: var(--r-ctl);
  background: transparent;
  font-family: var(--font-sans);
  text-align: left;
  cursor: pointer;
}

.doc-row-name {
  font-size: 12px;
  color: var(--text-2);
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.doc-row.active .doc-row-name {
  color: var(--text-1);
  font-weight: 600;
}

.doc-row-meta {
  font-size: 11px;
  color: var(--text-2);
}

.doc-del {
  width: 28px;
  border: none;
  border-radius: var(--r-ctl);
  background: transparent;
  color: var(--text-3);
  font-size: 15px;
  line-height: 1;
  cursor: pointer;
  transition: background 150ms, color 150ms;
}

.doc-del:hover {
  background: var(--danger-bg);
  color: var(--danger);
}

/* ============================================================
   视图布局：write / split / preview / style
   面板不再是常驻列，而是一个临时模式——进入它时让编辑区让位，
   因为调样式时你要看的是结果，不是 Markdown 源码。
   布局切换不做过渡动画：Geist 说「多数交互 0ms 最跟手」，
   而且省掉了「宽度还在动画时量到旧值」那一整类 bug。
   ============================================================ */

.main {
  flex: 1;
  display: flex;
  padding: 12px;
  min-height: 0;
}

/* .main 自带 display:flex，会盖掉 UA 的 [hidden]，必须显式写回来
   （跟 .field[hidden] 同一个坑） */
.main[hidden] { display: none; }

/* 起始页占满整屏，顶栏那一整条在没有文档时没有意义 */
body[data-empty="1"] .topbar { display: none; }

.pane,
.panel {
  display: flex;
  flex-direction: column;
  min-width: 0;
  min-height: 0;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-surface);
  box-shadow: var(--shadow-card);
  overflow: hidden;
}

/* 分屏时**编辑区是固定宽度**，预览吃掉剩下的全部——跟排版模式下
   右侧面板固定宽是同一个模型。换手机 / 平板 / 电脑时只有右边的纸在变，
   左边写字的地方纹丝不动，光标和折行位置不会跳。
   注意 flex-grow 千万别写成小于 1 的值：0.5 只会吃掉一半剩余空间，
   另一半就那么空着（排版模式右边那条死白就是这么来的）。 */
/* 预览的 flex-basis 必须是 0 而不是 auto：auto 会拿内容宽度当基准，
   于是收缩时把编辑区一起拽窄，编辑区就不再是「固定宽度」了。
   basis 0 之后编辑区只在整体空间不够（free space 为负）时才收缩。 */
.pane-editor { flex: 0 1 var(--edit-w); min-width: 360px; }
.pane-preview { flex: 1 1 0; min-width: 0; margin-left: 12px; }

.panel {
  flex: 0 0 380px;
  margin-left: 12px;
}

.main[data-view="preview"] .pane-editor,
.main[data-view="preview"] .panel,
.main[data-view="split"] .panel,
.main[data-view="style"] .pane-editor {
  display: none;
}

/* 没有编辑区的时候预览从最左边开始 */
.main[data-view="preview"] .pane-preview,
.main[data-view="style"] .pane-preview {
  margin-left: 0;
}

.pane-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  height: 44px;
  padding: 0 12px 0 16px;
  font-size: 12px;
  color: var(--text-2);
  border-bottom: 1px solid var(--hairline);
  flex-shrink: 0;
}

.pane-title {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 13px;
  font-weight: 600;
  letter-spacing: -0.26px;
  color: var(--text-1);
}

.pane-meta {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.pane-foot {
  display: flex;
  align-items: center;
  gap: 14px;
  height: 34px;
  padding: 0 16px;
  font-size: 12px;
  color: var(--text-2);
  border-top: 1px solid var(--hairline);
  background: var(--surface-2);
  flex-shrink: 0;
}

.pane-foot b {
  color: var(--text-1);
  font-weight: 600;
}

.foot-spacer { flex: 1; }

.foot-hint { color: var(--text-3); }

/* ============================================================
   编辑器快捷插入栏
   ============================================================ */

/* --- 编辑区的两个 buffer ---
   正文和固定结尾共用同一个编辑区，切一下换一份文本。放在编辑区自己的
   pane-head 里（跟预览那条头对称），因为它是「我在编辑哪一份」而不是排版设置。 */

.pane-editor .pane-head { padding-left: 12px; }

.buf-side {
  display: flex;
  align-items: center;
  gap: 10px;
}

/* 那个开关只跟固定结尾有关，编辑正文时不该在那儿占位置 */
body[data-buffer="body"] .buf-side[data-for="ending"] { display: none; }

.switch-sm { transform: scale(0.86); transform-origin: right center; }

/* 文字按钮：它是条退路，不是常用动作，所以不做成正经按钮去抢注意力 */
.buf-link {
  padding: 0;
  border: none;
  background: none;
  color: var(--text-3);
  font-family: var(--font-sans);
  font-size: 12px;
  cursor: pointer;
  text-decoration: underline;
  text-underline-offset: 3px;
  text-decoration-color: var(--border-strong);
  transition: color 150ms;
}

.buf-link:hover { color: var(--text-1); }

/* 工具栏和页脚跟正文对齐到同一根左边线 */
.md-toolbar,
.pane-editor .pane-foot {
  padding-left: calc(var(--gutter-w) + 20px);
  padding-right: 20px;
}

.md-toolbar {
  display: flex;
  align-items: center;
  gap: 1px;
  height: 44px;
  border-bottom: 1px solid var(--hairline);
  flex-shrink: 0;
  overflow-x: auto;
  scrollbar-width: none;
}

.md-toolbar::-webkit-scrollbar { height: 0; }

/* 统一一套线稿图标。以前字母（H2 / B / I）和中文（引用 / 列表 / 分割线）
   混排，两种视觉语言挤在一条窄栏里，扫一眼分不出哪个是哪个。 */
.tb-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 30px;
  height: 30px;
  padding: 0;
  border: 1px solid transparent;
  border-radius: var(--r-ctl);
  background: transparent;
  color: var(--text-2);
  cursor: pointer;
  flex-shrink: 0;
  transition: background 150ms, color 150ms;
}

.tb-btn svg {
  width: 16px;
  height: 16px;
  display: block;
}

.tb-btn:hover {
  background: var(--hover-bg);
  color: var(--text-1);
}

.tb-btn:active { background: var(--active-bg); }

.tb-sep {
  width: 1px;
  height: 16px;
  margin: 0 5px;
  background: var(--border);
  flex-shrink: 0;
}

/* 把清空推到最右边，跟插入类工具拉开距离。工具栏横向溢出时它会收成 0，
   那时按钮仍然排得下，只是不再靠右 */
.tb-spacer { flex: 1; min-width: 12px; }

/* 破坏性动作只在 hover 时才红：常态下它是工具栏里的一个普通图标，
   不该一直在那儿嚷嚷 */
.tb-danger:hover {
  background: var(--danger-wash);
  color: var(--danger);
}

/* ============================================================
   校对结果的审阅条
   校对是这个工具里唯一会改**用户原文**的功能，所以它必须留下出口。
   条只在审阅态出现，跟工具栏对齐到同一根左边线。
   ============================================================ */

/* ⚠️ **这条不能长得像工具栏。** 顶栏 / 排版条 / pane 头 / 工具栏 / 审阅条
   摞在一起有五条，全是白底 + 发丝线 + 小灰字的话，眼睛扫过去只看到
   「五条一样的东西」，哪一条都跳不出来。加深其中一条只会变成
   「六条里有一条更吵」——要靠**性质**分开，不是靠浓淡。

   审阅条是**临时状态**，不是常驻工具，所以它用审阅自己的颜色：浅绿底 +
   一条绿色左端。这同时把它和正文里那些绿色标记读成同一件事——
   在这之前，两者唯一的关联是左边那个 8px 小绿点，太弱了。 */
.review-bar {
  display: flex;
  align-items: center;
  gap: 10px;
  height: 40px;
  padding-left: calc(var(--gutter-w) + 20px);
  padding-right: 16px;
  border-bottom: 1px solid var(--syn-tidy);
  background: var(--tidy-bar);
  box-shadow: inset 3px 0 0 var(--syn-tidy-line);
  font-size: 12px;
  color: var(--text-2);
  flex-shrink: 0;
}

.review-bar[hidden] { display: none; }

/* 「N 处改动」是这条栏的主语，比旁边的分类明显重一档 */
.rv-sum {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font-size: 13px;
  color: var(--text-1);
  font-weight: 600;
  white-space: nowrap;
}

.rv-sum b {
  font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum" 1;
}

.rv-kinds {
  color: var(--text-3);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.rv-spacer { flex: 1; }

.rv-nav {
  display: grid;
  place-items: center;
  width: 26px;
  height: 26px;
  padding: 0;
  border: none;
  border-radius: var(--r-full);
  background: transparent;
  color: var(--text-2);
  cursor: pointer;
  flex-shrink: 0;
  transition: background 150ms, color 150ms;
}

.rv-nav:hover {
  background: var(--hover-bg);
  color: var(--text-1);
}

.rv-btn {
  height: 26px;
  padding: 0 12px;
  border: 1px solid var(--border);
  border-radius: var(--r-full);
  background: var(--surface);
  color: var(--text-2);
  font-family: var(--font-sans);
  font-size: 12px;
  cursor: pointer;
  white-space: nowrap;
  flex-shrink: 0;
  transition: border-color 150ms, background 150ms, color 150ms;
}

.rv-btn:hover {
  border-color: var(--border-hover);
  background: var(--hover-bg);
  color: var(--text-1);
}

.rv-btn[hidden] { display: none; }

/* 实心黑块 =「弄完了，从这儿出去」。审阅是个模式，模式必须有个明确的出口 */
.rv-done {
  border-color: var(--solid);
  background: var(--solid);
  color: var(--on-solid);
  font-weight: 500;
}

.rv-done:hover {
  border-color: var(--solid);
  background: var(--solid);
  color: var(--on-solid);
  opacity: 0.88;
}

/* 改过的地方：底色 + 一条实心下划线。
   ⚠️ 只准写 background / color / text-decoration：改字重 / 字号 / 字距会让
   镜像的字宽和 textarea 里的真实文本对不上，光标当场漂移。
   下划线走 text-decoration 而不是 border-bottom，就是为了守住这条线。 */
.rv-mark {
  background: var(--syn-tidy);
  border-radius: 2px;
  text-decoration: underline;
  text-decoration-color: var(--syn-tidy-line);
  text-decoration-thickness: 2px;
  text-underline-offset: 2px;
}

.rv-mark.is-on { background: var(--syn-tidy-on); }

/* 审阅是个模式：这时候唯一要紧的就是那几处改动，别的语法色一律让位。
   长稿里标题底衬和加粗暖色遍地都是，不压下去那两三处绿的根本找不着。
   只换两个 token 的值，组件规则一行不用动；退出审阅自动全恢复。 */
body[data-review="on"] {
  /* 换成中性底而不是 transparent：标题该还认得出是标题，只是别再抢颜色。
     借 --hover-bg 是因为它本来就是「浅暗两套都成立的一层极淡中性蒙版」 */
  --syn-h-band: var(--hover-bg);
  --syn-strong: var(--text-2);
}

/* 单处改动的气泡。挂在 body 上并 fixed：.editor-wrap 是滚动容器，
   挂里面会被裁掉。 */
.rv-pop {
  position: fixed;
  z-index: 60;
  width: 300px;
  padding: 12px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-surface);
  box-shadow: var(--shadow-pop);
}

.rv-pop[hidden] { display: none; }

.rv-pop-kind {
  font-size: 11px;
  color: var(--text-3);
  margin-bottom: 8px;
}

/* 上下两行摞着，不是左右并排：中文一行装不下多少字，横着放会两边都被截短 */
.rv-pop-diff {
  font-size: 13px;
  line-height: 1.9;
  margin-bottom: 12px;
  word-break: break-all;
}

.rv-old,
.rv-new {
  display: block;
  position: relative;
  padding-left: 16px;
}

/* 行首一个 − / + 记号。红绿之外再给一层非颜色的区分，色觉障碍下也读得出来 */
.rv-old::before,
.rv-new::before {
  position: absolute;
  left: 0;
  font-family: var(--font-mono);
  font-size: 11px;
}

.rv-old::before {
  content: "−";
  color: var(--danger);
}

.rv-new::before {
  content: "+";
  color: var(--ok-solid);
}

/* 上下文压灰、改动本身留原色：两行长得一样的话，用户还得自己找不同 */
.rv-ctx { color: var(--text-3); }

/* 红底 vs 绿底。**字保持原色**，颜色全交给底——红字压红底两边都吃亏，
   而这两行本来就是要读的。删除线是第三重记号 */
.rv-old .rv-hit {
  color: var(--text-1);
  background: var(--tidy-del);
  border-radius: 3px;
  text-decoration: line-through;
  text-decoration-color: var(--danger);
}

.rv-new .rv-hit {
  color: var(--text-1);
  background: var(--syn-tidy-on);
  border-radius: 3px;
}

/* 箭头竖着放在两行之间，占一行太浪费，所以缩成一个小记号 */
.rv-arrow {
  display: block;
  color: var(--text-3);
  font-size: 10px;
  line-height: 1.2;
  padding-left: 16px;
}

.rv-pop-act {
  display: flex;
  gap: 8px;
}

/* ============================================================
   编辑区
   透明 textarea 叠在着色镜像上。两者的字体度量、内边距、换行规则必须完全一致，
   否则光标会漂移 —— 所以 font 相关属性只写在下面这条共用规则里，
   两层共用 --font-editor / --size-editor，换字体时一起换。
   行号是镜像里每行的绝对定位子元素，天然跟着软换行走。
   ============================================================ */

.editor-wrap {
  position: relative;
  flex: 1;
  min-height: 0;
}

.gutter-bg {
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  width: var(--gutter-w);
  background: var(--surface-2);
  border-right: 1px solid var(--hairline);
  z-index: 0;
}

body[data-gutter="off"] .gutter-bg,
body[data-gutter="off"] .ml-n {
  display: none;
}

#editor,
#editor-mirror {
  position: absolute;
  inset: 0;
  margin: 0;
  padding: 24px 20px 56px calc(var(--gutter-w) + 20px);
  border: none;
  font-family: var(--font-editor);
  font-size: var(--size-editor);
  font-weight: 400;
  line-height: 1.85;
  letter-spacing: 0;
  white-space: pre-wrap;
  word-break: break-word;
  overflow-wrap: break-word;
  tab-size: 2;
  overflow-y: scroll;
  overflow-x: hidden;
}

#editor-mirror {
  color: var(--text-1);
  background: transparent;
  pointer-events: none;
  z-index: 1;
}

#editor {
  resize: none;
  outline: none;
  background: transparent;
  color: transparent;
  caret-color: var(--text-1);
  z-index: 2;
}

#editor::selection { background: var(--select-bg); }
#editor::placeholder { color: var(--text-3); }
#editor-mirror::-webkit-scrollbar-thumb { background: transparent; }

.ml {
  display: block;
  position: relative;
  min-height: 1.85em;
}

.ml-n {
  position: absolute;
  left: calc(-1 * var(--gutter-w) - 14px);
  width: var(--gutter-w);
  padding-right: 10px;
  text-align: right;
  color: var(--text-3);
  font-size: 12px;
  user-select: none;
}

/* Markdown 语法着色。
   ⚠️ **只准改 color / background / text-decoration。** 凡是会改变字宽或行高的
   属性（font-family / font-size / font-weight / letter-spacing）一律不准——
   镜像和 textarea 的字必须严丝合缝地叠在一起，差一点点光标就漂了。
   这三个属性都不参与文本度量，所以是安全的。

   标题靠一块**贴着字的底衬**（--syn-h-band）而不是字号字重区分：
   落点得在**扫的时候**看得见，而在这一层里唯一能用的手段就是背景。
   `#` 那个记号本身仍然退到 --syn-mark，只有标题的字带底衬。 */
.mk-mark { color: var(--syn-mark); }
.mk-h {
  color: var(--syn-h);
  background: var(--syn-h-band);
}
.mk-quote { color: var(--syn-quote); }
.mk-code,
.mk-codeblock { color: var(--syn-code); }
.mk-fence { color: var(--syn-mark); }
/* 加粗是这一层唯一的暖色，和工作台正文里看到的是同一个颜色——
   编辑和阅读长两样的话，人得在两套记号之间做一次翻译 */
.mk-strong { color: var(--syn-strong); }
.mk-em { color: var(--syn-em); }
.mk-del { color: var(--syn-mark); }
/* 链接 = 灰字 + 一条下划线。text-decoration 不改字宽，是这层能用的第三个手段 */
.mk-link {
  color: var(--syn-link);
  text-decoration: underline;
  text-decoration-color: var(--syn-mark);
  text-underline-offset: 3px;
}
.mk-url { color: var(--syn-mark); }
.mk-bullet { color: var(--syn-bullet); }
.mk-hr { color: var(--syn-bullet); }
.mk-table { color: var(--syn-table); }

/* ============================================================
   预览区
   ============================================================ */

.pane-preview { background: var(--canvas-preview); }

.pane-preview .pane-head {
  background: var(--surface);
}

#preview-scroll {
  flex: 1;
  overflow-y: auto;
  padding: 24px 20px 64px;
}

/* 白纸恒白：暗色下也不许变，所见即所得是这个工具的全部价值 */
.paper {
  max-width: 440px;
  margin: 0 auto;
  background: var(--paper-bg);
  border: 1px solid var(--paper-border);
  border-radius: 8px;
  box-shadow: var(--paper-shadow);
  padding: 26px 22px 20px;
}

.device-pick {
  display: flex;
  align-items: center;
  gap: 10px;
}

/* --- 公众号文章外壳 ---
   这些节点必须留在 #preview-content 外面：previewHtml() 只读
   #preview-content，所以它们天然进不了复制产物。配色也全用固定值，
   跟着 .paper 一起「不参与主题」。 */

.wx-head { margin-bottom: 22px; }

.wx-title {
  margin: 0 0 14px;
  font-size: 22px;
  font-weight: 600;
  line-height: 1.45;
  color: var(--wx-title);
  word-break: break-word;
}

.wx-byline {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-bottom: 7px;
}

.wx-profile {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 2px 4px;
  margin: -2px -4px;
  border: none;
  border-radius: 4px;
  background: transparent;
  cursor: pointer;
  font-family: inherit;
  transition: background 150ms;
}

.wx-profile:hover { background: rgba(0, 0, 0, 0.05); }

/* 默认号用自己的头像图，改过名就退回「名字首字 + 主题色」。
   ⚠️ 空的纯色方块读起来就是「图没加载出来」——这块外壳唯一的作用是让人相信
   「发出去就长这样」，一个像坏图的方块正好起反作用。改名之后用首字是因为
   真实头像不可能预填，而首字跟着名字自动变，用户一个字都不用多填。 */
.wx-avatar {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 20px;
  height: 20px;
  border-radius: 3px;
  /* ⚠️ 用 background-color 不用 background 简写：简写会把下面两条一起重置掉，
     头像图就退回 auto 尺寸 + 左上角对齐，20px 框里只剩原图左上角那块空白 */
  background-color: var(--wx-link);
  background-size: cover;
  background-position: center;
  color: #fff;
  font-size: 11px;
  font-style: normal; /* 它是 <i>，不加这条汉字会被斜体 */
  font-weight: 500;
  line-height: 1;
  flex-shrink: 0;
}

.wx-name {
  font-size: 13px;
  color: var(--wx-link);
  max-width: 180px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.wx-follow {
  font-size: 13px;
  color: var(--wx-link);
}

.wx-meta {
  display: flex;
  gap: 8px;
  font-size: 12px;
  color: var(--wx-meta);
}

.wx-foot {
  margin-top: 26px;
  padding-top: 12px;
  border-top: 1px solid var(--wx-line);
}

.wx-actions {
  display: flex;
  justify-content: flex-end;
  gap: 16px;
  font-size: 12px;
  color: var(--wx-meta);
}

.wx-head[hidden],
.wx-foot[hidden] { display: none; }

/* 公众号信息小弹层 */
.profile-pop {
  position: fixed;
  z-index: 45;
  width: 232px;
  padding: 12px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-surface);
  box-shadow: var(--shadow-pop);
}

.profile-pop[hidden] { display: none; }

.profile-field {
  display: block;
  margin-bottom: 12px;
}

.profile-field > span,
.profile-field-label {
  display: block;
  margin-bottom: 5px;
  font-size: 11px;
  color: var(--text-2);
}

.profile-field input { width: 100%; }

.profile-colors {
  display: grid;
  grid-template-columns: repeat(6, 1fr);
  gap: 6px;
}

.profile-colors[hidden] { display: none; }

/* 头像：预览本身就是按钮，点它换图。不做「预览 + 一个『上传』按钮」两件套——
   那张图就是最明确的点击目标，旁边再放一个按钮是把一件事说了两遍 */
.profile-avatar-row {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-bottom: 12px;
}

.profile-avatar {
  position: relative;
  width: 44px;
  height: 44px;
  padding: 0;
  border: 1px solid var(--border);
  border-radius: var(--r-ctl);
  background: var(--surface-2);
  cursor: pointer;
  overflow: hidden;
  flex: none;
}

.profile-avatar:hover { border-color: var(--border-strong); }

.profile-avatar-face {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: 100%;
  background-size: cover;
  background-position: center;
  color: #fff;
  font-size: 18px;
  font-weight: 500;
}

/* 「换图」压在图下沿，只在 hover 时露出来：常态下它挡着头像，
   而这块地方的第一要务是让人看清头像现在长什么样 */
.profile-avatar-hint {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  padding: 2px 0;
  background: rgba(0, 0, 0, 0.55);
  color: #fff;
  font-size: 10px;
  line-height: 1.4;
  text-align: center;
  opacity: 0;
  transition: opacity 150ms var(--ease);
}

.profile-avatar:hover .profile-avatar-hint,
.profile-avatar:focus-visible .profile-avatar-hint { opacity: 1; }

#profile-avatar-clear {
  height: 28px;
  padding: 0 10px;
  font-size: 12px;
}

/* ============================================================
   设置面板
   ============================================================ */

.tabs {
  display: flex;
  align-items: center;
  gap: 2px;
  padding: 0 8px 0 12px;
  border-bottom: 1px solid var(--hairline);
  flex-shrink: 0;
}

.tab {
  height: 44px;
  padding: 0 8px;
  border: none;
  background: transparent;
  color: var(--text-2);
  font-family: var(--font-sans);
  font-size: 13px;
  font-weight: 500;
  cursor: pointer;
  border-bottom: 2px solid transparent;
  margin-bottom: -1px;
  transition: color 150ms;
}

.tab:hover { color: var(--text-1); }

.tab.active {
  color: var(--text-1);
  font-weight: 600;
  border-bottom-color: var(--text-1);
}

.tabs-spacer { flex: 1; }

/* --- 分组 ---
   十几个分组全部收起时，这一列就是面板的全部内容，所以收起态必须
   **轻**：一行 38px，没有边框没有底，行与行之间靠 2px 间距分开。
   上一版每组画一条通栏分隔线 + 一枚 26px 圆形描边图标 + 46px 行高，
   十三行摞起来像一张手机设置页，而且每一行都在争夺注意力。

   展开的那一组才**重**：整块换成浅底 + 圆角，标题加粗——「我打开的是这一块」
   一眼就看得出来，不用去数哪个箭头是朝上的。 */

.panel-body {
  flex: 1;
  overflow-y: auto;
  padding: 10px 12px 24px;
}

.group {
  border-radius: var(--r-md);
  margin-bottom: 2px;
  transition: background 160ms var(--ease);
}

/* 浅底 + 一圈发丝边。只给浅底的话（#f4f4f5 压在 #fff 上）差别太小，
   隔着一屏看不出来是哪一组开着。边框用 inset 阴影不用 border：
   border 会把这一组撑高 2px，收起 / 展开时整列跟着跳 */
.group.open {
  background: var(--surface-2);
  box-shadow: inset 0 0 0 1px var(--hairline);
  margin: 6px 0;
  padding-bottom: 2px;
}

.group-head {
  display: flex;
  align-items: center;
  gap: 9px;
  width: 100%;
  height: 38px;
  padding: 0 10px;
  border: none;
  border-radius: var(--r-md);
  background: none;
  cursor: pointer;
  font-family: var(--font-sans);
  color: var(--text-3);
  transition: background 150ms;
}

.group:not(.open) .group-head:hover { background: var(--hover-bg); }

/* 裸线稿，不套圆圈：一列图标本来就够认了，十三个圆环只是十三圈多余的墨。
   收起来之后它仍然是这一组唯一的记号，所以不能省。 */
.group-icon {
  width: 17px;
  height: 17px;
  flex: none;
  display: grid;
  place-items: center;
  color: var(--text-3);
  transition: color 150ms;
}

.group-icon svg { width: 17px; height: 17px; display: block; }

.group-head:hover .group-title,
.group-head:hover .group-icon { color: var(--text-1); }

.group.open .group-icon { color: var(--text-1); }
.group.open .group-title { font-weight: 600; }

.group-head .chev {
  color: var(--text-3);
  transition: transform 160ms var(--ease);
}
.group.open .group-head .chev { transform: rotate(180deg); }

.group-body {
  display: none;
  padding: 2px 10px 12px;
}

.group.open > .group-body { display: block; }

/* margin-right:auto 把 chev 顶到最右——用 space-between 的话
   图标、标题、chev 三个会被平分开，图标就不再是「贴着标题的」 */
.group-title {
  margin: 0 auto 0 0;
  font-size: 13px;
  font-weight: 500;
  color: var(--text-1);
  letter-spacing: -0.2px;
}

/* 「编辑器与预览」装的是工具偏好，跟前面那些排版轴不是一类东西，
   前面用一条带小字的分隔把它划出去。分隔是个独立元素而不是 .group 的
   ::before：展开时 .group 有底色，伪元素会被那块底色一起罩住 */
.panel-divider {
  margin: 20px 0 8px;
  padding: 12px 10px 0;
  border-top: 1px solid var(--hairline);
  font-size: 11px;
  color: var(--text-3);
}

.group-hint {
  margin: 0 0 10px;
  font-size: 11px;
  line-height: 1.6;
  color: var(--text-2);
}

.group-sub {
  margin: 14px 0 6px;
  font-size: 11px;
  font-weight: 500;
  color: var(--text-2);
}

.group-sub small {
  margin-left: 6px;
  font-weight: 400;
  color: var(--text-3);
}

/* --- 主题风格胶囊 --- */

.pill-row {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(64px, 1fr));
  gap: 6px;
}

.pill {
  height: var(--h-ctl);
  padding: 0 8px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  border: 1px solid var(--border);
  border-radius: var(--r-full);
  background: var(--surface);
  color: var(--text-2);
  font-family: var(--font-sans);
  font-size: 12px;
  cursor: pointer;
  transition: background 150ms, border-color 150ms, color 150ms;
}

.pill:hover {
  border-color: var(--border-hover);
  background: var(--hover-bg);
  color: var(--text-1);
}

/* 内置风格排在自己的搭配后面，用虚线边框弱化一档，一眼能分出哪些是自己存的 */
.pill-builtin {
  border-style: dashed;
  color: var(--text-2);
}

.pill.active {
  background: var(--accent);
  border-color: var(--accent);
  border-style: solid;
  color: var(--on-accent);
  font-weight: 600;
}

/* --- 色板 --- */

/* 11 个颜色 + 自定义 = 12 格，6×2 排满。加减颜色时要凑够 12 的因数，
   否则末尾会空出一格，看着像少画了一个颜色 */
.color-row {
  display: grid;
  grid-template-columns: repeat(6, 1fr);
  gap: 6px;
  justify-items: center;
}

.swatch-btn {
  width: 25px;
  height: 25px;
  border-radius: var(--r-full);
  border: 2px solid transparent;
  padding: 0;
  cursor: pointer;
  position: relative;
  background-clip: content-box;
  transition: transform 150ms var(--ease);
}

/* 「自动」有一半是留白，加一圈内描边才看得出边界 */
.swatch-btn.auto { box-shadow: inset 0 0 0 1px var(--border-strong); }

.swatch-btn:hover { transform: scale(1.08); }

.swatch-btn.active {
  border-color: var(--text-1);
  box-shadow: inset 0 0 0 2px var(--surface);
}

.swatch-btn.active::after {
  content: "";
  position: absolute;
  left: 6.5px;
  top: 3.5px;
  width: 5px;
  height: 9px;
  border: solid #fff;
  border-width: 0 2px 2px 0;
  transform: rotate(42deg);
}

.swatch-custom {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 25px;
  height: 25px;
  border-radius: var(--r-full);
  padding: 2px;
  background: conic-gradient(#c0342b, #c2603c, #b8860b, #0f7b46,
      #0e8f86, #2563eb, #7c3aed, #c0342b);
  cursor: pointer;
  flex-shrink: 0;
}

.swatch-custom.active { box-shadow: 0 0 0 2px var(--text-1); }

.swatch-input {
  width: 100%;
  height: 100%;
  padding: 0;
  border: none;
  border-radius: var(--r-full);
  background: none;
  cursor: pointer;
  overflow: hidden;
}

.swatch-input::-webkit-color-swatch-wrapper { padding: 0; }
.swatch-input::-webkit-color-swatch { border: 1px solid var(--surface); border-radius: var(--r-full); }
.swatch-input::-moz-color-swatch { border: 1px solid var(--surface); border-radius: var(--r-full); }

.color-chip {
  display: flex;
  align-items: center;
  gap: 7px;
  height: var(--h-ctl);
  padding: 0 12px;
  border: 1px solid var(--border);
  border-radius: var(--r-full);
  background: var(--surface);
  color: var(--text-2);
  font-family: var(--font-sans);
  font-size: 12px;
  cursor: pointer;
  transition: border-color 150ms, background 150ms, color 150ms;
}

.color-chip:hover {
  border-color: var(--border-hover);
  background: var(--hover-bg);
  color: var(--text-1);
}

.chip-dot {
  width: 14px;
  height: 14px;
  border-radius: var(--r-full);
  box-shadow: inset 0 0 0 1px var(--border-strong);
  flex-shrink: 0;
}

.color-pop {
  position: absolute;
  z-index: 20;
  padding: 8px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-surface);
  box-shadow: var(--shadow-pop);
}

.color-pop[hidden] { display: none; }

.color-pop-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 7px;
}

.color-pop-custom {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-top: 8px;
  padding-top: 8px;
  border-top: 1px solid var(--hairline);
  font-size: 11px;
  color: var(--text-2);
  cursor: pointer;
}

/* --- 样式磁贴 --- */

.tile-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 6px;
}

.tile-grid.cols-2 { grid-template-columns: repeat(2, 1fr); }
.tile-grid + .field { margin-top: 12px; }

.tile {
  padding: 6px 5px 7px;
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  background: var(--surface);
  cursor: pointer;
  transition: border-color 150ms, background 150ms;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
}

.tile:hover {
  border-color: var(--border-hover);
  background: var(--hover-bg);
}

/* 选中的磁贴用一圈**黑框**（边 + inset 各 1px 才够实），底保持面色——
   图示画的是白纸上的效果，底一暗就看不清它到底长什么样了 */
.tile.active {
  border-color: var(--text-1);
  background: var(--surface);
  box-shadow: inset 0 0 0 1px var(--text-1);
}

/* 图示画的是白纸上的效果（近黑标题、浅灰正文线），所以底永远是白纸。
   暗色下这块就成了一张小纸样张，如实反映渲染结果。
   浅色下白纸压在白面板上，要一道极淡的边才看得出是「一张纸」；
   暗色下白块本身就跟深色磁贴拉满对比，这道半透明白的边自然消失。 */
.tile-art {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: 32px;
  border-radius: 6px;
  background: var(--paper-bg);
  box-shadow: inset 0 0 0 1px var(--hairline);
}

.tile svg { display: block; }

.tile-name {
  font-size: 11px;
  color: var(--text-2);
  white-space: nowrap;
}

.tile.active .tile-name {
  color: var(--text-1);
  font-weight: 600;
}

/* --- 字段行 --- */

.field {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  margin-bottom: 8px;
}

/* .field 自带 display:flex，会盖掉 UA 的 [hidden]，必须显式写回来 */
.field[hidden] { display: none; }

.field-label {
  font-size: 12px;
  color: var(--text-2);
  white-space: nowrap;
}

.heading-level-field {
  min-height: 38px;
  padding: 4px 0 8px;
  border-bottom: 1px solid var(--hairline);
}

.heading-level-field .field-label {
  line-height: var(--h-ctl);
}

.heading-level-field .field-label b {
  display: inline-block;
  min-width: 22px;
  color: var(--text-1);
  font-size: 11px;
  letter-spacing: 0.04em;
}

.heading-level-controls {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 7px;
  min-width: 0;
}

.heading-level-pick { min-width: 88px; }
.heading-level-controls .seg button { padding: 0 9px; }

select,
input[type="text"] {
  height: var(--h-ctl);
  padding: 0 8px;
  border: 1px solid var(--border);
  border-radius: var(--r-ctl);
  background: var(--surface);
  color: var(--text-1);
  font-family: var(--font-sans);
  font-size: 12px;
  min-width: 0;
  transition: border-color 150ms;
}

select:hover,
input[type="text"]:hover { border-color: var(--border-hover); }
input[type="text"]::placeholder { color: var(--text-3); }

select {
  cursor: pointer;
  flex: 1;
  max-width: 172px;
}

/* --- 固定结尾 --- */

/* 用正文字体不用等宽：写的是几句中文，不是代码 */
.ending-md {
  display: block;
  width: 100%;
  margin: 4px 0 8px;
  padding: 9px 10px;
  border: 1px solid var(--border);
  border-radius: var(--r-ctl);
  background: var(--surface);
  color: var(--text-1);
  font-family: var(--font-sans);
  font-size: 12px;
  line-height: 1.7;
  resize: vertical;
  transition: border-color 150ms;
}

.ending-md:hover { border-color: var(--border-hover); }

.ending-md:focus {
  outline: none;
  border-color: var(--border-strong);
}

.ending-md::placeholder { color: var(--text-3); }

.ending-foot {
  display: flex;
  justify-content: space-between;
  gap: 10px;
  margin-bottom: 0;
}

/* --- 步进器 --- */

.stepper {
  display: flex;
  align-items: center;
  border: 1px solid var(--border);
  border-radius: var(--r-ctl);
  overflow: hidden;
  height: var(--h-ctl);
  background: var(--surface);
}

.stepper button {
  width: 30px;
  height: 100%;
  border: none;
  background: transparent;
  color: var(--text-2);
  font-family: var(--font-sans);
  font-size: 13px;
  cursor: pointer;
  transition: background 150ms, color 150ms;
}

.stepper button:hover:not(:disabled) {
  background: var(--hover-bg);
  color: var(--text-1);
}

.stepper button:disabled {
  color: var(--text-4);
  cursor: not-allowed;
}

.stepper span {
  min-width: 48px;
  text-align: center;
  font-size: 12px;
  color: var(--text-1);
  border-left: 1px solid var(--border);
  border-right: 1px solid var(--border);
  line-height: 30px;
}

/* --- 分段控件 --- */

.seg {
  display: flex;
  align-items: center;
  gap: 3px;
  padding: 3px;
  border-radius: var(--r-full);
  background: var(--surface);
  box-shadow: inset 0 0 0 1px var(--border), var(--shadow-card);
  height: var(--h-ctl);
}

.seg button {
  height: 100%;
  padding: 0 12px;
  border: none;
  border-radius: var(--r-full);
  background: transparent;
  color: var(--text-2);
  font-family: var(--font-sans);
  font-size: 12px;
  cursor: pointer;
  white-space: nowrap;
  transition: background 150ms, color 150ms;
}

.seg button:hover { color: var(--text-1); }

.seg button:disabled {
  color: var(--text-4);
  cursor: not-allowed;
  opacity: 0.45;
}

.seg button:disabled:hover { color: var(--text-4); }

/* **选中格是实心黑块。** 这个工具里每一组 .seg 都是互斥的「我现在在哪一档」
   ——视图、预览设备、对齐、提示块配色、编辑区字体，全是位置。位置一律用黑块，
   这是整套语言里最强的一个记号。
   上一版是「浅底 + 一点阴影浮起来」，黑白配色下弱到几乎看不出哪个被选中了。 */
.seg button.active {
  background: var(--accent);
  color: var(--on-accent);
  font-weight: 600;
}

.seg-mini { height: 28px; padding: 2px; }
.seg-mini button { padding: 0 11px; font-size: 11px; }

/* 顶栏的视图切换 */
.seg-view { flex-shrink: 0; }
.seg-view button { padding: 0 12px; font-size: 12.5px; }

/* --- 开关 --- */

.switch-row {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 12px;
  padding: 6px 0;
  cursor: pointer;
}

.switch-row > span:first-child {
  font-size: 12px;
  color: var(--text-1);
}

.switch-row small {
  display: block;
  margin-top: 3px;
  font-size: 11px;
  line-height: 1.6;
  color: var(--text-2);
}

.switch {
  position: relative;
  display: inline-block;
  width: 32px;
  height: 18px;
  flex-shrink: 0;
  margin-top: 1px;
}

.switch input { opacity: 0; width: 0; height: 0; }

.switch-track {
  position: absolute;
  inset: 0;
  border-radius: var(--r-full);
  background: var(--border-strong);
  transition: background 150ms;
  cursor: pointer;
}

.switch-track::after {
  content: "";
  position: absolute;
  top: 2px;
  left: 2px;
  width: 14px;
  height: 14px;
  border-radius: var(--r-full);
  background: #fff;
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.25);
  transition: transform 150ms var(--ease);
}

.switch input:checked + .switch-track { background: var(--solid); }

.switch input:checked + .switch-track::after {
  transform: translateX(14px);
  background: var(--on-solid);
}

.switch input:focus-visible + .switch-track {
  box-shadow: 0 0 0 2px var(--surface), 0 0 0 4px var(--ring);
}

/* ============================================================
   我的搭配
   ============================================================ */

.panel-body > .group > .group-title {
  display: block;
  padding: 14px 2px 8px;
}

.save-row { display: flex; gap: 6px; }
.save-row input { flex: 1; }

.combo {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 10px;
  border: 1px solid var(--border);
  border-radius: var(--r-ctl);
  margin-bottom: 6px;
  background: var(--surface);
  transition: border-color 150ms;
}

.combo:hover { border-color: var(--border-hover); }

.combo-dot {
  width: 14px;
  height: 14px;
  border-radius: var(--r-full);
  box-shadow: inset 0 0 0 1px var(--border-strong);
  flex-shrink: 0;
}

.combo-info { flex: 1; min-width: 0; }

.combo-name {
  display: block;
  font-size: 12px;
  font-weight: 500;
  color: var(--text-1);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.combo-desc {
  display: block;
  font-size: 11px;
  color: var(--text-2);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.combo-act { display: flex; gap: 4px; flex-shrink: 0; }

.combo-act button {
  height: 26px;
  padding: 0 8px;
  border: 1px solid var(--border);
  border-radius: var(--r-ctl);
  background: var(--surface);
  color: var(--text-2);
  font-family: var(--font-sans);
  font-size: 11px;
  cursor: pointer;
  transition: background 150ms, border-color 150ms, color 150ms;
}

.combo-act button:hover {
  background: var(--hover-bg);
  border-color: var(--border-hover);
  color: var(--text-1);
}

/* 空态指向第一个动作，而不是留一片空白 */
.empty {
  font-size: 12px;
  line-height: 1.7;
  color: var(--text-2);
  padding: 16px 0;
}

.empty-act {
  display: inline-flex;
  align-items: center;
  height: 28px;
  margin-top: 8px;
  padding: 0 10px;
  border: 1px solid var(--border);
  border-radius: var(--r-ctl);
  background: var(--surface);
  color: var(--text-1);
  font-family: var(--font-sans);
  font-size: 12px;
  font-weight: 500;
  cursor: pointer;
  transition: background 150ms, border-color 150ms;
}

.empty-act:hover {
  background: var(--hover-bg);
  border-color: var(--border-hover);
}

/* ============================================================
   起始页：没有草稿时代替主区，指向第一个动作
   ============================================================ */

.start {
  position: relative;
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px;
  min-height: 0;
  overflow-y: auto;
}

/* 点阵母题：极轻，只在右上角一片。它不承担信息，只是让大片留白
   不显得是「没做完」。
   ⚠️ **只放这一屏。** 其余三个视图（分屏 / 预览 / 排版）里画布只在边缘露 12px，
   铺上去等于看不见——为母题而母题不如不放。 */
.start::before {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  background-image: radial-gradient(var(--border-strong) 1px, transparent 1px);
  background-size: 26px 26px;
  opacity: 0.4;
  mask-image: radial-gradient(circle at 82% 6%, #000 0%, transparent 56%);
  -webkit-mask-image: radial-gradient(circle at 82% 6%, #000 0%, transparent 56%);
}

.start[hidden] { display: none; }

/* 左对齐，不居中：眉标 + 大标题 + 说明这个开场是靠**同一条左边线**站住的，
   居中之后三行各自的起点都不一样，眼睛要重新找落点 */
.start-inner {
  position: relative;
  width: 100%;
  max-width: 560px;
  text-align: left;
}

/* display:flex 而不是 inline-flex：inline 的话它会和下面那行眉标挤在同一行，
   `//` 正好贴在图标右边，看着像图标的一部分 */
.start-mark {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  margin-bottom: 22px;
  border-radius: var(--r-md);
  background: var(--accent);
  color: var(--on-accent);
}

.start-mark .mark { width: 28px; height: 28px; display: block; }

.start-eyebrow { margin-bottom: 10px; }

/* 中文标题的字号上限要比英文低：中文动辄十几个字，西文那套 clamp
   在这儿会占满两三行，把卡片推到折叠线以下 */
.start-title {
  margin: 0 0 12px;
  font-family: var(--font-display);
  font-size: 32px;
  font-weight: 700;
  letter-spacing: -0.03em;
  line-height: 1.25;
  color: var(--text-1);
}

/* 不另设 max-width，跟着 .start-inner 的 560px 走：再窄一点这句话就会
   在「丢。」两个字上折行，一个孤零零的句号挂在第二行比长一点更难看 */
.start-desc {
  margin: 0 0 32px;
  font-size: 14px;
  line-height: 1.75;
  color: var(--text-2);
}

.start-cards {
  display: grid;
  gap: 8px;
  text-align: left;
}

.start-card {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 3px;
  text-align: left; /* button 的 UA 样式是居中，要显式压回来 */
  padding: 15px 18px;
  border: 1px solid var(--border);
  border-radius: var(--r-surface);
  background: var(--surface);
  cursor: pointer;
  font-family: var(--font-sans);
  box-shadow: var(--shadow-card);
  transition: border-color 150ms, background 150ms;
}

/* hover 走**边框阶梯**加一层 alpha 底，不换实色底——
   alpha 在浅暗两套下自动成立，实色底不会 */
.start-card:hover {
  border-color: var(--border-strong);
  background: var(--hover-bg);
}

.start-card-title {
  font-size: 14px;
  font-weight: 600;
  color: var(--text-1);
}

.start-card-desc {
  font-size: 12.5px;
  color: var(--text-2);
}

/* ============================================================
   命令面板
   ============================================================ */

.palette-wrap {
  position: fixed;
  inset: 0;
  z-index: 60;
  display: flex;
  align-items: flex-start;
  justify-content: center;
  padding: 12vh 16px 16px;
}

.palette-wrap[hidden] { display: none; }

.palette-scrim {
  position: absolute;
  inset: 0;
  background: var(--scrim);
}

.palette {
  position: relative;
  display: flex;
  flex-direction: column;
  width: min(560px, 100%);
  max-height: 64vh;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-surface);
  box-shadow: var(--shadow-modal);
  overflow: hidden;
}

.palette-top {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 0 14px;
  height: 50px;
  border-bottom: 1px solid var(--hairline);
  color: var(--text-3);
  flex-shrink: 0;
}

#palette-input {
  flex: 1;
  height: 100%;
  padding: 0;
  border: none;
  background: transparent;
  color: var(--text-1);
  font-family: var(--font-sans);
  font-size: 15px;
  outline: none;
}

#palette-input::placeholder { color: var(--text-3); }

.palette-list {
  flex: 1;
  overflow-y: auto;
  padding: 6px;
}

.palette-group {
  padding: 10px 10px 4px;
  font-size: 11px;
  font-weight: 500;
  color: var(--text-2);
}

.palette-item {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  padding: 8px 10px;
  border: none;
  border-radius: var(--r-ctl);
  background: transparent;
  color: var(--text-1);
  font-family: var(--font-sans);
  font-size: 13px;
  text-align: left;
  cursor: pointer;
}

.palette-item.sel { background: var(--hover-bg); }

.palette-item-name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.palette-item-hint {
  font-size: 11px;
  color: var(--text-2);
  flex-shrink: 0;
}

.palette-foot {
  display: flex;
  gap: 16px;
  padding: 8px 14px;
  border-top: 1px solid var(--hairline);
  background: var(--surface-2);
  font-size: 11px;
  color: var(--text-2);
  flex-shrink: 0;
}

.palette-foot span {
  display: inline-flex;
  align-items: center;
  gap: 4px;
}

/* ============================================================
   图片拼贴面板
   预览这一层是工具界面，不进复制产物，所以可以放心用 object-fit /
   aspect-ratio 这类现代 CSS——真正插入时走的是 canvas 裁切，两边构图一致。
   ============================================================ */

.gal-wrap {
  position: fixed;
  inset: 0;
  z-index: 60;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px;
}

.gal-wrap[hidden] { display: none; }

.gal {
  position: relative;
  display: flex;
  flex-direction: column;
  width: min(760px, 100%);
  max-height: 86vh;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-surface);
  box-shadow: var(--shadow-modal);
  overflow: hidden;
}

.gal-head {
  padding: 16px 20px 12px;
  border-bottom: 1px solid var(--hairline);
}

.gal-head b { display: block; font-size: 15px; font-weight: 600; }

.gal-hint {
  display: block;
  margin-top: 3px;
  font-size: 12px;
  color: var(--text-2);
}

.gal-body {
  flex: 1;
  min-height: 0;
  display: grid;
  grid-template-columns: 232px 1fr;
  gap: 20px;
  padding: 18px 20px;
  overflow-y: auto;
}

.gal-form .field { margin-bottom: 12px; }
.gal-form .field[hidden] { display: none; }
.gal-form .group-hint { margin: 0; }

/* 预览：白纸底，模拟公众号正文那张纸 */
.gal-preview {
  background: var(--paper-bg);
  box-shadow: inset 0 0 0 1px var(--hairline);
  border-radius: 8px;
  padding: 12px;
  align-self: start;
  font-size: 0;
}

.gal-preview[data-layout="grid"] {
  display: grid;
  grid-template-columns: repeat(var(--gal-cols, 2), 1fr);
}

.gal-preview[data-layout="collage"] {
  display: grid;
  grid-template-columns: 2fr 1fr;
  align-items: start;
}

.gal-col { display: block; }

.gal-cell {
  position: relative;
  overflow: hidden;
  background: var(--surface-2);
}

.gal-cell img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

/* 竖排没有裁切，用原始比例 */
.gal-preview[data-layout="column"] .gal-cell img { height: auto; }

.gal-foot {
  display: flex;
  justify-content: flex-end;
  gap: 8px;
  padding: 12px 20px;
  border-top: 1px solid var(--hairline);
  background: var(--surface-2);
}

/* ============================================================
   复制成功后的收尾卡片：告诉用户下一步去哪，别断在 toast
   ============================================================ */

/* 有本地图片时这张卡片会说一整段「怎么逐张粘图」，所以按多行排：
   顶对齐 + 勾和按钮都不许被压扁 */
.copy-card {
  position: fixed;
  right: 16px;
  bottom: 16px;
  z-index: 50;
  display: flex;
  align-items: flex-start;
  gap: 12px;
  max-width: min(440px, calc(100vw - 32px));
  padding: 12px 12px 12px 14px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-surface);
  box-shadow: var(--shadow-modal);
  transform: translateY(8px);
  opacity: 0;
  transition: opacity 200ms, transform 200ms var(--ease);
}

.copy-card[hidden] { display: none; }
.copy-card.show { opacity: 1; transform: translateY(0); }

.copy-card-tick {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 24px;
  height: 24px;
  border-radius: var(--r-full);
  background: var(--ok-solid);
  color: #fff;
  flex-shrink: 0;
}

.copy-card-text {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}

.copy-card-text b {
  font-size: 13px;
  font-weight: 600;
  color: var(--text-1);
}

.copy-card-text small {
  font-size: 12px;
  line-height: 1.55;
  color: var(--text-2);
}

#copy-card-link { flex-shrink: 0; }

/* ============================================================
   Toast
   ============================================================ */

.toast {
  position: fixed;
  left: 50%;
  bottom: 40px;
  display: flex;
  align-items: center;
  gap: 8px;
  transform: translate(-50%, 8px);
  background: var(--solid);
  color: var(--on-solid);
  font-size: 13px;
  padding: 9px 14px;
  border-radius: var(--r-ctl);
  box-shadow: var(--shadow-modal), 0 12px 28px -10px rgba(0, 0, 0, 0.4);
  opacity: 0;
  pointer-events: none;
  transition: opacity 200ms, transform 200ms var(--ease);
  z-index: 55;
}

.toast-dot {
  width: 6px;
  height: 6px;
  border-radius: var(--r-full);
  background: var(--ok);
  flex-shrink: 0;
}

.toast.is-warn .toast-dot { background: var(--warn); }
.toast.is-error .toast-dot { background: var(--danger); }

.toast.show {
  opacity: 1;
  transform: translate(-50%, 0);
}

/* ============================================================
   滚动条
   ============================================================ */

/* 做法不是「消灭滚动条」而是「让它安静」：8px、圆角、平时接近透明，
   鼠标进到那个区域才变深。滚动条还在、还能拖，只是不再抢注意力。
   这一屏天生就有四条（编辑区 / 镜像 / 预览 / 面板），系统默认的实心灰条
   竖四根在屏幕上，视觉重量比它们各自承载的信息还大。

   ⚠️ 宽度必须**四条一致**：编辑区和镜像两层的内容宽度要完全相同，
   一层 10px 一层 8px 的话，软换行位置对不上，光标当场漂移。
   （所以下面 #editor-mirror 只出现在「宽度」那条规则里，它的 thumb 透明，
   写在编辑区一节。） */

#editor::-webkit-scrollbar,
#editor-mirror::-webkit-scrollbar,
#preview-scroll::-webkit-scrollbar,
#doc-list::-webkit-scrollbar,
.palette-list::-webkit-scrollbar,
.panel-body::-webkit-scrollbar {
  width: 8px;
  height: 8px;
}

#editor::-webkit-scrollbar-track,
#preview-scroll::-webkit-scrollbar-track,
#doc-list::-webkit-scrollbar-track,
.palette-list::-webkit-scrollbar-track,
.panel-body::-webkit-scrollbar-track {
  background: transparent;
}

#editor::-webkit-scrollbar-thumb,
#preview-scroll::-webkit-scrollbar-thumb,
#doc-list::-webkit-scrollbar-thumb,
.palette-list::-webkit-scrollbar-thumb,
.panel-body::-webkit-scrollbar-thumb {
  background: transparent;
  border-radius: var(--r-full);
  border: 2px solid transparent;
  background-clip: content-box;
}

.editor-wrap:hover #editor::-webkit-scrollbar-thumb,
#preview-scroll:hover::-webkit-scrollbar-thumb,
#doc-list:hover::-webkit-scrollbar-thumb,
.palette-list:hover::-webkit-scrollbar-thumb,
.panel-body:hover::-webkit-scrollbar-thumb {
  background: color-mix(in srgb, var(--text-3) 42%, transparent);
  background-clip: content-box;
}

#editor::-webkit-scrollbar-thumb:hover,
#preview-scroll::-webkit-scrollbar-thumb:hover,
#doc-list::-webkit-scrollbar-thumb:hover,
.palette-list::-webkit-scrollbar-thumb:hover,
.panel-body::-webkit-scrollbar-thumb:hover {
  background: var(--text-3);
  background-clip: content-box;
}

/* Firefox 没有 hover 态的滚动条，给它一条一直可见但很淡的。
   ⚠️ scrollbar-width 也必须四处一致，理由同上（内容宽度）。 */
@supports (scrollbar-color: red red) and (not selector(::-webkit-scrollbar)) {
  #editor,
  #editor-mirror,
  #preview-scroll,
  #doc-list,
  .palette-list,
  .panel-body {
    scrollbar-width: thin;
    scrollbar-color: color-mix(in srgb, var(--text-3) 40%, transparent)
      transparent;
  }
  #editor-mirror { scrollbar-color: transparent transparent; }
}

/* ============================================================
   窄屏
   ============================================================ */

@media (max-width: 1180px) {
  .save-chip { display: none; }
}

@media (max-width: 980px) {
  /* 塞不下两栏时，分屏退化成只剩编辑区：靠视图切换来回看 */
  .main[data-view="split"] .pane-preview { display: none; }

  .panel { flex: 1 1 auto; margin-left: 0; }
  .main[data-view="style"] .pane-preview { display: none; }
}

@media (prefers-reduced-motion: reduce) {
  * {
    animation: none !important;
    transition: none !important;
  }
}
