/* ══════════════════════════════════════════════════════════════
   墨耕 · 水墨视觉系统
   宣纸为底，墨色为字，朱砂为记。深色不是水墨的真解。
   ══════════════════════════════════════════════════════════════ */

:root {
	color-scheme: light;
	--paper:       #efe8d9;   /* 宣纸 */
	--paper-hi:    #f7f2e6;   /* 纸面高光：凸起的地方（按钮、输入框） */
	--paper-lo:    #e4dbc7;   /* 纸面阴影 */
	--paper-sunk:  #ded4be;   /* 凹陷：输入框内里 */

	--ink:         #2a2620;   /* 墨：正文 */
	--ink-2:       #5b5347;   /* 淡墨 */
	/* ink-3 / ink-4 是「淡墨 / 飞白」两级：前者承担可读的次要文字（≥4.5:1），
	   后者是纯装饰的最淡一级（≥3:1）。两级都推满 4.5 就会糊成同一个色，
	   水墨的浓淡关系反而没了。
	   所以 ink-4 只许用于描边、分隔、圆点、滚动条这些不成句的地方；
	   凡是能读的句子（含占位符、标签、字数、时间）一律降到 ink-3 或更高。
	   ink-3 原为 #6d665c，在 paper-lo / paper-sunk 上只有 4.12 / 3.85，够不着自己
	   承诺的 4.5；压深一档后四种纸面上是 5.16 / 5.64 / 4.58 / 4.28。 */
	--ink-3:       #665f55;   /* 淡墨（次要文字，可读） */
	--ink-4:       #8a8274;   /* 飞白（最淡，只做描边与点缀，不承载文字） */
	--rule:        rgba(42, 38, 32, 0.13);
	--rule-soft:   rgba(42, 38, 32, 0.07);
	--rule-strong: rgba(42, 38, 32, 0.22);
	--hover:       rgba(42, 38, 32, 0.05);

	--cinnabar:    #a8392b;   /* 朱砂 */
	--cinnabar-lt: #c2543f;
	/* 朱砂当字用的时候另有一档：印、底、边用 --cinnabar 都合式，
	   但同一支朱砂落到自家染出来的浅红底（cinnabar-wash）上，
	   要够得着 4.5:1 才行。浅色纸上 #a8392b 本身就有 4.70–5.24，
	   所以这一档只对暗色有意义（暗色 #d1594a 在洗红底上只有 3.91）。
	   --cinnabar 仍然负责一切「填」的地方，字一律走 --cinnabar-ink。 */
	--cinnabar-ink: #a8392b;
	--cinnabar-wash: rgba(168, 57, 43, 0.09);
	--indigo:      #3b4c66;   /* 靛青 */
	--moss:        #55684a;   /* 苔绿 */
	--seal:        #9c2f22;   /* 印泥 */
	--on-paper:    #f8f2e6;   /* 落在墨底上的字（亮色主题的主按钮悬停） */
	--on-cinnabar: #f8f2e6;   /* 落在朱砂上的字 */
	--song:   var(--serif);   /* 正文用的宋体；此前引用了未定义的 --song，会落回无衬线 */

	--serif: "Songti SC", "STSong", "SimSun", "Noto Serif SC", "Source Han Serif SC", serif;
	--kai:   "Kaiti SC", "STKaiti", "KaiTi", "楷体", var(--serif);
	--sans:  -apple-system, "PingFang SC", "Microsoft YaHei", "Segoe UI", system-ui, sans-serif;
	--mono:  "Cascadia Code", "SF Mono", Consolas, monospace;
	/* 稿台排版偏好。JS 会按「排版」里的选择改写这三个变量。 */
	--ms-font-size: 17px;
	--ms-line-height: 2.05;
	--ms-measure: 54em;

	--noise: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='260' height='260'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.8' numOctaves='4' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='260' height='260' filter='url(%23n)' opacity='0.4'/%3E%3C/svg%3E");
	/* 纸纤维的叠色方式：亮纸上 multiply 才像纸，暗纸上要换成 lighten */
	--fiber-blend: multiply;
	--fiber-alpha: 0.05;

	--wash: 420ms cubic-bezier(0.22, 0.61, 0.36, 1);
	--ink-wash: radial-gradient(ellipse 92% 100% at 0% 50%, rgba(42, 38, 32, 0.1), rgba(42, 38, 32, 0.02) 72%, transparent);
	--sheen: radial-gradient(ellipse 120% 60% at 50% 0%, rgba(255, 253, 247, 0.55), transparent 70%);
	--shade: linear-gradient(180deg, transparent, rgba(228, 219, 199, 0.4));
	--lift: rgba(42, 38, 32, 0.045);
	--lift-2: rgba(42, 38, 32, 0.03);
	--seal-edge: rgba(246, 241, 228, 0.32);
	--seal-drop: rgba(120, 40, 30, 0.28);
	--amber:        #b8862f;
	--cinnabar-edge: rgba(168, 57, 43, 0.32);
	--cinnabar-soft: rgba(168, 57, 43, 0.05);
	--cinnabar-faint: rgba(168, 57, 43, 0.12);
	--cinnabar-tint: rgba(168, 57, 43, 0.045);
	--cinnabar-glow: rgba(168, 57, 43, 0.055);
	--moss-edge:    rgba(85, 104, 74, 0.3);
	--moss-wash:    rgba(85, 104, 74, 0.1);
	--moss-soft:    rgba(85, 104, 74, 0.06);
	--ink-lift:     #3d3730;
	--focus-paper:  #fbf7ee;
	--shadow:       rgba(42, 38, 32, 0.22);
	--backdrop:     rgba(42, 38, 32, 0.42);
	--scrim:        rgba(228, 219, 199, 0.42);

	/* 安全区：横屏刘海、底部 Home Indicator。env() 在没有安全区的设备上回退成 0。 */
	--safe-t: env(safe-area-inset-top, 0px);
	--safe-b: env(safe-area-inset-bottom, 0px);
	--safe-l: env(safe-area-inset-left, 0px);
	--safe-r: env(safe-area-inset-right, 0px);
	/* 触屏上最小的点击目标 */
	--tap: 44px;

	/* ── 冻结的度量阶梯 ───────────────────────────────────────
	   间距 / 圆角 / 字号 / 动效曲线 / 触控尺寸。这几组与昼夜无关，
	   所以只写在亮色块里，由测试的 themeInvariant 白名单放行。
	   新写的规则一律从这里取值：散落的 px 一多，古风的「匀」就散了。 */
	--sp-1: 4px;
	--sp-2: 8px;
	--sp-3: 12px;
	--sp-4: 16px;
	--sp-5: 24px;
	--sp-6: 32px;
	--r-1: 3px;
	--r-2: 6px;
	--r-3: 10px;
	--fs-xs: 11.5px;
	--fs-sm: 12.5px;
	--fs-md: 14px;
	--fs-lg: 16px;
	--fs-xl: 19px;
	/* 一笔刷下去的时长与曲线：所有新动效共用，快而收得住。
	   不要用弹性曲线 —— 纸上不会弹。 */
	--brush: 320ms cubic-bezier(0.2, 0.7, 0.3, 1);
	/* 安卓上舒服的最小触控高度（Material 的 48dp 口径） */
	--tap-lg: 48px;

	/* ── 裱纸：面板的双线框与厚度 ─────────────────────────────
	   外一条强线（走既有 border 或 inset 强线），内一条弱线，顶边再一道高光。
	   三层都靠 box-shadow 叠，绝不加 border：面板每宽 1px，
	≥900px 的两栏 / 三栏都会跟着挪位。 */
	--panel-hi:   rgba(255, 253, 247, 0.62);   /* 顶边那道高光 */
	--panel-ring: rgba(42, 38, 32, 0.075);     /* 内描线：裱纸的第二道框 */
	--panel-drop: rgba(42, 38, 32, 0.055);     /* 面板浮起的一线投影 */
	--panel-face: linear-gradient(180deg, var(--paper-hi) 0%, var(--paper) 44%, var(--paper) 100%);

	/* ── 赭金与茶褐：角花、界格、回纹用的低饱和暖色 ─────────── */
	--gold-line:  rgba(184, 134, 47, 0.5);
	--gold-wash:  rgba(184, 134, 47, 0.07);
	--gold-edge:  rgba(184, 134, 47, 0.28);
	--tea:        #7a5b3e;
	--tea-wash:   rgba(122, 91, 62, 0.075);
	--tea-edge:   rgba(122, 91, 62, 0.26);
	/* 回纹带：一排竖短齿压一条收口的横线，6px 高。
	   真正的回纹要画 SVG，那就得把颜色写进 data-uri —— 违反令牌约束，
	   也会在暗色下变成一坨硬色。宁可抽象成「齿线」。 */
	--fret:
		repeating-linear-gradient(90deg, var(--gold-line) 0 1px, transparent 1px 7px),
		linear-gradient(90deg, transparent, var(--gold-edge) 14%, var(--gold-edge) 86%, transparent);

	/* 远山：空状态背后极淡的山影与云气，压到几乎看不见才算「淡墨」 */
	--mountains:
		radial-gradient(ellipse 58% 40% at 14% 92%, rgba(42, 38, 32, 0.055), transparent 72%),
		radial-gradient(ellipse 44% 28% at 54% 100%, rgba(42, 38, 32, 0.045), transparent 74%),
		radial-gradient(ellipse 66% 24% at 88% 84%, rgba(59, 76, 102, 0.045), transparent 76%);

	/* 墨晕 / 朱晕：悬停与按下时从底边洇上来的一层色 */
	--ink-bleed:      radial-gradient(ellipse 120% 78% at 50% 118%, rgba(42, 38, 32, 0.16), transparent 72%);
	--cinnabar-bleed: radial-gradient(ellipse 120% 78% at 50% 118%, rgba(168, 57, 43, 0.14), transparent 72%);

	/* 骨架屏：纸色底 + 一道掠过的光。光要窄，宽了就成旋转的银条了 */
	--skeleton:       rgba(42, 38, 32, 0.07);
	--skeleton-hi:    rgba(255, 253, 247, 0.55);
	--skeleton-sheen: linear-gradient(100deg, transparent 0%, transparent 38%, var(--skeleton-hi) 50%, transparent 62%, transparent 100%);

	/* 稿面正文：单独一个令牌，夜里才能只提亮正文而不动全局墨色 */
	--ms-ink: #2a2620;
}

/* ── 夜窗：同一套宣纸/墨/朱砂，换在夜里读 ─────────────────────
   不是把亮色反相，而是把「纸」压成暖黑、「墨」提成月白 ——
   浓淡关系照旧，只是纸墨互换了位置。 */
:root[data-theme="dark"] {
	color-scheme: dark;
	--paper:       #17150f;
	--paper-hi:    #221f18;
	--paper-lo:    #100e09;
	--paper-sunk:  #0c0b07;

	--ink:         #ece5d4;
	--ink-2:       #c2bba7;
	--ink-3:       #948c78;
	--ink-4:       #6d6656;
	--on-paper:    #17150f;

	--ink-4:       #766f60;   /* 夜里的飞白要比白天的再抬一点，否则标签看不清 */
	--rule:        rgba(236, 229, 212, 0.14);
	--rule-soft:   rgba(236, 229, 212, 0.075);
	--rule-strong: rgba(236, 229, 212, 0.24);
	--hover:       rgba(236, 229, 212, 0.07);

	/* 朱砂在黑底上要提亮，否则发闷 */
	--cinnabar:    #d1594a;
	--cinnabar-lt: #e07a68;
	/* 夜里当字用的朱砂再抬一档：#d1594a 压在自家洗红底上只有 3.91:1，
	   #e07a68 在洗红底上是 5.34、在纸面高光上是 5.60、在纸上是 6.22。
	   填色（印、底、边）照旧用 --cinnabar。 */
	--cinnabar-ink: #e07a68;
	--cinnabar-wash: rgba(209, 89, 74, 0.14);
	--indigo:      #8fa6c4;
	--moss:        #9db488;
	--seal:        #b83728;
	--on-cinnabar: #f8f2e6;   /* 落在朱砂上的字 */

	--fiber-blend: lighten;
	--fiber-alpha: 0.035;

	--ink-wash: radial-gradient(ellipse 92% 100% at 0% 50%, rgba(236, 229, 212, 0.09), rgba(236, 229, 212, 0.02) 72%, transparent);
	--sheen: radial-gradient(ellipse 120% 60% at 50% 0%, rgba(236, 229, 212, 0.05), transparent 70%);
	--shade: linear-gradient(180deg, transparent, rgba(0, 0, 0, 0.35));
	--lift: rgba(236, 229, 212, 0.05);
	--lift-2: rgba(236, 229, 212, 0.032);
	--seal-edge: rgba(236, 229, 212, 0.22);
	--amber:        #d9a445;
	--cinnabar-edge: rgba(209, 89, 74, 0.42);
	--cinnabar-soft: rgba(209, 89, 74, 0.1);
	--cinnabar-faint: rgba(209, 89, 74, 0.18);
	--cinnabar-tint: rgba(209, 89, 74, 0.09);
	--cinnabar-glow: rgba(209, 89, 74, 0.12);
	--moss-edge:    rgba(157, 180, 136, 0.4);
	--moss-wash:    rgba(157, 180, 136, 0.14);
	--moss-soft:    rgba(157, 180, 136, 0.1);
	--ink-lift:     #f6f0e0;
	--focus-paper:  #2a2620;
	--shadow:       rgba(0, 0, 0, 0.62);
	--backdrop:     rgba(0, 0, 0, 0.66);
	--scrim:        rgba(0, 0, 0, 0.4);
	--seal-drop: rgba(0, 0, 0, 0.5);

	/* ── 夜窗里的裱纸：纸压成暖黑之后，高光只能给极少一点 ─────── */
	--panel-hi:   rgba(236, 229, 212, 0.06);
	--panel-ring: rgba(236, 229, 212, 0.06);
	--panel-drop: rgba(0, 0, 0, 0.42);
	--panel-face: linear-gradient(180deg, var(--paper-hi) 0%, var(--paper) 44%, var(--paper) 100%);

	/* 赭金与茶褐在黑底上都要提亮，否则角花彻底看不见 */
	--gold-line:  rgba(217, 164, 69, 0.46);
	--gold-wash:  rgba(217, 164, 69, 0.1);
	--gold-edge:  rgba(217, 164, 69, 0.26);
	--tea:        #c2a17c;
	--tea-wash:   rgba(194, 161, 124, 0.1);
	--tea-edge:   rgba(194, 161, 124, 0.3);
	--fret:
		repeating-linear-gradient(90deg, var(--gold-line) 0 1px, transparent 1px 7px),
		linear-gradient(90deg, transparent, var(--gold-edge) 14%, var(--gold-edge) 86%, transparent);

	/* 夜里的远山：换成月白，山影才浮得出来 */
	--mountains:
		radial-gradient(ellipse 58% 40% at 14% 92%, rgba(236, 229, 212, 0.05), transparent 72%),
		radial-gradient(ellipse 44% 28% at 54% 100%, rgba(236, 229, 212, 0.04), transparent 74%),
		radial-gradient(ellipse 66% 24% at 88% 84%, rgba(143, 166, 196, 0.05), transparent 76%);

	--ink-bleed:      radial-gradient(ellipse 120% 78% at 50% 118%, rgba(236, 229, 212, 0.13), transparent 72%);
	--cinnabar-bleed: radial-gradient(ellipse 120% 78% at 50% 118%, rgba(209, 89, 74, 0.2), transparent 72%);

	--skeleton:       rgba(236, 229, 212, 0.08);
	--skeleton-hi:    rgba(236, 229, 212, 0.11);
	--skeleton-sheen: linear-gradient(100deg, transparent 0%, transparent 38%, var(--skeleton-hi) 50%, transparent 62%, transparent 100%);

	/* 夜里读长章全靠正文那一档对比度：只把正文提亮，别把整页墨都推上去 */
	--ms-ink: #f2ecdd;
}

* { box-sizing: border-box; }
html, body { height: 100%; }
/* 文字放大要听用户的，别被浏览器自己按屏幕宽度缩一遍 */
html {
	-webkit-text-size-adjust: 100%;
	text-size-adjust: 100%;
	/* 右案（≤1240 改成抽屉）收起时停在视口外：right: 0 再 translateX(102%)。
	   这一停，整张纸就被撑宽了抽屉的宽度 —— 1100 的窗口里文档宽 1467，
	   整页能被拖出桌面三百来像素，左边的栏目标题跟着一起滑走。
	   抽屉本身不能改（它得从右边滑进来），所以改根元素：横向裁掉。
	   用 clip 而不是 hidden —— hidden 会造出一个滚动容器，clip 只裁不滚。 */
	overflow-x: clip;
}

body {
	margin: 0;
	background: var(--paper);
	color: var(--ink);
	font-family: var(--sans);
	font-size: var(--fs-md);
	overflow: hidden;
	overflow-x: hidden;
	/* 页面本身不滚，橡皮筋就留给内部的滚动容器 */
	overscroll-behavior-y: none;
	-webkit-font-smoothing: antialiased;
}

/* 纸纤维。强度必须低，否则像电视雪花 */
body::before {
	content: "";
	position: fixed;
	inset: 0;
	background-image: var(--noise);
	opacity: var(--fiber-alpha);
	mix-blend-mode: var(--fiber-blend);
	pointer-events: none;
	z-index: 1;
}

::selection { background: var(--cinnabar-wash); }

/* 焦点环：一枚朱砂细圈。键盘走到哪就得看得见，这条不能为了「素」而让掉 */
:focus-visible { outline: 3px solid var(--cinnabar); outline-offset: 2px; }

/* 滚动条：细、圆、轨道全透明 —— 页面是纸，不该挂一根金属条 */
* { scrollbar-width: thin; scrollbar-color: var(--rule-strong) transparent; }
*::-webkit-scrollbar { width: 8px; height: 8px; }
*::-webkit-scrollbar-track { background: transparent; }
*::-webkit-scrollbar-thumb {
	background: var(--rule-strong);
	border-radius: var(--sp-2);
	border: 2px solid transparent;
	background-clip: content-box;
}
*::-webkit-scrollbar-thumb:hover { background: var(--ink-4); background-clip: content-box; }
*::-webkit-scrollbar-corner { background: transparent; }

/* ── 骨架 ────────────────────────────────────────────────── */

.desk {
	position: relative;
	z-index: 2;
	display: grid;
	grid-template-columns: 264px minmax(0, 1fr) 322px;
	/* alert 行平时是 0 高（横幅 display:none），出现时才占位。
	   顶栏那行要留出刘海的高度，安全区之外的墨才该是纸。 */
	grid-template-rows: calc(58px + var(--safe-t)) auto minmax(0, 1fr);
	grid-template-areas:
		"beam   beam  beam"
		"alert  alert alert"
		"rail   stage  desk";
	height: 100vh;
	/* dvh 跟着地址栏收缩走，vh 会留一条永远够不着的空白 */
	height: 100dvh;
	animation: settle 900ms cubic-bezier(0.22, 0.61, 0.36, 1) both;
}

/* ── 案头（管理）与写作台（创作）是两级，不是一排并列的页 ──── */

/* 案头：只有中台。左卷与右案都收起，顶栏也不出现写作相关的控件 */
.desk.is-home {
	grid-template-columns: minmax(0, 1fr);
	grid-template-areas:
		"beam"
		"alert"
		"stage";
}
.desk.is-home .rail,
.desk.is-home .desk-right { display: none; }
.desk.is-home .stage-bar { display: none; }
/* 案头上的设定官也要用模型，所以这支笔和档位在这里同样要能选。
   早先这里是 display:none —— 那时案头还没有智能体，现在藏起来就没法备料了。 */

/* 写作台里的两个工作台自带素材库与装配清单，右案此时重复，让出宽度。
   grid-template-areas 必须跟着列数一起改：两边不一致时整条声明会作废。 */
.desk.is-bench {
	grid-template-columns: 264px minmax(0, 1fr);
	grid-template-areas:
		"beam  beam"
		"alert alert"
		"rail  stage";
}
.desk.is-bench .desk-right { display: none; }

/* 顶栏里的「回案头」：它是上一层，不该和书名挤在一起 */
.beam-back { flex: none; align-self: center; font-size: 12px; }

@keyframes settle {
	from { opacity: 0; transform: translateY(8px); }
	to   { opacity: 1; transform: none; }
}

/* ── 顶栏 ────────────────────────────────────────────────── */

.beam {
	grid-area: beam;
	position: relative;
	display: flex;
	align-items: center;
	gap: 20px;
	/* 顶栏要避开刘海与横向缺口 */
	padding: var(--safe-t) calc(20px + var(--safe-r)) 0 calc(20px + var(--safe-l));
	background: linear-gradient(180deg, var(--paper-hi), var(--paper));
	border-bottom: 1px solid var(--rule);
}

.brand { display: flex; align-items: center; gap: 11px; flex: none; }

/* 印：朱泥方章 */
.seal {
	position: relative;
	width: 34px;
	height: 34px;
	display: grid;
	place-items: center;
	background: var(--seal);
	color: var(--on-cinnabar);
	font-family: var(--kai);
	font-size: 21px;
	line-height: 1;
	border-radius: 2px;
	transform: rotate(-3.5deg);
	box-shadow:
	inset 0 0 0 1.5px var(--seal-edge),
	0 1px 3px var(--seal-drop);
	overflow: hidden;
}
/* 印泥不匀 */
.seal::after {
	content: "";
	position: absolute;
	inset: 0;
	background-image: var(--noise);
	opacity: 0.28;
	mix-blend-mode: screen;
}

.brand-text h1 {
	margin: 0;
	font-family: var(--kai);
	font-size: 17px;
	letter-spacing: 0.14em;
	font-weight: 600;
}
.brand-text p { margin: 1px 0 0; font-size: 10.5px; color: var(--ink-3); letter-spacing: 0.04em; }

.beam-mid { flex: 1; min-width: 0; display: flex; align-items: baseline; gap: 12px; }
.beam-title {
	font-family: var(--kai);
	font-size: 16px;
	letter-spacing: 0.05em;
	white-space: nowrap;
	overflow: hidden;
	text-overflow: ellipsis;
}
.beam-stats { font-size: 11.5px; color: var(--ink-3); font-variant-numeric: tabular-nums; white-space: nowrap; }

.beam-controls { display: flex; align-items: center; gap: 7px; flex: none; }

/* ── 左卷 ────────────────────────────────────────────────── */

.rail {
	grid-area: rail;
	background: linear-gradient(180deg, var(--paper-lo), var(--paper));
	border-right: 1px solid var(--rule);
	display: flex;
	flex-direction: column;
	overflow: hidden;
	/* 同为网格项：不显式归零就会被内容顶大，把整页顶出滚动条。 */
	min-height: 0;
}

.rail-block { display: flex; flex-direction: column; padding: 16px 12px 8px; min-height: 0; }
.rail-block + .rail-block { border-top: 1px solid var(--rule-soft); }
.rail-grow { flex: 1; }

.rail-label {
	display: flex;
	align-items: center;
	gap: 8px;
	margin: 0 0 10px 4px;
	font-family: var(--kai);
	font-size: var(--fs-sm);
	font-weight: 600;
	letter-spacing: 0.14em;
	color: var(--ink-2);
}
.tick { width: 5px; height: 5px; background: var(--cinnabar); transform: rotate(45deg); flex: none; }
/* 题签外的线从朱砂/赭金起笔，向右淡出 —— 一条实线会把标题切断 */
.rail-label::after {
	content: "";
	flex: 1;
	height: 1px;
	background: linear-gradient(90deg, var(--gold-edge), transparent);
}
.rail-note {
	margin: 6px;
	padding-bottom: var(--sp-5);
	font-size: var(--fs-sm);
	line-height: 1.9;
	color: var(--ink-3);
	font-family: var(--serif);
	/* 空卷底下一痕远山：写不写得出字还不知道，先给个开门见山 */
	background-image: var(--mountains);
	background-repeat: no-repeat;
	background-position: center bottom;
}

.project-list, .chapter-list { list-style: none; margin: 0; padding: 0; overflow-y: auto; min-height: 0; }

/* 章目是一页目录：序号列右侧压一条朱丝栏，整卷的条目都排在它右边。
   线画在列表上而不是每个条目上 —— 条目一换行或 hover，竖线不能断。
   34px = 10px 内边距 + 序号列 1.7em + 半个 gap，见下面的 .chapter-item。 */
.chapter-list {
	background-image: linear-gradient(90deg, transparent 33px, var(--rule-soft) 33px, var(--rule-soft) 34px, transparent 34px);
	background-repeat: no-repeat;
}

.project-item {
	position: relative;
	padding: 8px 10px;
	margin-bottom: 2px;
	border-radius: 4px;
	cursor: pointer;
	transition: background var(--wash);
}
.project-item:hover { background: var(--lift); }
.project-item.is-on { background: var(--ink-wash); }
.project-item.is-on::before {
	content: "";
	position: absolute;
	left: 0;
	top: 8px;
	bottom: 8px;
	width: 2px;
	background: var(--cinnabar);
	border-radius: 2px;
}
.project-item .name { font-family: var(--serif); font-size: 14px; line-height: 1.5; }
.project-item .meta { font-size: 10.5px; color: var(--ink-3); margin-top: 2px; font-variant-numeric: tabular-nums; }

.chapter-item {
	position: relative;
	display: flex;
	align-items: baseline;
	gap: 9px;
	padding: 7px 10px;
	border-radius: var(--r-1);
	cursor: pointer;
	transition: background var(--brush), box-shadow var(--brush);
	/* 书页行线：用 inset 阴影画，加 border 会让每一行高 1px，
	   一屏十几行就是一整段位移 —— 章目滚动位置会跟着抖。 */
	box-shadow: inset 0 -1px 0 var(--rule-soft);
}
/* 书口记号：已落笔的章用一枚墨点，未落笔的用淡点（配合末尾的空心印）。
   点落在行首内边距里，所以不占位、也不影响序号对齐。 */
.chapter-item::after {
	content: "";
	position: absolute;
	left: 3px;
	top: 50%;
	width: 3px;
	height: 3px;
	margin-top: -1.5px;
	border-radius: 50%;
	background: var(--ink-4);
	opacity: 0.85;
	pointer-events: none;
}
/* 未落笔：只有 .dotmark 这一个 DOM 差别，用 :has 认它 */
.chapter-item:has(.dotmark)::after { background: var(--rule-strong); opacity: 1; }
.chapter-item:hover { background: var(--lift); }
.chapter-item.is-on {
	background: var(--ink-wash);
	/* 当前章：朱砂细线 + 纸面高光，像在目录上夹了一枚书签 */
	box-shadow: inset 0 -1px 0 var(--rule-soft), inset 0 0 0 1px var(--cinnabar-faint), inset 0 1px 0 var(--panel-hi);
}
.chapter-item.is-on::after { display: none; }
.chapter-item.is-on::before {
	content: "";
	position: absolute;
	left: 0;
	top: 7px;
	bottom: 7px;
	width: 2px;
	background: var(--cinnabar);
	border-radius: 2px;
}
.chapter-item .ord {
	flex: none;
	width: 1.7em;
	/* 楷体的「一二三」才有书口题号的味道，宋体的数字偏印刷体 */
	font-family: var(--kai);
	font-size: var(--fs-sm);
	color: var(--ink-3);
	font-variant-numeric: tabular-nums;
	letter-spacing: 0.02em;
}
.chapter-item.is-on .ord { color: var(--cinnabar-ink); }
.chapter-item .ct { flex: 1; min-width: 0; font-family: var(--serif); font-size: 13.5px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.chapter-item .cw { flex: none; font-size: 10.5px; color: var(--ink-3); font-variant-numeric: tabular-nums; }
/* 未落笔的记号从实心朱点改成空心小印：空的那一格也得像个记号，不能像杂质 */
.chapter-item .dotmark {
	flex: none;
	align-self: center;
	margin-left: 2px;
	width: 6px;
	height: 6px;
	border-radius: 50%;
	background: transparent;
	border: 1px solid var(--cinnabar-edge);
	opacity: 1;
}

/* ── 稿台 ────────────────────────────────────────────────── */

.stage {
	grid-area: stage;
	display: flex;
	flex-direction: column;
	min-width: 0;
	/* 网格项默认 min-height:auto，会被内容顶大 —— 这一格一旦撑开，
	   整条高度链（stage → view → bench → pane → stream）就全失效，
	   页面出现滚动条而不是对话区自己滚。 */
	min-height: 0;
	background:
	var(--sheen),
		var(--paper);
}

.stage-bar {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 16px;
	padding: 9px 26px;
	border-bottom: 1px solid var(--rule-soft);
	flex: none;
	position: relative;
}
/* 台口的一道朱丝线：两端淡出，只在中间实。
   绝对定位压在既有的 1px border 上，不占高度 —— 顶栏不会因此高 1px。 */
.stage-bar::after {
	content: "";
	position: absolute;
	left: 0;
	right: 0;
	bottom: -1px;
	height: 1px;
	background: linear-gradient(90deg, transparent, var(--gold-line) 16%, var(--gold-line) 84%, transparent);
	opacity: 0.6;
	pointer-events: none;
}

.tabs { display: flex; gap: 3px; }
.tab {
	display: flex;
	align-items: baseline;
	gap: 7px;
	padding: 5px 15px;
	border: 0;
	border-radius: 4px;
	background: transparent;
	color: var(--ink-3);
	font-family: inherit;
	cursor: pointer;
	transition: color var(--wash), background var(--wash);
}
.tab b { font-family: var(--kai); font-size: 16px; font-weight: 600; letter-spacing: 0.1em; }
.tab span { font-size: 11.5px; letter-spacing: 0.08em; }
.tab:hover { color: var(--ink-2); background: var(--hover); }
.tab.is-on { color: var(--cinnabar-ink); background: var(--cinnabar-wash); }

.stage-actions { display: flex; align-items: center; gap: 8px; }

.view { display: none; flex: 1; min-height: 0; }
.view.is-on { display: flex; flex-direction: column; }
/* 工作台是两栏布局，滚动交给内部的 .bench 自己管 */
.view-bench { overflow: hidden; }

/* ── 文稿 ────────────────────────────────────────────────── */

/* 稿台自己就是滚动容器。
   body 是 overflow:hidden，骨架又是 100vh 的网格，往下每一级都只写了 min-height:0 ——
   整条链上没有任何一个滚动条，长章节因此被直接裁掉：翻不到底，也拖不动。

   上留白**不能**放在这个滚动容器上：容器有 padding-top，吸顶的操作条就会被垫下去一截
   （条子的 overflow 会跟着 padding 走），台口永远留一道缝。所以上面留白给零，
   改由稿纸 .ms-page / 总目 .front-matter 自己撑着；左右与底部留白仍留在这里。 */
#view-manuscript {
	/* 三个分量仍要能被别处引用：稿纸靠 --ms-pad-t 撑天头，操作条靠 --ms-pad-x 出血。 */
	--ms-pad-t: 46px;
	--ms-pad-x: 40px;
	--ms-pad-b: 96px;
	overflow: auto;
	padding: 0 var(--ms-pad-x) var(--ms-pad-b);
	overscroll-behavior: contain;
}

/* width:100% 不能省。稿台是 flex 纵向容器，而 margin:auto 会关掉 align-self:stretch ——
   只写 max-width 的话，稿纸退化成 fit-content：读稿时被长句顶到 54em 上限看着正常，
   一进改稿模式正文就成了唯一内容，宽度塌到 textarea 的 cols 默认值（20 字），
   于是编辑框窄成一条。给它一个确定宽度，再由 max-width 收口。 */
.ms-page {
	width: 100%;
	max-width: var(--ms-measure, 54em);
	margin: 0 auto;
	/* 天头留白在稿纸上，不在滚动容器上 —— 容器留了就垫高了吸顶的操作条。 */
	padding-top: var(--ms-pad-t);
	animation: fade 520ms ease both;
}

.ms-head { text-align: center; margin-bottom: 40px; }
.ms-kicker { margin: 0 0 12px; font-size: 11.5px; letter-spacing: 0.24em; color: var(--ink-3); }
.ms-title {
	margin: 0;
	font-family: var(--kai);
	font-size: 30px;
	font-weight: 600;
	letter-spacing: 0.1em;
	line-height: 1.4;
}
/* 题下的界格：一条 6px 的回纹带，替掉原来那根实线 —— 书页的天头地脚 */
.ms-rule {
	width: 46px;
	height: 6px;
	margin: 20px auto 14px;
	background-image: var(--fret);
	background-repeat: repeat-x, no-repeat;
	background-size: 7px 5px, 100% 1px;
	background-position: 0 0, 0 100%;
	opacity: 0.8;
}
.ms-meta { margin: 0; font-size: 11.5px; color: var(--ink-3); font-variant-numeric: tabular-nums; }

/* 朱丝栏：稿纸的竖向界线，低到不干扰阅读。
   正文用 --ms-ink 而不是 --ink：夜里只提亮稿面，侧栏与表单的墨色不动，
   一页长章的对比度够读，整屏又不至于发白。 */
.ms-text {
	position: relative;
	font-family: var(--serif);
	font-size: var(--ms-font-size, 17px);
	line-height: var(--ms-line-height, 2.05);
	letter-spacing: 0.02em;
	color: var(--ms-ink);
	/* 中文两端对齐：字距交给浏览器按字（inter-ideograph）匀，末行不拉。
	   不加这条，右侧永远参差，书页感就没了。 */
	text-align: justify;
	text-justify: inter-ideograph;
	/* 正文里偶尔会有不带空格的长串（网址、生造词），默认会把稿台顶出横向滚动条 */
	overflow-wrap: break-word;
}
.ms-text::before {
	content: "";
	position: absolute;
	inset: -14px -20px;
	background-image: repeating-linear-gradient(
		90deg,
		transparent 0,
		transparent 33px,
	var(--cinnabar-glow) 33px,
	var(--cinnabar-glow) 34px
	);
	pointer-events: none;
	z-index: -1;
}
.ms-text p { margin: 0 0 1.05em; text-indent: 2em; }
.ms-text p:last-child { margin-bottom: 0; }

.ms-blank {
	padding: 54px 0;
	text-align: center;
	color: var(--ink-3);
	font-family: var(--kai);
	font-size: 15px;
	letter-spacing: 0.1em;
}

.ms-edit {
	display: block;
	width: 100%;
	min-height: 420px;
	/* 高度由脚本按内容撑开（见 fitEditor），这里不留拖拽手柄，免得两者互相打架。 */
	resize: none;
	overflow: hidden;
	padding: 0;
	border: 0;
	background: transparent;
	color: var(--ink);
	font-family: var(--serif);
	font-size: var(--ms-font-size, 17px);
	line-height: var(--ms-line-height, 2.05);
	letter-spacing: 0.02em;
}

.front-matter {
	width: 100%;
	max-width: 44em;
	margin: 0 auto;
	/* 与 .ms-page 同理：天头在纸上，滚动容器上不留 top padding。 */
	padding-top: var(--ms-pad-t);
	animation: fade 520ms ease both;
}
.front-head { text-align: center; margin-bottom: 40px; }
.front-head h2 { margin: 0 0 10px; font-family: var(--kai); font-size: 26px; letter-spacing: 0.2em; font-weight: 600; }
.front-head p { margin: 0; font-size: 12.5px; color: var(--ink-3); line-height: 1.9; }

.toc { list-style: none; margin: 0; padding: 0; counter-reset: toc; }
.toc-item {
	position: relative;
	counter-increment: toc;
	padding: 15px 0 15px 46px;
	border-bottom: 1px solid var(--rule-soft);
	cursor: pointer;
	transition: opacity var(--wash);
}
.toc-item::before {
	content: counter(toc, cjk-ideographic);
	position: absolute;
	left: 4px;
	top: 16px;
	font-family: var(--serif);
	font-size: 13px;
	color: var(--cinnabar-ink);
}
.toc-item:hover { opacity: 0.7; }
.toc-item h3 { margin: 0 0 5px; font-family: var(--kai); font-size: 16.5px; font-weight: 600; letter-spacing: 0.04em; }
.toc-item p { margin: 0; font-family: var(--serif); font-size: 13.5px; line-height: 1.9; color: var(--ink-2); }
.toc-item .toc-meta { margin-top: 7px; font-size: 11px; color: var(--ink-3); font-variant-numeric: tabular-nums; }

/* ── 对议 ────────────────────────────────────────────────── */

.stream {
	flex: 1;
	/* 对话区要自己滚，不能被内容顶高。flex 项的 min-height 默认是 auto，
	   内容一长它就把父容器撑开，页面跟着出现滚动条。 */
	min-height: 0;
	overflow-y: auto;
	padding: 34px 40px 12px;
	display: flex;
	flex-direction: column;
	gap: 26px;
}

.msg { max-width: 40em; margin: 0 auto; width: 100%; }
.msg-role { font-size: 10.5px; letter-spacing: 0.2em; color: var(--ink-3); margin-bottom: 9px; }

/* 墨客的话：直接排成正文，不装进气泡 */
.msg.assistant .msg-body {
	font-family: var(--serif);
	font-size: 16px;
	line-height: 2;
	white-space: pre-wrap;
	word-break: break-word;
}
.msg.user .msg-body {
	font-family: var(--serif);
	font-size: 14.5px;
	line-height: 1.95;
	white-space: pre-wrap;
	word-break: break-word;
	padding-left: 14px;
	border-left: 2px solid var(--cinnabar);
	color: var(--ink-2);
}
.msg.error .msg-body {
	font-family: var(--serif);
	font-size: 14px;
	line-height: 1.9;
	color: var(--cinnabar-ink);
	white-space: pre-wrap;
	padding-left: 14px;
	border-left: 2px solid var(--cinnabar);
}

/* 湿墨点：正在落笔 */
.cursor::after {
	content: "";
	display: inline-block;
	width: 7px;
	height: 1.02em;
	margin-left: 3px;
	vertical-align: -0.16em;
	background: var(--ink);
	animation: bleed 1.5s ease-in-out infinite;
}
@keyframes bleed {
	0%, 100% { opacity: 0.85; transform: scaleY(1); }
	50%      { opacity: 0.2;  transform: scaleY(0.78); }
}

/* 旁批：思考过程默认收起，点开才看 */
.thinking {
	margin: 0 0 10px;
	padding-left: 13px;
	border-left: 1px solid var(--rule);
}
.thinking-head {
	display: block;
	cursor: pointer;
	list-style: none;
	font-family: var(--kai);
	font-size: 12px;
	color: var(--ink-3);
	letter-spacing: 0.06em;
}
.thinking-head::-webkit-details-marker { display: none; }
.thinking-head::before { content: "▸ "; }
.thinking[open] .thinking-head::before { content: "▾ "; }
.thinking-head:hover { color: var(--ink-2); }
.thinking-body {
	margin-top: 4px;
	color: var(--ink-3);
	font-family: var(--serif);
	font-size: 13.5px;
	line-height: 1.85;
	white-space: pre-wrap;
}

.tool {
	display: flex;
	gap: 10px;
	padding: 3px 0 3px 13px;
	border-left: 1px solid var(--rule);
	font-size: 12.5px;
}
.tool + .tool { margin-top: 3px; }
.tool-mark { flex: none; font-family: var(--serif); color: var(--ink-3); width: 1em; }
.tool-name { font-family: var(--kai); font-size: 13px; color: var(--ink-2); letter-spacing: 0.04em; }
.tool-preview { color: var(--ink-3); font-size: 11.5px; line-height: 1.7; margin-top: 2px; white-space: pre-wrap; }
.tool.is-failed { border-left-color: var(--cinnabar); }
.tool.is-failed .tool-mark, .tool.is-failed .tool-name { color: var(--cinnabar-ink); }

/* ── 智能体提问 ───────────────────────────────────────────────
   模型在行笔途中问作者一件事。卡片自带输入框 —— 主输入框这一轮是禁的，
   复用不了，作者得在卡片上就地回一句。
   问完了就把卡片封存：别让人以为还能再答。 */
.ask-card {
	max-width: 40em;
	margin: 0 auto;
	width: 100%;
	padding: var(--sp-3) var(--sp-4);
	border: 1px solid var(--rule);
	border-left: 2px solid var(--cinnabar);
	border-radius: var(--r-2);
	background: var(--paper-hi);
	box-shadow: inset 0 1px 0 var(--panel-hi);
}
.ask-head {
	font-family: var(--kai);
	font-size: var(--fs-xs);
	letter-spacing: 0.16em;
	color: var(--ink-3);
	margin-bottom: var(--sp-1);
}
.ask-text {
	font-family: var(--serif);
	font-size: var(--fs-md);
	line-height: 1.9;
	color: var(--ink);
	white-space: pre-wrap;
	word-break: break-word;
}
.ask-options {
	display: flex;
	flex-wrap: wrap;
	gap: var(--sp-2);
	margin-top: var(--sp-2);
}
.ask-option {
	border: 1px dashed var(--rule-strong);
	border-radius: var(--r-1);
	background: transparent;
	color: var(--ink-2);
	padding: 4px 10px;
	font-family: var(--kai);
	font-size: var(--fs-xs);
	letter-spacing: 0.05em;
	cursor: pointer;
	transition: color var(--wash), border-color var(--wash), background var(--wash);
}
.ask-option:hover:not(:disabled) { color: var(--cinnabar-ink); border-color: var(--cinnabar); background: var(--cinnabar-wash); }
.ask-option:disabled { opacity: 0.5; cursor: not-allowed; }
.ask-form {
	display: flex;
	gap: var(--sp-2);
	margin-top: var(--sp-3);
}
.ask-input {
	flex: 1;
	min-width: 0;
	background: var(--paper-sunk);
	color: var(--ink);
	border: 1px solid var(--rule);
	border-radius: var(--r-1);
	padding: 6px 10px;
	font-family: var(--serif);
	font-size: var(--fs-md);
	outline: none;
	transition: border-color var(--wash), background var(--wash);
}
.ask-input:focus { border-color: var(--ink-3); background: var(--focus-paper); }
.ask-input:disabled { opacity: 0.55; cursor: not-allowed; }
.ask-note {
	margin-top: var(--sp-2);
	font-size: var(--fs-xs);
	line-height: 1.7;
	color: var(--ink-3);
	white-space: pre-wrap;
	word-break: break-word;
}
.ask-note:empty { display: none; }
.ask-card.is-sending { opacity: 0.9; }
.ask-card.is-answered { border-left-color: var(--moss); }
.ask-card.is-answered .ask-head { color: var(--moss); }
.ask-card.is-closed,
.ask-card.is-timeout { border-left-color: var(--ink-4); }
.ask-card.is-closed .ask-head,
.ask-card.is-timeout .ask-head { color: var(--ink-3); }
.bench-talk .ask-card { max-width: min(46em, 100%); }

.msg-foot {
	max-width: 40em;
	margin: 0 auto;
	width: 100%;
	font-size: 10.5px;
	color: var(--ink-3);
	font-variant-numeric: tabular-nums;
	letter-spacing: 0.06em;
}

.void { margin: auto; text-align: center; max-width: 30em; padding: 0 20px; }
.void h3 { margin: 0 0 12px; font-family: var(--kai); font-size: 19px; letter-spacing: 0.14em; color: var(--ink-2); font-weight: 600; }
.void p { margin: 0; font-family: var(--serif); font-size: 14px; line-height: 2; color: var(--ink-3); }

/* ── 案（右栏）───────────────────────────────────────────── */

.desk-right {
	grid-area: desk;
	background: linear-gradient(180deg, var(--paper-lo), var(--paper));
	border-left: 1px solid var(--rule);
	display: flex;
	flex-direction: column;
	overflow: hidden;
	/* 与 .rail 同理：网格项不归零 min-height 就会被内容顶大。 */
	min-height: 0;
}

.bible-tabs { display: flex; flex: none; border-bottom: 1px solid var(--rule); }
.bible-tab {
	flex: 1;
	padding: 11px 4px;
	border: 0;
	border-bottom: 2px solid transparent;
	background: transparent;
	color: var(--ink-3);
	font-family: var(--kai);
	font-size: 14px;
	letter-spacing: 0.1em;
	cursor: pointer;
	transition: color var(--wash), border-color var(--wash);
}
.bible-tab:hover { color: var(--ink-2); }
.bible-tab.is-on { color: var(--cinnabar-ink); border-bottom-color: var(--cinnabar); }

.bible { flex: 1; overflow-y: auto; padding: 16px 16px 40px; }

.card { padding: 13px 0; border-bottom: 1px solid var(--rule-soft); }
.card:last-child { border-bottom: 0; }
.card h4 {
	margin: 0 0 7px;
	font-family: var(--kai);
	font-size: 15px;
	font-weight: 600;
	letter-spacing: 0.05em;
	display: flex;
	align-items: baseline;
	gap: 8px;
}
.card h4 .role { font-family: var(--sans); font-size: 10.5px; font-weight: 400; color: var(--ink-3); letter-spacing: 0.06em; }
.card dl { margin: 0; display: grid; grid-template-columns: 3.4em 1fr; gap: 3px 10px; }
.card dt { font-size: 11px; color: var(--ink-3); letter-spacing: 0.06em; }
.card dd { margin: 0; font-family: var(--serif); font-size: 12.5px; line-height: 1.8; color: var(--ink-2); word-break: break-word; }
.card .tagline { font-size: 11px; color: var(--ink-3); margin-top: 6px; }

.note {
	display: flex;
	gap: 9px;
	padding: 10px 0;
	border-bottom: 1px solid var(--rule-soft);
	font-size: 12.5px;
}
.note:last-child { border-bottom: 0; }
.note-mark { flex: none; width: 5px; height: 5px; border-radius: 50%; margin-top: 7px; background: var(--ink-4); }
.note.info .note-mark { background: var(--indigo); }
.note.warning .note-mark { background: var(--amber); }
.note.blocker .note-mark { background: var(--cinnabar); }
.note-body { min-width: 0; }
.note-where { font-family: var(--kai); font-size: 13px; color: var(--ink-2); }
.note-text { font-family: var(--serif); font-size: 12px; line-height: 1.75; color: var(--ink-3); margin-top: 2px; }

.bible-empty { padding: 40px 0; text-align: center; font-family: var(--kai); font-size: 14px; color: var(--ink-3); letter-spacing: 0.08em; line-height: 2; }

/* ── 素材（料）──────────────────────────────────────────── */

.mat-filter {
	display: flex;
	flex-wrap: wrap;
	gap: 6px;
	padding: 14px 0 4px;
	position: sticky;
	top: 0;
	background: linear-gradient(180deg, var(--paper) 72%, transparent);
	z-index: 2;
}

.chip {
	padding: 3px 11px;
	border: 1px solid var(--rule-soft);
	border-radius: 999px;
	background: transparent;
	font-family: var(--kai);
	font-size: 12.5px;
	color: var(--ink-2);
	cursor: pointer;
	transition: background 0.14s, color 0.14s, border-color 0.14s;
}
.chip:hover { border-color: var(--ink-4); color: var(--ink); }
.chip.is-on { background: var(--ink-wash); border-color: var(--ink-4); color: var(--ink); }

.mat-group { margin: 20px 0 0; }
.mat-group-head {
	display: flex;
	align-items: baseline;
	gap: 8px;
	margin: 0 0 9px;
	padding-bottom: 5px;
	border-bottom: 1px solid var(--rule-soft);
}
.mat-group-head h3 { margin: 0; font-family: var(--kai); font-size: 14px; font-weight: 600; letter-spacing: 0.1em; color: var(--ink); }
.mat-group-head .count { font-size: 11px; color: var(--ink-3); }

/* 素材库两列并排。列宽用 minmax(0,1fr)：不加 0 下限，长标题会把格子撑破。
   列数由下面「素材卡按栏宽排布」一节的容器查询按实测栏宽定，这里给的是兜底。 */
.mat-grid {
	display: grid;
	grid-template-columns: repeat(2, minmax(0, 1fr));
	gap: 10px 12px;
	align-items: start;
}

.card.mat h4 { display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap; }
.card.mat h4 .kind, .mat-head .kind {
	font-family: var(--sans);
	font-size: 10.5px;
	font-weight: 500;
	letter-spacing: 0.06em;
	color: var(--ink-3);
	border: 1px solid var(--rule-soft);
	border-radius: 2px;
	padding: 0 5px;
}
/* 徽章永远靠右首：标题占满一行时它跟在同一行右端，标题放不下折行时它仍贴右首 */
.mat-head .kind { margin-left: auto; }
.card.mat h4 .ok, .mat-head .ok { font-size: 10.5px; font-family: var(--sans); color: var(--cinnabar-ink); }
.card.mat .usage {
	font-size: 12.5px;
	color: var(--ink-2);
	line-height: 1.75;
	padding-left: 9px;
	border-left: 2px solid var(--cinnabar-wash);
	margin-bottom: 7px;
}
.card.mat .mat-body { font-family: var(--song); font-size: 13.5px; line-height: 1.9; color: var(--ink-2); white-space: pre-wrap; }

/* ── 案头（输入）─────────────────────────────────────────── */

.composer {
	flex: none;
	display: flex;
	gap: 12px;
	align-items: flex-end;
	padding: 14px 40px 20px;
	border-top: 1px solid var(--rule-soft);
	background: var(--shade);
}
.composer textarea {
	flex: 1;
	/* textarea 默认 20 列，min-content 宽能有一百多像素；栏拖窄后
	   它会顶着侧边按钮把整条输入区挤出行外 */
	min-width: 0;
	min-height: 62px;
	max-height: 220px;
	resize: vertical;
	padding: 12px 15px;
	border: 1px solid var(--rule);
	border-radius: 4px;
	background: var(--paper-hi);
	color: var(--ink);
	font-family: var(--serif);
	font-size: 15px;
	line-height: 1.9;
	transition: border-color var(--wash), background var(--wash);
}
.composer textarea::placeholder { color: var(--ink-3); font-size: 14px; }
.composer textarea:focus { outline: none; border-color: var(--ink-3); background: var(--focus-paper); }
.composer-side { display: flex; flex-direction: column; gap: 7px; }

/* ── 按钮 ────────────────────────────────────────────────── */

/* 纸面按钮：描边 + 顶边高光 + 底边内阴影 = 一枚压平的纸片。
   四条语义各归其位：.btn 是纸、.btn-ink 是墨、.btn-quiet 无框、.btn-danger 是朱砂。
   过渡一律走 --brush：快而收得住，点了要有落手的感觉。 */
.btn {
	border: 1px solid var(--rule);
	border-radius: var(--r-2);
	background: var(--paper-hi);
	box-shadow: inset 0 1px 0 var(--panel-hi), inset 0 -1px 0 var(--panel-ring);
	color: var(--ink-2);
	padding: 7px 15px;
	font-family: inherit;
	font-size: var(--fs-sm);
	letter-spacing: 0.06em;
	cursor: pointer;
	transition:
		background-color var(--brush),
		border-color var(--brush),
		color var(--brush),
		box-shadow var(--brush),
		transform var(--brush);
	white-space: nowrap;
	/* 安卓上点一下就闪一块灰蓝，纸上不能有这种颜色 */
	-webkit-tap-highlight-color: transparent;
}
.btn:hover:not(:disabled) {
	border-color: var(--ink-4);
	color: var(--ink);
	/* 从底边洇上来的一层薄墨：不用伪元素压字，阴影本身能插值 */
	box-shadow: inset 0 -7px 10px -7px var(--panel-hi), inset 0 1px 0 var(--panel-hi), inset 0 -1px 0 var(--panel-ring);
}
/* 按下：下沉 1px 并收掉高光。位移只有 1px —— 纸上按印，不是弹簧 */
.btn:active:not(:disabled) {
	transform: translateY(1px);
	box-shadow: inset 0 1px 3px var(--panel-ring);
}
.btn-ink { background: var(--ink); border-color: var(--ink); color: var(--paper-hi); box-shadow: inset 0 1px 0 var(--panel-hi); }
.btn-ink:hover:not(:disabled) {
	background: var(--ink-lift);
	border-color: var(--ink-lift);
	color: var(--on-paper);
	box-shadow: inset 0 -8px 12px -8px var(--panel-hi), inset 0 1px 0 var(--panel-hi);
}
.btn-quiet { background: transparent; border-color: transparent; color: var(--ink-3); box-shadow: none; }
.btn-quiet:hover:not(:disabled) { background: var(--hover); border-color: transparent; box-shadow: none; }
.btn-quiet:active:not(:disabled) { background: var(--hover); box-shadow: none; }
.btn-seal { background: var(--cinnabar); border-color: var(--cinnabar); color: var(--on-cinnabar); box-shadow: inset 0 1px 0 var(--seal-edge); }
.btn-seal:hover:not(:disabled) { background: var(--cinnabar-lt); border-color: var(--cinnabar-lt); color: var(--on-cinnabar); box-shadow: inset 0 -8px 12px -8px var(--seal-edge), inset 0 1px 0 var(--seal-edge); }
.btn-sm { padding: 4px 11px; font-size: var(--fs-xs); }
.btn:disabled { opacity: 0.4; cursor: not-allowed; }
/* 危险动作：朱砂描边的空印，不填色 —— 填了就成了主按钮，权重会压过「保存」 */
.btn-danger { color: var(--cinnabar-ink); border-color: var(--cinnabar-edge); background: transparent; box-shadow: none; }
.btn-danger:hover:not(:disabled) { background: var(--cinnabar-wash); border-color: var(--cinnabar); color: var(--cinnabar-ink); box-shadow: inset 0 -7px 10px -7px var(--cinnabar-faint); }

.ink-btn {
	width: 100%;
	margin-top: 8px;
	padding: 8px;
	border: 1px dashed var(--rule-strong);
	border-radius: 4px;
	background: transparent;
	color: var(--ink-3);
	font-family: var(--kai);
	font-size: 13px;
	letter-spacing: 0.08em;
	cursor: pointer;
	transition: color var(--wash), border-color var(--wash), background var(--wash);
}
.ink-btn:hover { color: var(--cinnabar-ink); border-color: var(--cinnabar); background: var(--cinnabar-wash); }

/* ── 表单件 ──────────────────────────────────────────────── */

select, input, textarea {
	background: var(--paper-sunk);
	color: var(--ink);
	border: 1px solid var(--rule);
	border-radius: 4px;
	padding: 6px 9px;
	font-family: inherit;
	font-size: 12.5px;
	outline: none;
	transition: border-color var(--wash);
}
select:focus, input:focus, textarea:focus { border-color: var(--ink-3); }
select { max-width: 230px; cursor: pointer; }

.switch { display: inline-flex; align-items: center; gap: 8px; font-size: 12.5px; color: var(--ink-2); cursor: pointer; }
.switch input, .model-table input[type="checkbox"] { width: auto; margin: 0; accent-color: var(--cinnabar); }

.field { margin-bottom: 14px; }
.field > label { display: block; font-size: 11.5px; color: var(--ink-3); letter-spacing: 0.08em; margin-bottom: 5px; }
.field input, .field select, .field textarea { width: 100%; max-width: none; }
.field .hint { font-size: 11px; color: var(--ink-3); margin-top: 4px; line-height: 1.6; }
.field-row { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; }
/* 落盘失败横幅：唯一的"你的东西没存上"提示，用朱砂色把它从水墨里拎出来。 */
.storage-banner {
	grid-area: alert;
	display: flex;
	align-items: center;
	gap: 12px;
	padding: 8px 20px;
	background: var(--cinnabar-tint);
	border-bottom: 1px solid var(--cinnabar);
	color: var(--ink);
	font-size: 12.5px;
}
.storage-text { flex: 1; }
.hidden { display: none !important; }
.muted { color: var(--ink-3); }

/* ── 对话框 ──────────────────────────────────────────────── */

.sheet {
	border: 1px solid var(--rule-strong);
	border-radius: 6px;
	background: var(--paper);
	color: var(--ink);
	padding: 26px;
	width: min(520px, 92vw);
	box-shadow: 0 18px 50px var(--shadow);
}
.sheet::backdrop { background: var(--backdrop); backdrop-filter: blur(2px); }
.sheet h3 { margin: 0 0 20px; font-family: var(--kai); font-size: 20px; letter-spacing: 0.16em; font-weight: 600; }
.sheet label { display: block; margin-bottom: 14px; font-size: 12px; color: var(--ink-3); letter-spacing: 0.06em; }
.sheet input, .sheet textarea { display: block; width: 100%; margin-top: 6px; font-family: var(--serif); font-size: 14px; }
.dialog-actions { display: flex; justify-content: flex-end; gap: 9px; margin-top: 22px; }

/* ── 设置 ────────────────────────────────────────────────── */

.sheet-wide { width: min(1080px, 94vw); height: min(760px, 88vh); padding: 0; display: none; }
.sheet-wide[open] { display: flex; flex-direction: column; }

.settings-head {
	display: flex;
	align-items: flex-start;
	justify-content: space-between;
	gap: 16px;
	padding: 20px 24px 16px;
	border-bottom: 1px solid var(--rule);
	flex: none;
}
.settings-head h3 { margin: 0; font-size: 19px; font-family: var(--kai); letter-spacing: 0.1em; }
.settings-head p { margin: 4px 0 0; font-size: 11.5px; color: var(--ink-3); }

.settings-defaults {
	display: flex;
	gap: 22px;
	padding: 14px 24px;
	border-bottom: 1px solid var(--rule-soft);
	background: var(--scrim);
	flex: none;
}
.settings-defaults label { display: flex; align-items: center; gap: 10px; font-size: 12px; color: var(--ink-3); letter-spacing: 0.06em; }
.settings-defaults select { min-width: 250px; }

.settings-body { flex: 1; display: grid; grid-template-columns: 274px 1fr; min-height: 0; }

/* 左栏拆成「搜索框 + 列表」两截：搜索框不参与列表重渲染，否则每敲一个字就被重建一次。 */
.providers-rail { display: flex; flex-direction: column; min-height: 0; border-right: 1px solid var(--rule); }
.settings-providers {
	list-style: none;
	margin: 0;
	padding: 0 10px 10px;
	overflow-y: auto;
	flex: 1;
	min-height: 0;
	display: flex;
	flex-direction: column;
	gap: 2px;
}
.settings-providers .group-label { font-size: 10.5px; letter-spacing: 0.16em; color: var(--ink-3); padding: 12px 10px 5px; }

.provider-row {
	display: flex;
	align-items: center;
	gap: 8px;
	padding: 8px 10px;
	border-radius: 4px;
	cursor: pointer;
	transition: background var(--wash);
}
.provider-row:hover { background: var(--lift); }
.provider-row.is-on { background: var(--ink-wash); }
.provider-row.is-off { opacity: 0.48; }
.provider-row .name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 13px; }
.provider-row .badge {
	font-size: 10px;
	padding: 2px 6px;
	border-radius: 3px;
	background: var(--hover);
	color: var(--ink-3);
	white-space: nowrap;
	flex: none;
}
.provider-row .badge.ok { color: var(--moss); background: var(--moss-wash); }
.provider-row .badge.custom { color: var(--cinnabar-ink); background: var(--cinnabar-wash); }
.provider-row .badge.err-badge { color: var(--cinnabar-ink); background: var(--cinnabar-faint); }

.dot { width: 6px; height: 6px; border-radius: 50%; background: var(--ink-4); flex: none; }
.dot.on { background: var(--moss); }

.settings-detail { overflow-y: auto; padding: 22px 26px; min-width: 0; }
.settings-detail h4 { margin: 0 0 5px; font-family: var(--kai); font-size: 18px; font-weight: 600; letter-spacing: 0.06em; }
.settings-detail .sub { margin: 0 0 20px; font-size: 11.5px; color: var(--ink-3); line-height: 1.7; }
.settings-detail h5.detail-h { margin: 26px 0 4px; font-size: 10.5px; letter-spacing: 0.16em; color: var(--ink-3); font-weight: 600; }

.actions { display: flex; gap: 8px; flex-wrap: wrap; margin: 18px 0 4px; align-items: center; }
.actions .spacer { flex: 1; }

.notice {
	padding: 9px 12px;
	border-radius: 4px;
	font-size: 12px;
	line-height: 1.7;
	margin: 12px 0;
	border: 1px solid var(--rule);
	background: var(--lift-2);
	color: var(--ink-2);
	white-space: pre-wrap;
}
.notice.ok { color: var(--moss); border-color: var(--moss-edge); background: var(--moss-soft); }
.notice.err { color: var(--cinnabar-ink); border-color: var(--cinnabar-edge); background: var(--cinnabar-soft); }

.model-table { width: 100%; border-collapse: collapse; font-size: 12px; margin-top: 6px; }
.model-table th {
	text-align: left;
	font-weight: 500;
	font-size: 10.5px;
	letter-spacing: 0.1em;
	color: var(--ink-3);
	padding: 7px 8px;
	border-bottom: 1px solid var(--rule);
	white-space: nowrap;
}
.model-table td { padding: 6px 8px; border-bottom: 1px solid var(--rule-soft); vertical-align: middle; }
.model-table input[type="number"] { width: 100%; min-width: 78px; padding: 4px 6px; }
.model-table input[type="text"] { width: 100%; min-width: 110px; padding: 4px 6px; font-family: var(--mono); font-size: 11.5px; }
.model-table .levels { display: flex; gap: 3px; flex-wrap: wrap; }
.model-table .levels label {
	display: inline-flex;
	align-items: center;
	gap: 2px;
	font-size: 10.5px;
	color: var(--ink-3);
	padding: 2px 5px;
	border: 1px solid var(--rule);
	border-radius: 3px;
	cursor: pointer;
}
.model-table .levels input { width: auto; margin: 0; }
.model-table .levels .level-code { color: var(--ink-3); font-family: var(--mono); font-size: 9.5px; }
.model-table tr.is-default td { background: var(--cinnabar-tint); }
.model-id { font-family: var(--mono); font-size: 11.5px; }
.row-actions { display: flex; gap: 4px; justify-content: flex-end; }
.empty-hint { color: var(--ink-3); font-size: 12.5px; padding: 22px 0; text-align: center; font-family: var(--kai); line-height: 2; }

/* ── 响应式 ──────────────────────────────────────────────── */

@media (max-width: 1240px) {
	.desk { grid-template-columns: 240px minmax(0, 1fr); grid-template-areas: "beam beam" "alert alert" "rail stage"; }
	.desk.is-bench { grid-template-columns: 240px minmax(0, 1fr); }
	/* 右案改成抽屉：窄屏不能让它彻底消失 —— 大纲与待办还得够得着。 */
	.desk-right {
		position: fixed;
		top: 0;
		right: 0;
		bottom: 0;
		width: min(360px, 86vw);
		z-index: 60;
		display: flex;
		visibility: hidden;
		transform: translateX(102%);
		transition: transform var(--wash), visibility var(--wash);
		box-shadow: -12px 0 36px var(--shadow);
	}
	.desk.is-bible-open .desk-right { transform: none; visibility: visible; }
	.bible-backdrop { display: block; position: fixed; inset: 0; z-index: 59; border: 0; padding: 0; background: var(--backdrop); }
	.only-narrow { display: inline-flex !important; }
}

@media (max-width: 900px) {
	.desk {
		grid-template-columns: minmax(0, 1fr);
		grid-template-rows: 58px auto auto minmax(0, 1fr);
		grid-template-areas: "beam" "alert" "rail" "stage";
	}
	.rail { flex-direction: row; border-right: 0; border-bottom: 1px solid var(--rule); max-height: 152px; }
	.rail-block { flex: 1; min-width: 0; }
	.rail-block + .rail-block { border-top: 0; border-left: 1px solid var(--rule-soft); }
	/* 窄窗只收书名与统计，回案头的路不能一起收掉。 */
	.beam-mid { display: flex; flex: none; }
	.beam-mid .beam-title,
	.beam-mid .beam-stats { display: none; }
	.stream, .composer { padding-left: 20px; padding-right: 20px; }
	#view-manuscript { --ms-pad-t: 30px; --ms-pad-x: 20px; --ms-pad-b: 70px; }
	.settings-body { grid-template-columns: minmax(0, 1fr); }
	.providers-rail { display: none; }
	/* 屏幕窄下来后一栏只剩两百来像素，两列并排已读不下标题与用法，退回单列。 */
	.mat-grid { grid-template-columns: minmax(0, 1fr); }
	/* 触屏 / 窄窗没有 hover：动作条常显，否则装入、改、删根本点不到。 */
	.card.mat.is-peek .mat-actions { max-height: none; margin-top: 9px; opacity: 1; overflow: visible; }
}

@media (prefers-reduced-motion: reduce) {
	*, *::before, *::after { animation-duration: 0.01ms !important; transition-duration: 0.01ms !important; }
}

/* ── 供应商搜索与新增（内置厂商 41 个，没有搜索没法用） ── */

/* 搜索框现在在列表之外，本身不滚动，sticky 不再需要。 */
.search-wrap { padding: 12px 14px 8px; background: var(--paper-lo); flex: none; }
.provider-search { width: 100%; max-width: none; font-size: 12.5px; padding: 6px 9px; }
.provider-search::-webkit-search-cancel-button { cursor: pointer; }

.add-row { color: var(--cinnabar-ink); margin-top: 4px; }
.add-row .dot { background: transparent; border: 1px dashed var(--cinnabar); }
.add-row .name { color: var(--cinnabar-ink); font-family: var(--kai); }

.form-hint { margin: -8px 0 14px; font-size: 11px; color: var(--ink-3); line-height: 1.7; }
.form-error { margin: 0 0 4px; font-size: 12px; color: var(--cinnabar-ink); min-height: 1.2em; }
.checkline { display: flex !important; align-items: center; gap: 8px; font-size: 12.5px; color: var(--ink-2); }
.checkline input { width: auto; margin: 0; accent-color: var(--cinnabar); }


/* 仍是默认占位值的输入框：加一道虚线，提示需要人工核对 */
.model-table input.is-placeholder {
	border-style: dashed;
	color: var(--ink-3);
	background: transparent;
}
.model-table input.is-placeholder:focus {
	border-style: solid;
	color: var(--ink);
	background: var(--paper-hi);
}


/* ── 工作台（料 / 文）────────────────────────────────────── */
.view-bench { overflow: hidden; }

.bench {
	flex: 1;
	min-height: 0;
	display: grid;
	/* 左栏宽度由拖提手写下的 --bench-a 决定（见下面「分栏提手」一节）。
	   没拖过时退回 1fr，与原来的两等分一致；minmax(0, …) 不能省，
	   否则长 URL / 代码会把栅格顶爆。 */
	grid-template-columns: minmax(0, var(--bench-a, 1fr)) minmax(0, 1fr);
}
/* 案头是三栏：卷宗、通用素材库、库的设定官。工作台仍是两栏。
   必须写在 .bench 之后 —— 同特异性下后写者胜，放前面会被两栏盖掉。 */
.bench.bench-three { grid-template-columns: minmax(0, 1fr) minmax(0, 1.15fr) minmax(0, 1fr); }

/* 案头页脚：常驻一行小字，把源码在哪、许可是什么交代清楚。
   flex: none —— 三栏再挤也不许把它压掉；滚动留给上面的 .bench。 */
.bench-foot {
	flex: none;
	padding: 7px 18px calc(8px + var(--safe-b));
	border-top: 1px solid var(--rule);
}
.bench-foot-note {
	margin: 0;
	font-size: 11.5px;
	line-height: 1.65;
	color: var(--ink-3);
}
.bench-foot-link {
	color: inherit;
	text-decoration: underline;
	text-underline-offset: 2px;
	text-decoration-color: var(--rule);
}
.bench-foot-link:hover { color: var(--ink); text-decoration-color: currentColor; }
.bench-foot-note code { font-family: var(--mono); font-size: 11px; }
.bench-pane {
	min-width: 0;
	min-height: 0;
	display: flex;
	flex-direction: column;
	overflow: hidden;
	/* 容器查询的锚：这一栏有多宽，只有这里知道。
	   栏宽是拖提手拖出来的，视口宽度量不着它。
	   只含 inline-size（不含 paint），卡片浮起时的投影不会被裁掉。 */
	container-type: inline-size;
	container-name: pane;
}
.bench-pane + .bench-pane { border-left: 1px solid var(--rule); }
/* 左栏自己滚：上传区、素材库、装配清单都可能很长 */
.bench-pane:not(.bench-talk) { overflow-y: auto; padding: 0 20px 44px; }

/* ── 分栏提手：料 / 文两栏可拖宽窄 ─────────────────────────── */

/* 左栏占比记在 --bench-a 上；--bench-hit 是提手的命中宽度。
   两个都只是尺度，不随昼夜变，所以挂在这个选择器上，不进令牌块。
   26%–74% 的夹取在脚本里做；这里只负责把百分比变成栅格轨道。 */
.bench.has-split {
	position: relative;
	--bench-a: 50%;
	--bench-hit: 14px;
}

/* 提手插进两栏之间后，`.bench-pane + .bench-pane` 那条相邻分界线就不再命中，
   右边这栏的左边框得在这里补回来。第一条留着兜底：提手没插进来时仍然有分界。 */
.bench.has-split > .bench-pane + .bench-pane,
.bench.has-split > .bench-split + .bench-pane { border-left: 1px solid var(--rule); }

/* 提手绝对定位，压在原来那条 1px 分界线上，左右各探出半个命中区。
   它不占栅格轨道 —— 插成一个栅格项，两栏就成了三栏，右栏还会被挤掉一缝。 */
.bench-split {
	position: absolute;
	top: 0;
	bottom: 0;
	left: var(--bench-a, 50%);
	z-index: 4;
	width: var(--bench-hit);
	transform: translateX(-50%);
	display: flex;
	align-items: center;
	justify-content: center;
	cursor: col-resize;
	/* 平板上手势先到先得：不写这条，拖动会被滚动 / 双击缩放抢走 */
	touch-action: none;
	-webkit-tap-highlight-color: transparent;
	outline: none;
}

/* 界格：一条赭金细线，平时只比原有边框略亮一点 */
.bench-split::before {
	content: "";
	position: absolute;
	top: 0;
	bottom: 0;
	left: 50%;
	width: 1px;
	margin-left: -0.5px;
	background: var(--gold-line);
	opacity: 0.75;
	transition: width var(--brush), margin-left var(--brush), background var(--brush), opacity var(--brush);
}

/* 提手本身：2×14 的短竖条，像界格上一枚没写完的记号。
   外面套一圈纸色描边，压在正文或栏头上时也认得出边界。 */
.bench-split-grip {
	position: relative;
	width: 2px;
	height: 14px;
	border-radius: 1px;
	background: var(--gold-line);
	box-shadow: 0 0 0 2px var(--paper);
	transition: width var(--brush), height var(--brush), background var(--brush), box-shadow var(--brush);
}

/* 指向、键盘聚焦、拖动中：点成朱砂，线也加宽一档 —— 让「现在能扯」看得见 */
.bench-split:hover::before,
.bench-split:focus-visible::before,
.bench-split.is-dragging::before {
	width: 2px;
	margin-left: -1px;
	background: var(--cinnabar);
	opacity: 1;
}
.bench-split:hover .bench-split-grip,
.bench-split:focus-visible .bench-split-grip,
.bench-split.is-dragging .bench-split-grip {
	width: 3px;
	height: 20px;
	background: var(--cinnabar);
	box-shadow: 0 0 0 2px var(--paper), 0 0 10px var(--cinnabar-glow);
}
.bench-split:focus-visible {
	background: var(--cinnabar-wash);
	outline: 1px solid var(--cinnabar-edge);
	outline-offset: -1px;
}

/* 拖动时整页换成「左右拉」的指针，正文也不能被顺手选蓝 */
body.is-splitting,
body.is-splitting * {
	cursor: col-resize !important;
	user-select: none;
	-webkit-user-select: none;
}

/* 手指没有 1px 的精度：命中区撑到 24px，提手也大一号 */
@media (pointer: coarse) {
	.bench.has-split { --bench-hit: 24px; }
	.bench-split-grip { width: 3px; height: 22px; }
}

/* 栏窄了，内容自己换排法。栏宽是拖出来的，媒体查询量的是视口，
   量不到「这一栏只剩一百七十像素」—— 所以由脚本按实测宽度挂类。 */
.bench.has-split.is-a-narrow .bench-pane:not(.bench-talk) {
	padding-left: var(--sp-3);
	padding-right: var(--sp-3);
}
.bench.has-split.is-b-narrow .bench-talk .stream,
.bench.has-split.is-b-narrow .bench-talk .write-actions,
.bench.has-split.is-b-narrow .bench-talk .composer {
	padding-left: var(--sp-4);
	padding-right: var(--sp-4);
}
.bench.has-split.is-b-narrow .bench-talk .pane-head {
	padding-left: var(--sp-4);
	padding-right: var(--sp-4);
	/* 栏头是「题签 + 注 + 按钮」一行，窄到 26% 时宁可让按钮换行，也别挤出界 */
	flex-wrap: wrap;
}
.bench.has-split.is-b-narrow .picked-bar {
	margin-left: var(--sp-4);
	margin-right: var(--sp-4);
}

/* 窄栏里的长串：URL、代码、没有空格的英文名，不能把卡片与栅格顶爆。
   只收工作台两栏；案头三栏与右案保持原样。 */
.bench.has-split .mat-head h4,
.bench.has-split .mat-group-head h3,
.bench.has-split .card.mat .usage,
.bench.has-split .card.mat .mat-body,
.bench.has-split .chip,
.bench.has-split .tagline,
.bench.has-split .dropzone p,
.bench.has-split .upload-note,
.bench.has-split .upload-preview,
.bench.has-split .picked-chip,
.bench.has-split .thinking-body,
.bench.has-split .tool-preview { overflow-wrap: anywhere; }

/* ── 素材卡按栏宽排布 ────────────────────────────────────────
   素材卡不该一张占满整栏：栏里横向排两列，栏拉宽了排三列，
   窄到塞不下两张才收成一列。

   量的是「这一栏有多宽」，不是视口有多宽 —— 栏宽是拖提手拖出来的，
   媒体查询量不着它（同一节里 is-a-narrow 那些类就是干这事的）。
   这里用容器查询直接量：拖一下提手，卡片立刻重排，不用等脚本挂类。 */

@container pane (max-width: 299px) {
	/* 两张卡并排至少要 ~150px 一张，再窄就一张一行吧。 */
	.mat-grid { grid-template-columns: minmax(0, 1fr); }
}

@container pane (min-width: 300px) {
	/* 两列是常态。手机上一栏铺满，容器查询照样管到 ——
	   媒体查询那条「窄屏一列」写在前面，这里按栏宽把它顶回去。 */
	.mat-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@container pane (min-width: 560px) {
	.mat-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}

/* 网格里的卡要有个「张」的形：单列时它是一条横线，两三列并排时
   若还只是一条线，卡与卡之间没有界，看着像没排完。 */
.mat-grid > .card.mat {
	padding: 12px 13px 13px;
	border: 1px solid var(--rule-soft);
	border-radius: var(--r-2);
}

/* 卡一窄，字就得收一收：不然标题挤成两行、用得住的小字断成三截。 */
@container pane (max-width: 430px) {
	.mat-grid > .card.mat { padding: 10px 11px 11px; }
	.mat-grid > .card.mat h4 { font-size: 14px; }
	.card.mat .usage { font-size: 12px; }
	.card.mat .mat-body { font-size: 13px; }
}

.pane-head {
	flex: none;
	display: flex;
	align-items: baseline;
	gap: 10px;
	padding: 18px 0 8px;
	position: sticky;
	top: 0;
	z-index: 2;
	background: linear-gradient(180deg, var(--paper) 76%, transparent);
}
/* 角花：两道 L 形赭金细线压在面板头的空白处，像装裱的界格。
   没有 ::after 可用（那是标题右边那条渐隐线），所以两个角用同一个伪元素
   的四层背景拼出来：横 9px、竖 9px，各两份，左上与右下。
   绝对定位 + pointer-events:none，不参与布局，也不挡点。 */
.pane-head::before {
	content: "";
	position: absolute;
	left: 0;
	right: 0;
	top: 6px;
	bottom: 2px;
	pointer-events: none;
	background-image:
		linear-gradient(var(--gold-line), var(--gold-line)),
		linear-gradient(var(--gold-line), var(--gold-line)),
		linear-gradient(var(--gold-line), var(--gold-line)),
		linear-gradient(var(--gold-line), var(--gold-line));
	background-size: 9px 1px, 1px 9px, 9px 1px, 1px 9px;
	background-position: left top, left top, right bottom, right bottom;
	background-repeat: no-repeat;
	opacity: 0.55;
}
/* 题签：楷体 + 字距，左首一枚朱砂小印。字号与原来一致，只换气质 */
.pane-head h3 {
	margin: 0;
	padding-left: 11px;
	position: relative;
	font-family: var(--kai);
	font-size: var(--fs-md);
	font-weight: 600;
	letter-spacing: 0.1em;
	color: var(--ink);
	/* 多出的 11px 会让长标题在窄栏里折行、把栏头撑高 —— 宁可让右边那条线缩没 */
	white-space: nowrap;
}
.pane-head h3::before {
	content: "";
	position: absolute;
	left: 1px;
	top: 0.42em;
	width: 3px;
	height: 3px;
	background: var(--cinnabar);
	/* 3px 的方印在 14px 字旁几乎看不见，补一圈同色淡晕把它坐住 */
	box-shadow: 0 0 0 1px var(--cinnabar-faint);
}
/* 从题签向右淡出的那条线：实线会把标题和工具条切成两半 */
.pane-head::after {
	content: "";
	flex: 1;
	height: 1px;
	align-self: center;
	background: linear-gradient(90deg, var(--rule) 0%, var(--rule-soft) 46%, transparent 100%);
}
/* 数量徽标当小方印：朱砂描边 + 楷体数字，空的时候整枚不出现 */
.pane-count {
	flex: none;
	font-family: var(--kai);
	font-size: var(--fs-xs);
	color: var(--cinnabar-ink);
	padding: 1px 5px;
	border: 1px solid var(--cinnabar-edge);
	border-radius: 2px;
	background: var(--cinnabar-soft);
	line-height: 1.5;
	font-variant-numeric: tabular-nums;
	letter-spacing: 0.02em;
}
/* 栏头的小签：淡茶褐，比徽标轻，只做说明 */
.pane-note {
	flex: 0 1 auto;
	min-width: 0;
	font-size: var(--fs-xs);
	color: var(--tea);
	padding: 1px 6px;
	border-radius: 2px;
	background: var(--tea-wash);
	box-shadow: inset 0 0 0 1px var(--tea-edge);
	white-space: nowrap;
	overflow: hidden;
	text-overflow: ellipsis;
}
/* 空元素不能留下一枚空印或一块空签 */
.pane-count:empty, .pane-note:empty { display: none; }
.pane-tools { flex: none; align-self: center; }

.bench-talk .pane-head {
	padding: 18px 26px 11px;
	justify-content: space-between;
	background: none;
	border-bottom: 1px solid var(--rule-soft);
}
.bench-talk .pane-head::after { display: none; }

.bench-empty {
	padding: 20px 2px;
	font-family: var(--serif);
	font-size: 13px;
	line-height: 1.95;
	color: var(--ink-3);
	white-space: pre-wrap;
}

/* ── 存照 ──────────────────────────────────────────────────── */

.snap-list {
	max-height: 52vh;
	overflow-y: auto;
	border-top: 1px solid var(--rule);
	border-bottom: 1px solid var(--rule);
	padding: 4px 0;
}
.snap-row {
	display: flex;
	align-items: center;
	gap: 12px;
	padding: 9px 2px;
	border-bottom: 1px dashed var(--rule);
}
.snap-row:last-child { border-bottom: 0; }
.snap-main { flex: 1; min-width: 0; }
.snap-when {
	font-family: var(--mono);
	font-size: 12.5px;
	color: var(--ink-2);
}
.snap-why {
	font-family: var(--kai);
	font-size: 12px;
	color: var(--ink-3);
	margin-top: 1px;
}
.snap-size {
	font-family: var(--mono);
	font-size: 11px;
	color: var(--ink-3);
	flex: none;
}

/* 存照对话框：条目少时贴着内容，多起来才由列表内部滚动。
   必须用 fit-content 而不是 auto —— <dialog> 处在 .sheet-wide[open] 的 flex 容器里，
   height:auto 会被解析成整屏高，内容全挤在顶上。 */
.snap-list { flex: none; }
#snapshot-dialog { height: fit-content; max-height: min(760px, 86vh); }

/* ── 上传原料 ────────────────────────────────────────────── */

.dropzone {
	margin-top: 2px;
	padding: 22px 14px;
	border: 1px dashed var(--rule-strong);
	border-radius: 4px;
	text-align: center;
	cursor: pointer;
	transition: background var(--wash), border-color var(--wash);
}
.dropzone p { margin: 0; font-family: var(--kai); font-size: 13px; color: var(--ink-3); letter-spacing: 0.06em; }
.dropzone .dropzone-hint { margin-top: 6px; font-family: var(--serif); font-size: 11px; color: var(--ink-3); letter-spacing: 0; }
.dropzone:hover, .dropzone.is-over { border-color: var(--cinnabar); background: var(--cinnabar-wash); }

.upload-list { list-style: none; margin: 12px 0 0; padding: 0; display: flex; flex-direction: column; gap: 10px; }
.upload-item {
	padding: 10px 12px;
	border: 1px solid var(--rule-soft);
	border-left: 2px solid var(--ink-4);
	border-radius: 3px;
	background: var(--paper-hi);
}
.upload-item.is-error { border-left-color: var(--cinnabar); }
.upload-head { display: flex; align-items: baseline; gap: 8px; }
.upload-name {
	flex: 1;
	min-width: 0;
	font-family: var(--serif);
	font-size: 13px;
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
}
.upload-state { flex: none; font-size: 11px; color: var(--ink-3); font-variant-numeric: tabular-nums; }
.upload-note { margin-top: 5px; font-size: 11px; line-height: 1.7; color: var(--ink-3); }
.upload-note.warn { color: var(--cinnabar-ink); }
.upload-preview {
	margin-top: 5px;
	font-family: var(--song);
	font-size: 11.5px;
	line-height: 1.7;
	color: var(--ink-3);
	display: -webkit-box;
	-webkit-line-clamp: 2;
	-webkit-box-orient: vertical;
	overflow: hidden;
}
.upload-actions { display: flex; gap: 4px; margin-top: 9px; flex-wrap: wrap; }

/* 库面板的原料列表：栏窄、且夹在对话与输入框之间，所以压紧一档。
   它自己滚动，不把设定官的对话区挤没。 */
.upload-list.compact {
	margin: 0;
	padding: 8px 20px;
	gap: 6px;
	max-height: 168px;
	overflow-y: auto;
	border-top: 1px solid var(--rule-soft);
	flex: none;
}
.upload-list.compact .upload-item { padding: 6px 9px; }
.upload-list.compact .upload-preview { -webkit-line-clamp: 1; }
.upload-list.compact .upload-actions { margin-top: 6px; }
.upload-list.compact:empty { display: none; }

/* 拖资料到设定官面板上的落点提示。 */
.bench-pane.is-over { background: var(--cinnabar-wash); }
/* ── 素材与装配清单 ──────────────────────────────────────── */

.material-list, .assembly-list, .pool-list { display: flex; flex-direction: column; }

/* 库空着的时候这一栏只有一句话，底下压着六七百像素的纸。
   让那句话落在这段空白的中线上 —— 空得像留白，而不是像没加载完。
   空着也把「裱纸」的那圈内框去掉（style.css 书斋层给 .material-list 的
   inset 1px），否则撑满整栏之后就是一个装空气的巨大空框。
   还是 auto 外边距：内容一高就退成 0，不会裁掉顶。 */
.bench-pane > .material-list:has(> .bench-empty:only-child) { flex: 1; min-height: 0; box-shadow: none; }
/* 这一句落到了这一栏的中线上，底下那痕远山就会悬在半空；
   它本来是该压在文字脚下的。空着的时候不要山，只要一句干净的话。 */
.bench-pane > .material-list > .bench-empty:only-child { margin-block: auto; background-image: none; }

/* 标题先给足一整行：flex-basis 用 auto（按内容宽）而不是 0 —— 标题放不下时，
   种类徽章自己折到下一行，标题就不会被挤成「末行只剩一个字」。
   徽章靠 margin-left: auto 钉右首，折下来也还在右首。 */
.mat-head { display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap; }
.mat-head h4 { flex: 1 1 auto; min-width: 0; text-wrap: balance; }
.mat-actions { display: flex; gap: 4px; margin-top: 9px; flex-wrap: wrap; }

.btn-xs { padding: 2px 9px; font-size: 11.5px; border-radius: 3px; }
.btn-quiet.is-danger { color: var(--cinnabar-ink); border-color: var(--cinnabar-edge); }
.btn-quiet.is-danger:hover:not(:disabled) { background: var(--cinnabar-wash); }

.card.mat.is-compact { cursor: pointer; transition: color var(--wash); }
.card.mat.is-compact:hover h4 { color: var(--cinnabar-ink); }

/* 写作作业条：选章 → 定写法 → 落笔。
   它挂在执笔者栏、紧贴输入框之上 —— 眼睛在看这一栏，手就不该跑回左栏按按钮。
   上下用细线跟对议区分开，但它自己不能撑高也不能缩：写在流里，栏矮时先压对话区。 */
.write-actions {
	display: flex;
	align-items: center;
	gap: 8px;
	flex-wrap: wrap;
	flex: none;
	margin: 0;
	padding: 10px 26px;
	border-top: 1px solid var(--rule-soft);
}
.chapter-select {
	/* 「第3章 · 核载二十人（已成稿）」这种长度，给个上限免得把写法挤下去 */
	max-width: 22em;
}
.mode-select {
	padding: 5px 8px;
	border: 1px solid var(--rule);
	border-radius: 3px;
	background: var(--paper-hi);
	color: var(--ink-2);
	font-family: inherit;
	font-size: 12px;
	cursor: pointer;
}
.actions-note { font-size: 11px; color: var(--ink-3); }

/* ── 工作台里的对议栏 ────────────────────────────────────── */

.bench-talk .stream { padding: 22px 26px 8px; gap: 20px; }
.bench-talk .composer { padding: 12px 26px 18px; }
.bench-talk .composer textarea { min-height: 56px; font-size: 14px; }
/* 46em 是舒适阅读宽，但栏被拖窄时它不能大过栏本身，否则正文会横向溢出 */
.bench-talk .msg, .bench-talk .msg-foot { max-width: min(46em, 100%); }
.bench-talk .msg.assistant .msg-body { font-size: 15px; line-height: 1.95; }

/* 开席之前：三块对议栏里一个字都没有，只剩一片约七百像素的白。
   「料」「文」两席进书时会收到一句招呼话（app.js 的 appendMessage），
   「库」这一席没有，于是案头右栏一直空着 —— 这就是那块空白的来历。
   流的子节点为空只发生在一种时候：还没说过话、也没在生成，正好是该给一句话的时候。
   话放在样式里而不是 DOM 里：mountStream 会用快照覆盖 box.innerHTML，
   塞进去的元素第一次挂载就被抹掉；::before 不占快照，也不进对话记录。 */
.bench-talk .stream:empty::before {
	display: block;
	max-width: 27em;
	/* auto 外边距把这句话按到这一栏的中线上，而不是贴在上面留底下六百像素的纸。
	   用 auto 而不是 justify-content: center —— 内容长过栏高时 auto 退成 0，
	   照常从顶上流下来；center 会把开头裁出可见区。 */
	margin: auto;
	font-family: var(--kai);
	font-size: 14px;
	line-height: 2.15;
	letter-spacing: 0.06em;
	color: var(--ink-3);
	white-space: pre-wrap;
	text-align: left;
}
#library-stream:empty::before {
	content: "还没有一席。\A这里是案头的设定官：备通用素材，不写正文。\A把一个题材、一类人物、一种世界观交代下来，就成了下一部书的底子。";
}
#material-stream:empty::before {
	content: "还没有一席。\A上传资料，或直接交代要立什么设定 —— 素材是一切之先。";
}
#writing-stream:empty::before {
	content: "还没有一席。\A在左栏装配本章素材，或直接交代这一章要写什么。";
}

.actions-center { justify-content: center; padding: 18px 0 0; margin: 0; }
/* 章节操作条钉在稿台顶部，排在正文之前。
   写作时手要够得着「存稿」，不该被一整章的篇幅压在底下；
   底色必须不透明，否则滚过去的正文会从按钮缝里透出来。

   正文滚到条子下缘就该消失，不再往上钻到最顶 —— 所以这里要三件事：
   ① 纸面实心；② 条子一路盖到滚动口上沿（top:0，不留缝）；③ 下缘用同色投影化开，
   让正文是「淡出」而不是被刀切。 */
#view-manuscript .actions-center {
	position: sticky;
	/* 停在滚动口最上沿。以前是 -ms-pad-t，等于允许条子自己往上缩一截，按钮会被切。 */
	top: 0;
	/* 层级必须显式写。操作条排在稿纸前面，而稿纸带着 fade 动画（动画的 opacity 让 .ms-page
	   自己也成了一个层叠上下文，跟 z-index:0 的元素画在同一层）—— 只给定位不给层级，
	   正文会按文档顺序画到条子上面去，这正是之前正文盖住按钮的原因。 */
	z-index: 2;
	/* 上边不留负外边距了：滚动容器已经没有 top padding，条子的自然位置就是台口。
	   只保留左右出血（让它横贯整个滚动口）与下沿的 18px —— 那 18px 是给投影的
	   淡出段落的，不是缝。 */
	margin: 0 calc(var(--ms-pad-x) * -1) 18px;
	/* 上 6px 是按钮与台口之间的全部间距，再小按钮就贴死在横线上了。 */
	padding: 6px var(--ms-pad-x) 14px;
	/* 底色要和台面咬合。台面是「纸 + 顶上一道天光」（.stage 的 --sheen），
	   只铺 --paper 会在台口留下一道比四周暗的横带；照抄同一层天光就接上了。 */
	background: var(--sheen), var(--paper);
	/* 投影是同色纸，不是墨：滚上来的正文在这十几像素里渐隐。 */
	box-shadow: 0 14px 16px -8px var(--paper);
}
.form-row { display: grid; grid-template-columns: 148px minmax(0, 1fr); gap: 12px; }

@media (max-width: 1180px) {
	.bench { grid-template-columns: minmax(0, 1fr); grid-template-rows: minmax(0, 1fr) minmax(0, 1fr); }
	/* 案头那三栏也要跟着堆叠：.bench-three 特异性更高，不显式写会把它顶掉，
	   结果窄屏下三栏继续并排，每栏只剩一百来像素。 */
	.bench.bench-three { grid-template-columns: minmax(0, 1fr); grid-template-rows: minmax(0, 1fr) minmax(0, 1fr) minmax(0, 1fr); }
	.bench-pane + .bench-pane { border-left: 0; border-top: 1px solid var(--rule); }
	/* 堆叠成一列后没有左右可拖，提手收掉。这一节在「分栏提手」之后，
	   同特异性下后写者胜，能盖掉前面 .bench-split 的 display:flex。 */
	.bench-split { display: none; }
	/* 提手夹在两栏之间，相邻选择器断了一环，横的分界线得单独补回来 */
	.bench.has-split > .bench-split + .bench-pane { border-left: 0; border-top: 1px solid var(--rule); }
	.desk.is-bench { grid-template-columns: minmax(0, 1fr); grid-template-areas: "beam" "alert" "stage"; }
	.desk.is-bench .rail { display: none; }
}

/* ── 素材表单（三段式：固定头 + 滚动体 + 固定脚）───────────── */

/* 比设置页窄：正文一行太长不好读 */
.sheet-form { width: min(880px, 94vw); height: min(820px, 90vh); overflow: hidden; }
.sheet-form form { flex: 1; min-height: 0; display: flex; flex-direction: column; }

.sheet-form .form-head {
	flex: none;
	padding: 22px 28px 16px;
	border-bottom: 1px solid var(--rule);
}
.sheet-form .form-head h3 { margin: 0; }
/* 全局的 .form-hint 带 -8px 上边距（为紧贴供应商表单的控件而设），
   在这里会把提示压到上一个控件上，所以就地压回正常边距。 */
.sheet-form .form-hint { margin: 7px 0 0; }
.sheet-form .form-hint:empty { display: none; }

.sheet-form .form-body {
	flex: 1;
	min-height: 0;
	overflow-y: auto;
	display: flex;
	flex-direction: column;
	padding: 20px 28px 16px;
}

.sheet-form .form-foot {
	flex: none;
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 16px;
	padding: 14px 28px 18px;
	border-top: 1px solid var(--rule-soft);
	background: var(--shade);
}
.sheet-form .form-foot .form-error { margin: 0; }
.sheet-form .form-foot .dialog-actions { margin-top: 0; }

/* 字段：标签 / 控件 / 说明 三段纵向排 */
.sheet-form .field { display: block; margin-bottom: 16px; }
.sheet-form .field-label {
	display: block;
	font-size: 12px;
	color: var(--ink-3);
	letter-spacing: 0.06em;
}
.sheet-form .field-label em {
	font-style: normal;
	font-family: var(--sans);
	font-size: 10.5px;
	color: var(--ink-3);
	margin-left: 6px;
	letter-spacing: 0.04em;
}
/* 控件统一 14px：全局 select 是 12.5px，混在一行里会显得矮一头 */
.sheet-form .field > input,
.sheet-form .field > select,
.sheet-form .field > textarea {
	margin-top: 6px;
	font-size: 14px;
}
.sheet-form select { width: 100%; max-width: none; }
.sheet-form .field-note {
	display: block;
	margin-top: 6px;
	font-size: 11px;
	line-height: 1.7;
	color: var(--ink-3);
}

.sheet-form .form-row { display: grid; grid-template-columns: 152px minmax(0, 1fr); gap: 14px; }

/* 内容吃掉剩余高度：常见篇幅下不用滚外框就能看到整段 */
.sheet-form .field-grow {
	flex: 1;
	min-height: 220px;
	display: flex;
	flex-direction: column;
	margin-bottom: 0;
}
.sheet-form .field-grow > textarea { flex: 1; min-height: 0; resize: none; line-height: 1.85; }

/* 视口窄时（对话窗跟着变窄）字段改为堆叠，两列会挤得读不出标题 */
@media (max-width: 780px) {
	.sheet-form .form-row { grid-template-columns: minmax(0, 1fr); gap: 0; }
}

/* ── 卷宗与通用素材库（案）───────────────────────────────── */

.pane-lead {
	margin: 0 0 2px;
	font-family: var(--serif);
	font-size: 12px;
	line-height: 1.85;
	color: var(--ink-3);
}

.record-list { display: flex; flex-direction: column; }

.card.record { padding: 14px 12px; border-bottom: 1px solid var(--rule-soft); border-radius: 3px; }
.card.record.is-on { background: var(--ink-wash); box-shadow: inset 2px 0 0 var(--cinnabar); }
.record-head { display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap; }
.card.record h4 { margin: 0; font-family: var(--kai); font-size: 16px; font-weight: 600; letter-spacing: 0.04em; }
.card.record .tagline { font-size: 11.5px; color: var(--ink-3); margin-top: 5px; line-height: 1.7; }
.card.record .tagline + .tagline { color: var(--ink-3); }

/* ── 新建作品时的库勾选 ──────────────────────────────────── */

.pick-count { margin-left: 6px; font-family: var(--sans); font-size: 10.5px; color: var(--cinnabar-ink); letter-spacing: 0; }

.pick-search { margin-top: 6px; }

.library-pick {
	flex: 1;
	min-height: 0;
	margin-top: 8px;
	border: 1px solid var(--rule-soft);
	border-radius: 4px;
	background: var(--paper-hi);
	overflow-y: auto;
}

.pick-row {
	display: flex !important;
	align-items: flex-start;
	gap: 9px;
	margin: 0 !important;
	padding: 9px 12px;
	border-bottom: 1px solid var(--rule-soft);
	cursor: pointer;
	letter-spacing: 0 !important;
}
.pick-row:last-child { border-bottom: 0; }
.pick-row:hover { background: var(--lift-2); }
.pick-row.is-on { background: var(--cinnabar-wash); }
.pick-row input {
	width: auto !important;
	max-width: none;
	margin: 3px 0 0 !important;
	accent-color: var(--cinnabar);
	flex: none;
}
.pick-body { flex: 1; min-width: 0; }
.pick-title { display: flex; align-items: baseline; gap: 7px; }
.pick-title .kind {
	flex: none;
	font-family: var(--sans);
	font-size: 10px;
	color: var(--ink-3);
	border: 1px solid var(--rule-soft);
	border-radius: 2px;
	padding: 0 4px;
}
.pick-title > span:last-child { font-family: var(--serif); font-size: 13.5px; color: var(--ink); }
.pick-usage { margin-top: 3px; font-size: 11px; line-height: 1.65; color: var(--ink-3); }

/* ── 存入素材库 ──────────────────────────────────────────── */

/* 这张表单短，不用撑满，但仍沿用三段式骨架 */
.sheet-form.promote { width: min(520px, 92vw); height: auto; max-height: min(660px, 88vh); }

/*
 * 只读弹层：读素材全文用。
 * 高度自适应而不是撑满，短素材不必开一张空荡荡的大纸。
 */
.sheet-read {
	width: min(720px, 92vw);
	height: auto;
	max-height: min(760px, 86vh);
}
.sheet-read .form-body { padding: 0 30px 26px; overflow: auto; }
.sheet-read .form-head { padding: 26px 30px 14px; }
.sheet-read .view-usage {
	margin: 0 0 16px;
	padding: 10px 12px;
	font-size: 12.5px;
	line-height: 1.8;
	color: var(--ink-3);
	background: var(--ink-wash);
	border-left: 2px solid var(--cinnabar-edge);
	border-radius: 2px;
}
.sheet-read .view-body {
	font-family: var(--song);
	font-size: 14.5px;
	line-height: 2.05;
	color: var(--ink-2);
	white-space: pre-wrap;
}
.sheet-read .form-foot { padding: 0 30px 22px; justify-content: flex-end; }

.promote-modes { margin-top: 4px; }
.promote-group { display: flex; flex-direction: column; gap: 2px; }
.promote-option {
	display: flex !important;
	align-items: center;
	gap: 9px;
	margin: 0 !important;
	padding: 9px 11px;
	border: 1px solid var(--rule-soft);
	border-radius: 3px;
	cursor: pointer;
	letter-spacing: 0 !important;
	font-size: 13px !important;
	color: var(--ink-2) !important;
}
.promote-option:hover { border-color: var(--ink-4); }
.promote-option:has(input:checked) { background: var(--cinnabar-wash); border-color: var(--cinnabar); }
.promote-option input {
	width: auto !important;
	max-width: none;
	margin: 0 !important;
	accent-color: var(--cinnabar);
	flex: none;
}

/* ── 「更多设置」折叠块 ───────────────────────────────────── */

/* 另起一卷只需要书名。骨相、字数、规约收起来，需要时再展开 */
.sheet-form .form-more { margin-bottom: 16px; }
.sheet-form .form-more > summary {
	display: flex;
	align-items: baseline;
	gap: 8px;
	padding: 9px 0;
	cursor: pointer;
	font-size: 12px;
	color: var(--ink-3);
	letter-spacing: 0.06em;
	list-style: none;
	transition: color var(--wash);
}
.sheet-form .form-more > summary::-webkit-details-marker { display: none; }
.sheet-form .form-more > summary::before {
	content: "＋";
	flex: none;
	font-family: var(--sans);
	color: var(--ink-3);
}
.sheet-form .form-more[open] > summary::before { content: "－"; }
.sheet-form .form-more > summary:hover { color: var(--ink); }
.sheet-form .form-more > summary em {
	font-style: normal;
	font-size: 11px;
	color: var(--ink-3);
	letter-spacing: 0;
}
.sheet-form .form-more[open] > summary {
	margin-bottom: 14px;
	border-bottom: 1px solid var(--rule-soft);
}

/* 提示条可以点掉：它有时很长，挡着下面的模型表 */
.notice { cursor: pointer; }

/* 素材工作台：点选若干条，再交代怎么改 */
.picked-bar {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: 6px;
	margin: 0 26px 8px;
	padding: 8px 11px;
	background: var(--cinnabar-wash);
	border: 1px solid var(--rule);
	border-radius: 3px;
}
.picked-label { font-family: var(--kai); font-size: 12.5px; color: var(--ink-2); letter-spacing: 0.04em; }
.picked-chip {
	font-family: var(--serif);
	font-size: 12px;
	color: var(--ink-2);
	background: var(--focus-paper);
	border: 1px solid var(--rule);
	border-radius: 2px;
	padding: 1px 7px;
}
.picked-bar .btn { margin-left: auto; }
.btn-quiet.is-on { color: var(--cinnabar-ink); border-color: var(--cinnabar); background: var(--cinnabar-wash); }
.card.mat.is-picked { background: var(--ink-wash); box-shadow: inset 2px 0 0 var(--cinnabar); }

/* 立一章：章节是装料的落点，没有章就看不了也装不了料 */
.rail-add {
	flex: none;
	margin: 0 6px 10px;
	padding: 5px 9px;
	border: 1px dashed var(--rule);
	border-radius: 3px;
	background: none;
	color: var(--ink-3);
	font-family: var(--kai);
	font-size: 12.5px;
	letter-spacing: 0.04em;
	cursor: pointer;
}
.rail-add:hover { color: var(--cinnabar-ink); border-color: var(--cinnabar); background: var(--cinnabar-wash); }
/* 装配区的立章按钮：居中，别贴着空状态文案 */
.bench-empty + .btn { display: table; margin: 14px auto 0; }
.bench-hint {
	margin: 0 0 10px;
	font-family: var(--kai);
	font-size: 12.5px;
	color: var(--ink-3);
	letter-spacing: 0.04em;
}
.btn:disabled { opacity: 0.4; cursor: not-allowed; }
.btn:disabled:hover { color: var(--ink-3); border-color: var(--rule); background: none; }

/* ── 昼夜开关 ─────────────────────────────────────────────
   图元不用图片：一枚日头与一弯月牙，靠 background 拼出来。
   切换时整枚缓慢自转，像天光流转。 */
.theme-toggle {
	display: inline-grid;
	place-items: center;
	width: 34px;
	height: 30px;
	padding: 0;
}
.theme-glyph {
	position: relative;
	width: 15px;
	height: 15px;
	border-radius: 50%;
	background: var(--ink-3);
	transition: background var(--wash), box-shadow var(--wash), transform 520ms cubic-bezier(0.22, 0.61, 0.36, 1);
}
/* 亮色下是日头：加一圈晕，说明「现在是白天」 */
:root[data-theme="light"] .theme-glyph {
	box-shadow: 0 0 0 3px var(--cinnabar-wash);
}
/* 暗色下是月牙：用一个纸色圆压出弯月 */
:root[data-theme="dark"] .theme-glyph {
	transform: rotate(-35deg);
	background: var(--ink-2);
}
:root[data-theme="dark"] .theme-glyph::after {
	content: "";
	position: absolute;
	inset: -1px -1px -1px 42%;
	border-radius: 50%;
	background: var(--paper);
}
.theme-toggle:hover .theme-glyph { background: var(--ink-2); }

/* ── 打磨 ────────────────────────────────────────────────── */

/* 交互元素给一条缓动，鼠标扫过列表时不至于像在跳 */
.project-item,
.chapter-item,
.tab,
.btn,
.chip,
.card.mat {
	transition: background var(--wash), border-color var(--wash), color var(--wash), box-shadow var(--wash), transform var(--wash);
}

/* 卡片浮起一点点：只是提示可点，不要动到布局 */
.card.record:hover,
.card.mat:hover {
	box-shadow: 0 2px 10px var(--shadow);
}

/* 工作台里的素材卡整张可点可拖，悬停时再明确一点：抬起、描朱砂边、显动作条 */
.card.mat.is-peek {
	cursor: pointer;
	position: relative;
}
.card.mat.is-peek:hover {
	transform: translateY(-2px);
	box-shadow: 0 4px 16px var(--shadow);
	border-color: var(--cinnabar-edge);
}
.card.mat.is-peek:hover h4 { color: var(--cinnabar-ink); }

/*
 * 动作条平时不占位，悬停或键盘焦点落在卡内时才显出来。
 * 两列并排时半宽卡片塞六个按钮会撑成三行，把网格拉得参差；
 * 收起来后卡片只剩标题、用法与元信息，行高才齐。
 */
.card.mat.is-peek .mat-actions {
	max-height: 0;
	margin-top: 0;
	overflow: hidden;
	opacity: 0;
	transition: max-height var(--wash), margin-top var(--wash), opacity var(--wash);
}
.card.mat.is-peek:hover .mat-actions,
.card.mat.is-peek:focus-within .mat-actions {
	max-height: 80px;
	margin-top: 9px;
	opacity: 1;
}

/* 拖起来的那张淡下去，让落点更清楚 */
.card.mat.is-dragging {
	opacity: 0.45;
	transform: none;
}

/* 落区：拖到设定官那一栏时整栏描边，并压一句提示 */
/* 拖放落区：设定官整栏、执笔者的输入框，两处同一套观感 */
#material-drop,
#writing-composer { position: relative; }

#material-drop.is-over,
#writing-composer.is-over {
	outline: 2px dashed var(--cinnabar-edge);
	outline-offset: -6px;
	background: var(--cinnabar-wash);
}

.drop-hint {
	position: absolute;
	top: 8px;
	left: 0;
	right: 0;
	margin: 0;
	text-align: center;
	font-family: var(--kai);
	font-size: 13px;
	letter-spacing: 0.12em;
	color: var(--cinnabar-ink);
	pointer-events: none;
	z-index: 3;
}
/* 设定官那栏的提示压在栏头下方，别和标题挤在一起 */
#material-drop > .drop-hint { top: 46px; }

/* 键盘走到哪，得看得见 */
.theme-toggle:focus-visible,
.tab:focus-visible,
.chip:focus-visible,
.rail-add:focus-visible,
.chapter-item:focus-visible {
	outline: 3px solid var(--cinnabar);
	outline-offset: 2px;
	border-radius: var(--r-1);
}

/* 正文与小字在暗底上略微提亮：夜里读长文全靠它 */
:root[data-theme="dark"] .bench-empty,
:root[data-theme="dark"] .rail-note,
:root[data-theme="dark"] .pane-lead { color: var(--ink-2); }

/* 纸纤维跟着主题换叠色（见 :root 的 --fiber-blend），强度已调低 */

/* 尊重系统的「减少动态效果」：动画一律收到最小。
   新加的墨晕、骨架流光、稿纸淡入也一并收掉 —— 这条兜底是给所有人的，
   不只是给那几个老动画的。 */
@media (prefers-reduced-motion: reduce) {
	*,
	*::before,
	*::after {
		animation-duration: 0.01ms !important;
		animation-iteration-count: 1 !important;
		transition-duration: 0.01ms !important;
		scroll-behavior: auto !important;
	}
	.desk { animation: none; }
	.skeleton,
	.sk-line,
	.ms-page,
	.front-matter,
	.toast {
		animation: none !important;
	}
	/* 静态的骨架不带流光也只留底噪，但不能再有「光」定在某处不动 */
	.skeleton,
	.sk-line {
		background-image: none !important;
	}
	.btn:active:not(:disabled) { transform: none; }
}

/* ══════════════════════════════════════════════════════════════
   体验层：检索、提示、版本、排版、专注、抽屉与等待态
   ══════════════════════════════════════════════════════════════ */

/* ── 触屏与窄窗的通用开关 ─────────────────────────────────── */
.only-narrow { display: none; }

/* ── 顶栏检索与快捷键提示 ─────────────────────────────────── */
.beam-search {
	display: inline-flex;
	align-items: center;
	gap: 7px;
	color: var(--ink-3);
}
.beam-search:hover { color: var(--ink); }
.beam-search-glyph {
	display: none;
	font-family: var(--kai);
	font-size: 13px;
	letter-spacing: 0.04em;
}
.beam-kbd,
kbd {
	font-family: var(--mono);
	font-size: 10px;
	line-height: 1;
	padding: 3px 5px;
	border: 1px solid var(--rule);
	border-bottom-width: 2px;
	border-radius: 3px;
	background: var(--paper-hi);
	color: var(--ink-3);
}

/* ── 检索框（左卷、料、右案）──────────────────────────────── */
.rail-filter {
	width: 100%;
	margin: 0 0 8px;
	font-size: 12px;
}
.mat-search {
	width: 100%;
	margin: 0 0 10px;
	font-size: 12.5px;
}
.mat-filter:empty { display: none; }
/* 库里一条料都没有时，分类条只剩末尾那个「＋」（增删种类）。空着的时候没有种类可加，
   它只是把空状态往下推了三十来像素 —— 和「没有内容就别摆支撑性控件」同一条道理。
   等有了第一条料，分类条自然带着种类回来，那个「＋」也就跟着有了用处。 */
.mat-filter:has(> .chip-add:only-child) { display: none; }
/* 默认的搜索清除按钮是系统蓝，和纸墨不搭；清空用 Esc 或退格即可。 */
.rail-filter::-webkit-search-cancel-button,
.mat-search::-webkit-search-cancel-button,
.bible-search::-webkit-search-cancel-button,
.palette-head input::-webkit-search-cancel-button { display: none; }
.chapter-search-empty {
	list-style: none;
	padding: 14px 4px;
	font-size: 11.5px;
	color: var(--ink-3);
	font-family: var(--kai);
}
.bible-head {
	display: flex;
	align-items: center;
	gap: 6px;
	padding: 10px 10px 0;
	flex: none;
}
.bible-search { flex: 1; min-width: 0; }

/* ── 浮层提示 ─────────────────────────────────────────────── */
.toast-stack {
	position: fixed;
	left: 50%;
	bottom: 24px;
	transform: translateX(-50%);
	z-index: 1000;
	display: flex;
	flex-direction: column;
	align-items: center;
	gap: 8px;
	pointer-events: none;
}
.toast {
	pointer-events: auto;
	display: flex;
	align-items: flex-start;
	gap: 9px;
	max-width: min(580px, 90vw);
	padding: 10px 15px;
	border: 1px solid var(--rule-strong);
	border-left: 3px solid var(--ink-3);
	border-radius: 4px;
	background: var(--paper-hi);
	color: var(--ink);
	box-shadow: 0 8px 26px var(--shadow);
	font-size: 12.5px;
	line-height: 1.7;
	cursor: pointer;
	animation: toast-in 220ms cubic-bezier(0.22, 0.61, 0.36, 1) both;
}
.toast-error { border-left-color: var(--cinnabar); }
.toast-ok { border-left-color: var(--moss); }
.toast-warn { border-left-color: var(--amber); }
.toast.is-gone { opacity: 0; transform: translateY(6px); transition: opacity 200ms ease, transform 200ms ease; }
/* 提示上的印章字：一个字的方印，不是色点。
   手机上提示一闪而过，靠颜色分不出「成」与「误」—— 字得看得见。
   边框跟着 currentColor 走，四档语气只改颜色，不必各写一条边。 */
.toast-mark {
	flex: none;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	min-width: 1.45em;
	height: 1.45em;
	margin-top: 1px;
	padding: 0 1px;
	border: 1px solid currentColor;
	border-radius: 2px;
	font-family: var(--kai);
	font-size: 11px;
	line-height: 1;
	color: var(--ink-3);
}
.toast-error .toast-mark { color: var(--cinnabar-ink); }
.toast-ok .toast-mark { color: var(--moss); }
.toast-warn .toast-mark { color: var(--amber); }
/* 关闭口：整条可点也能关，但手机上一眼看不出「点哪儿算关」，
   所以另给一个看得见的叉。桌面端它也在，只是更淡。 */
.toast-close {
	flex: none;
	align-self: flex-start;
	margin-left: auto;
	padding: 0 3px;
	border-radius: var(--r-1);
	font-size: 12px;
	line-height: 1.5;
	color: var(--ink-3);
	cursor: pointer;
}
.toast-close:hover { color: var(--cinnabar-ink); background: var(--cinnabar-wash); }
.toast-close:focus-visible { outline: 2px solid var(--cinnabar); outline-offset: 1px; }
.toast-text { min-width: 0; }
@keyframes toast-in {
	from { opacity: 0; transform: translateY(8px); }
	to   { opacity: 1; transform: none; }
}

/* ── 自动存稿状态 ─────────────────────────────────────────── */
.actions-center { flex-wrap: wrap; row-gap: 8px; }
.ms-save-state {
	align-self: center;
	min-width: 4.8em;
	font-size: 11px;
	color: var(--ink-3);
	font-variant-numeric: tabular-nums;
	letter-spacing: 0.04em;
}
.ms-save-state.is-dirty { color: var(--cinnabar-ink); }

/* ── 等待首字：三点墨依次晕开 ────────────────────────────────
   转圈的齿轮太像工具了；蘸墨点纸才对味 —— 三点依次涨落，
   看得出"还在动"，又不吵。 */
.msg.waiting {
	display: flex;
	align-items: center;
	gap: 10px;
	padding: 10px 2px;
	border: 0;
	background: transparent;
	color: var(--ink-3);
	font-family: var(--kai);
	font-size: 13px;
	letter-spacing: 0.1em;
}
.waiting-dots {
	flex: none;
	display: inline-flex;
	align-items: center;
	gap: 4px;
	width: auto;
	height: auto;
	border: 0;
	border-radius: 0;
}
.waiting-dots i {
	width: 6px;
	height: 6px;
	border-radius: 50%;
	background: var(--ink-3);
	animation: waiting-ink 1.5s ease-in-out infinite;
}
.waiting-dots i:nth-child(2) { animation-delay: 0.2s; }
.waiting-dots i:nth-child(3) { animation-delay: 0.4s; }
@keyframes waiting-ink {
	0%, 60%, 100% { opacity: 0.25; transform: scale(0.78); }
	30% { opacity: 1; transform: scale(1); }
}

/* ── 还在写：名字后头点一枚呼吸的墨点 ──────────────────────
   从助手消息建起来到第一个字到达，中间可能几十秒。
   作者得看见它还在忙，而不是以为卡死了。 */
.msg.is-writing .msg-role::after {
	content: "";
	display: inline-block;
	width: 6px;
	height: 6px;
	margin-left: 7px;
	border-radius: 50%;
	background: var(--cinnabar);
	vertical-align: 1px;
	animation: waiting-ink 1.5s ease-in-out infinite;
}

/* ── 失败之后的那排小动作 ─────────────────────────────────────
   目前只有「再试一次」。上游抽风是常事，让作者把长指令重敲一遍
   既费事又容易走样 —— 原样重发才是他要的。 */
.msg-actions {
	display: flex;
	flex-wrap: wrap;
	gap: 8px;
	margin-top: 10px;
}
.msg-actions .btn { font-size: 12px; }
.msg-actions .btn:disabled { opacity: 0.55; cursor: default; }

/* ── 版本抽屉 ─────────────────────────────────────────────── */
.history-lead {
	margin: 0 0 14px;
	font-size: 12px;
	line-height: 1.8;
	color: var(--ink-3);
}
.history-list { display: flex; flex-direction: column; gap: 10px; }
.history-row {
	padding: 11px 14px;
	border: 1px solid var(--rule);
	border-radius: 4px;
	background: var(--paper-hi);
}
.history-row.is-current { border-color: var(--cinnabar-edge); background: var(--cinnabar-tint); }
.history-head {
	display: flex;
	align-items: baseline;
	flex-wrap: wrap;
	gap: 4px 10px;
	font-size: 12px;
	color: var(--ink-3);
}
.history-version { font-family: var(--kai); font-size: 14.5px; color: var(--ink); letter-spacing: 0.06em; }
.history-mode { color: var(--cinnabar-ink); }
.history-when { color: var(--ink-3); font-variant-numeric: tabular-nums; }
.history-words { margin-left: auto; color: var(--ink-3); font-variant-numeric: tabular-nums; }
.history-row > .btn { margin-top: 8px; }
.history-preview { margin-top: 6px; }
.history-preview > summary {
	cursor: pointer;
	font-size: 11.5px;
	color: var(--ink-3);
	list-style: none;
}
.history-preview > summary::-webkit-details-marker { display: none; }
.history-preview > summary::before { content: "▸ "; color: var(--ink-3); }
.history-preview[open] > summary::before { content: "▾ "; }
.history-text {
	max-height: 300px;
	overflow: auto;
	margin: 8px 0 0;
	padding: 10px 12px;
	border-radius: 3px;
	background: var(--paper-sunk);
	font-family: var(--serif);
	font-size: 13px;
	line-height: 1.9;
	white-space: pre-wrap;
}
.history-empty { padding: 10px 0; font-size: 12px; color: var(--ink-3); }
.history-hint { margin: 6px 0 0; font-size: 11px; color: var(--ink-3); }

/* ── 导出 / 排版 / 快捷键 ─────────────────────────────────── */
.export-dialog,
.type-dialog,
.shortcuts-dialog {
	width: min(560px, 92vw);
	/* dialog 的 UA 样式把上下两条 inset 都钉成 0，height:auto 会被拉满一屏；
	   fit-content 才是「内容多高就多高」。 */
	height: fit-content;
	max-height: min(800px, 90vh);
}
.export-dialog .form-body,
.type-dialog .form-body,
.shortcuts-dialog .form-body { flex: 0 1 auto; }

.seg { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 7px; }
.seg label {
	display: inline-flex;
	align-items: center;
	gap: 6px;
	margin: 0;
	padding: 5px 13px;
	border: 1px solid var(--rule);
	border-radius: 999px;
	background: var(--paper-hi);
	color: var(--ink-2);
	font-size: 12.5px;
	cursor: pointer;
	transition: border-color var(--wash), background var(--wash), color var(--wash);
}
.seg label:has(input:checked) {
	border-color: var(--cinnabar);
	color: var(--cinnabar-ink);
	background: var(--cinnabar-wash);
}
.seg label:has(input:disabled) { opacity: 0.45; cursor: not-allowed; }
.seg input { width: auto; margin: 0; accent-color: var(--cinnabar); }
/* 单选框换成墨点：系统蓝圆点与纸墨不搭，焦点环也不该是个方框。 */
.seg input[type="radio"] {
	appearance: none;
	display: inline-block;
	flex: none;
	width: 13px;
	height: 13px;
	padding: 0;
	border: 1px solid var(--ink-4);
	border-radius: 50%;
	background: transparent;
}
.seg input[type="radio"]:checked {
	border-color: var(--cinnabar);
	background: var(--cinnabar);
	box-shadow: inset 0 0 0 3px var(--paper-hi);
}
.seg input[type="radio"]:focus-visible {
	outline: 2px solid var(--cinnabar);
	outline-offset: 2px;
}

.keys { margin: 0; display: flex; flex-direction: column; gap: 2px; }
.keys > div {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 24px;
	padding: 9px 0;
	border-bottom: 1px dashed var(--rule-soft);
}
.keys > div:last-child { border-bottom: 0; }
.keys dt { display: flex; align-items: center; gap: 4px; }
.keys dd { margin: 0; font-size: 12.5px; color: var(--ink-3); }

.front-progress { margin-top: 8px !important; color: var(--cinnabar-ink) !important; font-variant-numeric: tabular-nums; }

/* ── 检索面板 ─────────────────────────────────────────────── */
.palette {
	position: fixed;
	inset: 10vh 0 auto;
	margin: 0 auto;
	width: min(660px, 92vw);
	padding: 0;
	border: 1px solid var(--rule-strong);
	border-radius: 6px;
	background: var(--paper);
	color: var(--ink);
	box-shadow: 0 24px 70px var(--shadow);
	overflow: hidden;
}
.palette::backdrop { background: var(--backdrop); backdrop-filter: blur(2px); }
.palette-head {
	display: flex;
	align-items: center;
	gap: 10px;
	padding: 12px 14px;
	border-bottom: 1px solid var(--rule);
}
.palette-head input {
	flex: 1;
	min-width: 0;
	border: 0;
	background: transparent;
	color: var(--ink);
	font-family: var(--serif);
	font-size: 16px;
	padding: 4px 2px;
	outline: none;
}
.palette-results { max-height: min(58vh, 520px); overflow-y: auto; padding: 6px; }
.palette-row {
	display: flex;
	align-items: flex-start;
	gap: 10px;
	padding: 9px 12px;
	border-radius: 4px;
	cursor: pointer;
}
.palette-row.is-on { background: var(--ink-wash); }
.palette-group {
	flex: none;
	margin-top: 2px;
	padding: 1px 5px;
	border: 1px solid var(--rule);
	border-radius: 3px;
	font-size: 10.5px;
	color: var(--ink-3);
}
.palette-main { min-width: 0; }
.palette-label { font-size: 13.5px; color: var(--ink); }
.palette-hint {
	max-width: 520px;
	margin-top: 2px;
	font-size: 11.5px;
	color: var(--ink-3);
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
}
.palette-empty { padding: 28px 16px; text-align: center; font-size: 12.5px; color: var(--ink-3); font-family: var(--kai); }

/* ── 专注模式 ─────────────────────────────────────────────── */
.desk.is-focus {
	grid-template-columns: minmax(0, 1fr);
	grid-template-areas: "beam" "alert" "stage";
}
.desk.is-focus .rail,
.desk.is-focus .desk-right { display: none !important; }
.desk.is-focus .stage-bar { display: none; }
.desk.is-focus .beam-mid { justify-content: center; }
.desk.is-focus #view-manuscript {
	--ms-pad-t: 58px;
	--ms-pad-x: 64px;
	--ms-pad-b: 150px;
}
body.focus-mode { background: var(--paper); }

/* ── 顶栏在窄窗里的取舍 ───────────────────────────────────── */
.beam-stats { overflow: hidden; text-overflow: ellipsis; }
@media (max-width: 1320px) {
	.brand-text p { display: none; }
	.beam-mid { gap: 8px; }
	/* 统计在窄窗里让位给书名与模型：进度还能在稿台与案头看到。 */
	.beam-stats { display: none; }
	.beam-controls select { max-width: 150px; }
	.beam-search-label { display: none; }
	.beam-search-glyph { display: inline; }
	.beam-kbd { display: none; }
}

/* ── 触屏：动作条常显（hover 永不到达）────────────────────── */
@media (hover: none) {
	.card.mat.is-peek .mat-actions {
		max-height: none;
		margin-top: 9px;
		opacity: 1;
		overflow: visible;
	}
}

/* ── settings.js 用到的按钮别名（此前只有样式表外的类名）───── */
.btn-primary {
	background: var(--ink);
	border-color: var(--ink);
	color: var(--paper-hi);
}
.btn-primary:hover:not(:disabled) { background: var(--ink-lift); border-color: var(--ink-lift); color: var(--on-paper); }
.btn-ghost { background: transparent; border-color: var(--rule); color: var(--ink-3); }
.btn-ghost:hover:not(:disabled) { border-color: var(--ink-4); color: var(--ink); }

/* ══════════════════════════════════════════════════════════════
   书斋层：裱纸、界格、题签、印章、回纹、远山、骨架
   三条规矩：
   1. 只叠层次，不改盒子 —— 面板的 border 宽度一个都没动，「厚」全靠
      box-shadow 与伪元素做出来，≥900px 的两栏 / 三栏不会因此挪位；
   2. 颜色只来自令牌，这一整段里不出现任何字面色值；
   3. 动效一律 var(--brush)，位移不超过 4px，不做弹性。
   ══════════════════════════════════════════════════════════════ */

/* ── 裱纸：面板的双线框 ──────────────────────────────────────
   外一条强线（既有 border），内一条弱线，顶边一道高光，底边一线投影。
   缺了那道高光，双线框就只是「画了个框」，没有纸的厚度。 */
.bench-pane,
.rail,
.desk-right,
.record-list,
.material-list,
.assembly-list,
.pool-list {
	box-shadow:
		inset 0 0 0 1px var(--panel-ring),
		inset 0 1px 0 var(--panel-hi),
		inset 0 -1px 0 var(--panel-drop);
}
/* 典籍栏已经嵌在右案的双线框里，再加一圈会糊成三道线，只留顶边高光 */
.bible { box-shadow: inset 0 1px 0 var(--panel-hi); }

/* 对话框与提示是「浮起来的那张纸」：既有投影必须留着，内线补在最前。
   --panel-face 让纸面从顶边亮起，--ink-bleed 在底边压一道墨影。 */
.sheet {
	background-image: var(--ink-bleed), var(--panel-face);
	box-shadow:
		0 18px 50px var(--shadow),
		inset 0 0 0 1px var(--panel-ring),
		inset 0 1px 0 var(--panel-hi);
}
.palette {
	background-image: var(--panel-face);
	box-shadow:
		0 24px 70px var(--shadow),
		inset 0 0 0 1px var(--panel-ring),
		inset 0 1px 0 var(--panel-hi);
}
.toast {
	box-shadow: 0 8px 26px var(--shadow), inset 0 1px 0 var(--panel-hi);
}

/* ── 印章式状态 ─────────────────────────────────────────────
   <span class="stamp">已存</span>，加 --moss / --tea 换色，--solid 填朱。
   方形、细描边、楷体字 —— 它是一枚记号，不是一个彩色标签，
   所以不留圆角、不加粗、不填满。 */
.stamp {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	flex: none;
	gap: var(--sp-1);
	padding: 1px 6px;
	border: 1px solid var(--cinnabar-edge);
	border-radius: 2px;
	background: var(--cinnabar-soft);
	color: var(--cinnabar-ink);
	font-family: var(--kai);
	font-size: var(--fs-xs);
	line-height: 1.5;
	letter-spacing: 0.08em;
	font-variant-numeric: tabular-nums;
	white-space: nowrap;
	vertical-align: middle;
}
/* 空印章不能留一个空框 */
.stamp:empty { display: none; }
.stamp--moss { border-color: var(--moss-edge); background: var(--moss-wash); color: var(--moss); }
.stamp--tea { border-color: var(--tea-edge); background: var(--tea-wash); color: var(--tea); }
.stamp--solid { border-color: var(--cinnabar); background: var(--cinnabar); color: var(--on-cinnabar); }

/* ── 回纹：一条 6px 的横向界格带 ─────────────────────────────
   放在 .pane-head 之后、或是两块内容之间。它是纹样，不是分割线，
   所以透明度压到 0.5 以下 —— 看得清纹路，看不清边界。 */
.fret {
	height: 6px;
	flex: none;
	background-image: var(--fret);
	background-repeat: repeat-x, no-repeat;
	background-size: 7px 5px, 100% 1px;
	background-position: 0 0, 0 100%;
	opacity: 0.5;
	pointer-events: none;
}
.fret--wide { height: 8px; opacity: 0.4; }

/* ── 空状态：一痕远山 ────────────────────────────────────────
   空的地方最容易显得「坏了」。压一层几乎看不见的山影与云气，
   文字往下挪一点站到山前，空也就成了留白。 */
.rail-note,
.bench-hint,
.bench-empty,
.bible-empty,
.empty-hint,
.palette-empty,
.chapter-search-empty,
.history-empty {
	background-image: var(--mountains);
	background-repeat: no-repeat;
	background-position: center bottom;
	background-size: 100% 88%;
}
.bench-empty,
.bible-empty,
.empty-hint,
.palette-empty {
	padding-top: calc(var(--sp-4) + var(--sp-1));
	padding-bottom: calc(var(--sp-5) + var(--sp-1));
}

/* 拖入文件时整块面板从底边洇上朱砂：
   比一条描边更能说清「可以放在这儿」，也还是墨晕的路子 */
.bench-pane.is-over { background-image: var(--cinnabar-bleed); }

/* ── 骨架屏 ─────────────────────────────────────────────────
   一块纸色占位，一道窄光从左掠到右。光只占 12%（38%→62%），
   宽了就成了进度条；底色比纸深一档，才看得出「这里还没东西」。 */
@keyframes sk-sweep {
	from { background-position: -140% 0; }
	to { background-position: 240% 0; }
}
.skeleton,
.sk-line {
	background-color: var(--skeleton);
	background-image: var(--skeleton-sheen);
	background-repeat: no-repeat;
	background-size: 220% 100%;
	border-radius: var(--r-2);
	animation: sk-sweep 1.6s linear infinite;
}
.sk-line { height: 0.82em; margin: 0 0 var(--sp-2); border-radius: var(--r-1); }
.sk-line:last-child { margin-bottom: 0; }
.sk-line.is-short { width: 52%; }
.sk-line.is-mid { width: 76%; }

/* 稿纸淡入。.ms-page / .front-matter 早就写着 animation: fade，
   但一直没定义过这个名字 —— 补上，翻章时纸才是「落」下来的。 */
@keyframes fade {
	from { opacity: 0; }
	to { opacity: 1; }
}

/* ══════════════════════════════════════════════════════════════
   移动端：手机与平板的落纸处
   桌面（≥900px）的样貌与行为一概不动；这一段只从窄处开始改写。
   分三档：≤900px 触屏与窄窗、≤640px 手机、再往下是键盘与安全区。
   ══════════════════════════════════════════════════════════════ */

/* 只在手机上露面的控件：章目抽屉的开关、模型与档位的浮层。 */
.only-phone { display: none; }

/* 顶栏里的模型与档位：桌面端用 display:contents 还原成顶栏的一行，
   手机上收进一块浮层 —— 两个下拉放在 360px 宽的顶栏里必然溢出。 */
.beam-tools { display: contents; }
.beam-tools-cap { display: none; }

/* 章目抽屉的标题行：章目二字 + 收起 */
.rail-head { display: flex; align-items: center; gap: 8px; }
.rail-head .rail-label { flex: 1; min-width: 0; }
.rail-close { flex: none; }

/* 章目抽屉的遮罩：平时不在页面里，只有手机断点用得上 */
.rail-backdrop { display: none; }

/* 浮出来的提示要躲开 Home Indicator */
.toast-stack { bottom: calc(24px + var(--safe-b)); }

/* 内部滚动容器：手机上要惯性滚动，滚到头也不带动整页 */
.project-list,
.chapter-list,
.stream,
.bible,
.bench-pane,
.material-list,
.form-body,
.palette-results,
#view-manuscript {
	-webkit-overflow-scrolling: touch;
	overscroll-behavior: contain;
}

/* ── ≤1240px：右案已经成了抽屉，顶上那截要避开刘海 ───────────── */
@media (max-width: 1240px) {
	.desk-right { padding-top: var(--safe-t); }
}

/* ── ≤900px：触屏与窄窗的通例 ──────────────────────────────── */
@media (max-width: 900px) {
	/* 点得中：主要动作至少 44px 高 */
	.btn,
	.btn-sm,
	.btn-xs,
	.tab,
	.chip,
	.rail-add,
	.bible-tab,
	.ink-btn,
	.theme-toggle,
	.palette-row {
		min-height: var(--tap);
	}
	.theme-toggle { width: var(--tap); height: var(--tap); }
	.chapter-item { min-height: var(--tap); }
	.toc-item { min-height: var(--tap); }
	/* 底部的输入区要避开 Home Indicator */
	.composer { padding-bottom: calc(20px + var(--safe-b)); }
	.bench-talk .composer { padding-bottom: calc(18px + var(--safe-b)); }
	/* 稿台的操作条在窄屏上常常放不下，允许换行，别把稿子挤走 */
	.stage-bar { flex-wrap: wrap; row-gap: 6px; padding: 8px 16px; }
	.stage-actions { flex-wrap: wrap; row-gap: 6px; }
}

/* ── ≤640px：手机 ────────────────────────────────────────── */
@media (max-width: 640px) {
	/* 骨架：单列。章目不再占一行，收进抽屉，首屏全给稿子。 */
	.desk,
	.desk.is-bench,
	.desk.is-home,
	.desk.is-focus {
		grid-template-columns: minmax(0, 1fr);
		grid-template-rows: auto auto minmax(0, 1fr);
		grid-template-areas:
			"beam"
			"alert"
			"stage";
	}
	.desk { height: 100vh; height: 100dvh; }

	/* 顶栏：允许换行，按钮不再挤出屏幕 */
	.beam {
		flex-wrap: wrap;
		align-items: center;
		gap: 6px 10px;
		min-height: calc(58px + var(--safe-t));
		padding: var(--safe-t) calc(10px + var(--safe-r)) 6px calc(10px + var(--safe-l));
	}
	.brand-text p { display: none; }
	.brand-text h1 { font-size: 15px; }
	.beam-mid { flex: 1 1 auto; min-width: 0; }
	.beam-controls {
		flex: 1 0 100%;
		width: 100%;
		flex-wrap: wrap;
		justify-content: space-between;
		gap: 4px;
	}
	.only-phone { display: inline-flex !important; }
	/* 快捷键是桌面的东西，屏幕上按不出来 */
	#open-shortcuts { display: none; }
	/* 案头没有章目，料与文两页的章目在 ≤1180 已经收起了 */
	.desk.is-home #toggle-rail,
	.desk.is-bench #toggle-rail { display: none !important; }

	/* 模型与档位：收进一块浮层，点「笔」落下 */
	.beam-tools {
		display: none;
		position: absolute;
		top: calc(100% + 6px);
		right: calc(10px + var(--safe-r));
		z-index: 70;
		flex-direction: column;
		align-items: stretch;
		gap: 6px;
		min-width: 230px;
		padding: 12px;
		background: var(--paper-hi);
		border: 1px solid var(--rule-strong);
		border-radius: 6px;
		box-shadow: 0 16px 40px var(--shadow);
	}
	.beam-tools.is-open { display: flex; }
	.beam-tools-cap {
		display: block;
		font-size: 11px;
		letter-spacing: 0.16em;
		color: var(--ink-3);
	}
	.beam-tools select { width: 100%; max-width: none; }

	/* 章目抽屉：从左边滑进来，盖在稿子上 */
	.rail {
		position: fixed;
		top: 0;
		left: 0;
		bottom: 0;
		z-index: 60;
		grid-area: auto;
		flex-direction: column;
		width: min(300px, 84vw);
		max-height: none;
		padding-top: var(--safe-t);
		padding-bottom: var(--safe-b);
		border-right: 1px solid var(--rule);
		border-bottom: 0;
		box-shadow: 12px 0 36px var(--shadow);
		transform: translateX(-102%);
		visibility: hidden;
		transition: transform var(--wash), visibility var(--wash);
	}
	.desk.is-rail-open .rail { transform: none; visibility: visible; }
	.rail-backdrop {
		display: block;
		position: fixed;
		inset: 0;
		z-index: 59;
		border: 0;
		padding: 0;
		background: var(--backdrop);
	}

	/* 右案抽屉：不宽过一屏，可横向滑走 */
	.desk-right {
		width: min(100vw, 420px);
		padding-bottom: var(--safe-b);
		overscroll-behavior: contain;
	}

	/* 稿面：留白收紧，正文照旧可读 */
	#view-manuscript {
		--ms-pad-t: 18px;
		--ms-pad-x: 16px;
		--ms-pad-b: 88px;
	}
	.desk.is-focus #view-manuscript {
		--ms-pad-t: 18px;
		--ms-pad-x: 16px;
		--ms-pad-b: 88px;
	}
	.ms-title { font-size: 23px; }
	/* 朱丝栏的负边距不能超出留白，否则稿面会横向滚动 */
	.ms-text::before { inset: -10px -12px; }
	/* 操作条在手机上横向拖，不换行堆成一堵墙 */
	#view-manuscript .actions-center {
		justify-content: flex-start;
		flex-wrap: nowrap;
		overflow-x: auto;
		-webkit-overflow-scrolling: touch;
		scrollbar-width: none;
	}
	#view-manuscript .actions-center::-webkit-scrollbar { display: none; }

	/* 弹层：手机上全屏，里头自己滚 */
	.sheet {
		width: 100vw;
		max-width: 100vw;
		max-height: 100vh;
		max-height: 100dvh;
		margin: 0;
		border-radius: 0;
		padding: 18px 16px calc(18px + var(--safe-b));
	}
	.sheet-wide,
	.sheet-form,
	.sheet-read,
	.sheet-form.promote {
		width: 100vw;
		max-width: 100vw;
		height: 100vh;
		height: 100dvh;
		max-height: 100vh;
		max-height: 100dvh;
		margin: 0;
		border: 0;
		border-radius: 0;
		padding: 0;
	}
	.sheet-wide .settings-body { overflow-y: auto; }
	.form-body { padding: 16px 14px 12px; }
	.form-foot { padding-bottom: calc(14px + var(--safe-b)); }
	.palette {
		inset: 0;
		width: 100vw;
		max-width: 100vw;
		height: 100vh;
		height: 100dvh;
		max-height: 100dvh;
		margin: 0;
		border-radius: 0;
	}

	/* 触摸：输入框不小于 16px，iOS 聚焦时才不会把整页放大。
	   改稿框例外 —— 它跟着排版偏好走，手机上不低于 16px（见 app.js）。 */
	input:not(.ms-edit),
	textarea:not(.ms-edit),
	select {
		font-size: 16px !important;
	}
	.stream { padding: 20px 14px 10px; }
	.bench-pane:not(.bench-talk) { padding: 0 14px 32px; }
	/* 案头三栏在手机上竖着排，每栏本来平分一屏。可对议栏还要装头部与输入框，
	   平分下来流里只剩二十六像素 —— 一句引导话都读不全，只露出最后半行。
	   给对议栏多分一倍，流里才容得下四五行字。 */
	.bench.bench-three { grid-template-rows: minmax(0, 1fr) minmax(0, 1fr) minmax(0, 2fr); }
	.composer { padding: 12px 12px calc(12px + var(--safe-b)); }
	.composer textarea { font-size: 16px; }
	.bench-talk .composer { padding: 10px 12px calc(10px + var(--safe-b)); }
	.bench-talk .composer textarea { font-size: 16px; }
	.bench-talk .stream { padding: 16px 14px 8px; }
	/* 手机上章名一长就把「写法」和按钮挤到第二行，索性让它自己占一行 */
	.bench-talk .write-actions { padding: 8px 12px; gap: 6px; }
	.bench-talk .write-actions .chapter-select { flex: 1 1 100%; max-width: none; min-height: 38px; }
	.bench-talk .write-actions select,
	.bench-talk .write-actions .btn { min-height: 38px; }

	/* 提示：躲开 Home Indicator，左右也留出边 */
	.toast-stack {
		left: calc(10px + var(--safe-l));
		right: calc(10px + var(--safe-r));
		bottom: calc(12px + var(--safe-b));
		transform: none;
		align-items: stretch;
	}
	.toast { max-width: 100%; }
}

/* ── 触屏：hover 永不到达，动作要常显，动效要收 ─────────────── */
@media (hover: none) {
	/* 卡片不再浮起 —— 触屏上 :hover 会粘住，浮着的卡片看着像没点中 */
	.card.mat.is-peek:hover,
	.card.record:hover,
	.card.mat:hover {
		transform: none;
		box-shadow: none;
	}
	/* 鼠标扫过的缓动在触屏上是白耗的电 */
	.project-item,
	.chapter-item,
	.tab,
	.btn,
	.chip,
	.card.mat,
	.card.mat .mat-actions {
		transition: none;
	}
	/* 焦点环在触屏上更要看得清 */
	:focus-visible { outline-width: 3px; }
}

/* ══════════════════════════════════════════════════════════════
   触屏细部：书斋层在手指下的尺寸
   桌面（>900px）的尺寸一个没动；这里只收窄屏上的边角与记号。
   ══════════════════════════════════════════════════════════════ */
@media (max-width: 900px) {
	/* 章目行有 44px 的触控高度，书口记号得跟着大一号才看得见 */
	.chapter-item::after { width: 4px; height: 4px; margin-top: -2px; }
	/* 角花在窄栏里离标题太近，收小一号；位置不动，免得跟题签撞 */
	.pane-head::before { background-size: 7px 1px, 1px 7px, 7px 1px, 1px 7px; }
	/* 面板的内描线在窄屏上离内容太近，减到只有顶边高光 */
	.record-list, .material-list { box-shadow: inset 0 1px 0 var(--panel-hi); }
}

@media (max-width: 640px) {
	/* 手机上栏头就是抽屉的标题行，两个角花会挤到字，收掉 */
	.pane-head::before { display: none; }
	/* 印章与签要能被拇指看见，但不抢戏 */
	.stamp, .pane-count, .pane-note { min-height: 20px; }
	/* 天头地脚在手机上收一点，别占掉小半屏 */
	.ms-rule { margin: 16px auto 12px; }
	.rail-note { padding-bottom: var(--sp-4); }
	/* 骨架条在窄栏里按比例缩，别撑破卡片 */
	.sk-line { height: 0.9em; }
}

/* ══════════════════════════════════════════════════════════════
   接线的细部：给结构侧新增的钩子补上「书斋里的样子」

   index.html 与 app.js 这轮加了一批钩子（.icon-btn、data-cap、
   .beam-tools-head、.is-typing、.toast-close、#boot-skeleton）。
   结构侧只给了「能用」的兜底，颜色与字体在这里落定 —— 令牌全在
   本文件，别让兜底里的字面量成为事实上的终稿。
   ══════════════════════════════════════════════════════════════ */

/* 方形图标钮：「?」「☾」「×」这类没有字义的钮，宽高得一样，
   否则一排看过去像参差不齐的书签。 */
.icon-btn {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 30px;
	height: 30px;
	padding: 0;
	line-height: 1;
	letter-spacing: 0;
}
.icon-btn.btn-sm { font-size: var(--fs-sm); }

/* 顶栏「笔墨」浮层的头：手机上它自己带一个可见的收起口。
   桌面端这块由结构侧的 display:none 收着（浮层是横向展开的，不需要头）。 */
.beam-tools-title {
	font-family: var(--kai);
	font-size: var(--fs-md);
	letter-spacing: 0.18em;
	color: var(--ink-2);
}
.beam-tools-head {
	border-bottom: 1px solid var(--rule-soft);
}

/* 手机顶栏只剩一个单字：「目 / 笔 / 案」。
   单字靠字形认，所以用楷体写；靠字号按得准，所以撑到触控尺寸。
   全名留在 aria-label 与 title 里，读屏与长按都拿得到。 */
@media (max-width: 640px) {
	.beam-controls .btn[data-cap] {
		font-family: var(--kai);
		font-size: 15px;
		letter-spacing: 0;
		padding: 0;
		min-width: var(--tap-lg);
		height: var(--tap-lg);
		/* 撑满高度但不居中，单字就贴在钮的上沿 —— 旁边「搜」「设置」是居中的，
		   一排看过去这三位矮了半截。方形钮里的字本来就该落在正中。 */
		align-items: center;
		justify-content: center;
	}
}

/* 「呈上」有没有字可呈：没字时淡下去，有字才亮。
   手机上这一条输入框就是整块屏，按钮亮没亮是「按下去有没有反应」的唯一线索。
   只加一圈朱砂细边，不改字色 —— 它是 .btn-ink（墨底纸字），
   把字改成朱砂在墨底上会糊成一片。 */
.composer button[type="submit"] {
	transition: opacity var(--brush), box-shadow var(--brush);
}
.composer.is-typing button[type="submit"] {
	box-shadow: inset 0 1px 0 var(--panel-hi), 0 0 0 1px var(--cinnabar-edge);
}

/* 触屏上图标钮也要撑到 48px：它没有文字，小了就只剩一个点 */
@media (pointer: coarse) {
	.icon-btn,
	.icon-btn.btn-sm {
		min-width: var(--tap-lg);
		min-height: var(--tap-lg);
	}
	/* 印章字在手指底下大一号，才认得出是哪个字 */
	.toast-mark { font-size: 12px; min-width: 1.6em; height: 1.6em; }
	.toast-close { font-size: 14px; padding: 0 8px; }
}

/* ── 素材种类 ────────────────────────────────────────────────
   添一类是「一行输入 + 一个按钮」，改名与删除都在清单里就地做。
   所以这一层不需要再开第二层弹层，手机上少一次转场，也不会
   让返回键连着退两次。 */

.kind-add {
	display: flex;
	align-items: flex-end;
	gap: var(--sp-2);
	margin-bottom: var(--sp-4);
	/* form-body 是竖排 flex：不加 flex:none，内容一多这两块会被压扁 */
	flex: none;
}
/* 不用 .field-grow：那是给整段文本框的（min-height 220px），
   这一行只要一格输入框高。 */
.kind-add .field {
	flex: 1;
	min-width: 0;
	margin-bottom: 0;
}
.kind-add .btn { flex: none; }

.kind-list {
	list-style: none;
	margin: 0;
	padding: 0;
	display: flex;
	flex-direction: column;
	gap: var(--sp-2);
	flex: none;
}

.kind-row {
	display: flex;
	align-items: center;
	gap: var(--sp-2);
	padding: var(--sp-2) var(--sp-3);
	border: 1px solid var(--rule-soft);
	border-radius: var(--r-2);
	background: var(--shade);
}

.kind-row .kind-name {
	flex: 1;
	min-width: 0;
	font-family: var(--kai);
	font-size: var(--fs-md);
	color: var(--ink);
	overflow-wrap: anywhere;
}

.kind-row .kind-count {
	flex: none;
	font-size: var(--fs-xs);
	color: var(--ink-3);
}

/* 行内改名：宽度跟着格子走，别把两个按钮挤出去 */
.kind-row .kind-rename {
	flex: 1;
	min-width: 0;
	font-size: var(--fs-md);
	padding: 6px var(--sp-2);
}

.kind-empty {
	padding: var(--sp-4);
	border: 1px dashed var(--rule);
	border-radius: var(--r-2);
	font-size: var(--fs-sm);
	color: var(--ink-3);
	text-align: center;
}

/* 内置的那几类只报名字：改不得，就别摆一排按不动的按钮 */
.kind-builtin {
	display: flex;
	flex-wrap: wrap;
	align-items: baseline;
	gap: var(--sp-2);
	padding: var(--sp-2) var(--sp-3);
	font-size: var(--fs-sm);
	color: var(--ink-3);
}
.kind-builtin-cap {
	flex: none;
	font-size: var(--fs-xs);
	letter-spacing: 0.14em;
	color: var(--ink-3);
	padding: 1px 6px;
	border: 1px solid var(--rule-soft);
	border-radius: var(--r-1);
}
.kind-builtin-names { min-width: 0; overflow-wrap: anywhere; }

/* 分类条末尾那个「＋」：它是动作不是筛选项，所以不跟着 is-on 走 */
.chip.chip-add {
	font-family: var(--sans);
	letter-spacing: 0;
	color: var(--ink-3);
	border-style: dashed;
}
.chip.chip-add:hover { color: var(--ink); border-color: var(--ink-4); }

/* 手指底下这几行都要够高：改名、删、添入都靠点 */
@media (pointer: coarse) {
	.kind-row { padding: var(--sp-1) var(--sp-2); }
	.kind-row .btn { min-height: var(--tap); }
	.kind-add .btn { min-height: var(--tap); }
}

/* 手机上添入那一行改竖排：横排时输入框只剩半截，打两个字就看不见了 */
@media (max-width: 640px) {
	.kind-add { flex-direction: column; align-items: stretch; }
	.kind-add .btn { width: 100%; }
}

/* ── 分卷 ────────────────────────────────────────────────────
   卷是章目之上的一层：章目里插一条卷头，稿面与作业条里带一句卷名。
   卷可有可无，所以分隔一律用虚线 —— 有线，但不重。 */
.rail-actions {
	display: flex;
	gap: var(--sp-1);
	margin: 0 6px 10px;
}
.rail-actions .rail-add { margin: 0; flex: 1; min-width: 0; }
.rail-actions .rail-add-thin { flex: 0 0 auto; padding: 5px 10px; }

.chapter-volume {
	display: flex;
	align-items: baseline;
	gap: var(--sp-2);
	margin: 10px 0 2px;
	padding: 8px 8px 5px;
	border-top: 1px dashed var(--rule);
	font-family: var(--kai);
	font-size: 12.5px;
	letter-spacing: 0.04em;
	color: var(--ink-2);
	cursor: pointer;
}
.chapter-volume:hover { color: var(--cinnabar-ink); }
.chapter-volume .cv-title {
	flex: 1;
	min-width: 0;
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
}
.chapter-volume .cv-meta {
	flex: none;
	font-family: var(--sans);
	font-size: var(--fs-xs);
	letter-spacing: 0;
	color: var(--ink-3);
}
.chapter-volume:hover .cv-meta { color: var(--cinnabar-ink); }

/* 稿面上那行卷名：比题签小一号、比「第几章」重一点，读的时候知道自己在哪一卷 */
.ms-volume {
	margin: 0 0 6px;
	font-family: var(--kai);
	font-size: 12px;
	letter-spacing: 0.18em;
	color: var(--cinnabar-ink);
	opacity: 0.85;
}

/* 分卷弹层里的卷目清单 */
.volume-list {
	list-style: none;
	margin: var(--sp-3) 0 0;
	padding: 0;
	max-height: min(38vh, 260px);
	overflow-y: auto;
}
.volume-row {
	display: flex;
	align-items: flex-start;
	gap: var(--sp-2);
	padding: 9px 10px;
	border: 1px solid var(--rule-soft);
	border-radius: var(--r-2);
	background: var(--paper-hi);
}
.volume-row + .volume-row { margin-top: var(--sp-1); }
.volume-row.is-editing { border-color: var(--cinnabar); }
.volume-main { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.volume-name { font-family: var(--serif); font-size: 13.5px; color: var(--ink); }
.volume-meta { font-size: var(--fs-xs); color: var(--ink-3); }
.volume-summary { font-size: var(--fs-xs); color: var(--ink-3); line-height: 1.6; overflow-wrap: anywhere; }
.volume-acts { flex: none; display: flex; gap: var(--sp-1); }
.volume-empty { padding: var(--sp-2) 0; font-size: var(--fs-sm); color: var(--ink-3); }

@media (pointer: coarse) {
	.volume-row .btn { min-height: var(--tap); }
	.chapter-volume { padding-block: 10px; }
}
@media (max-width: 640px) {
	.volume-row { flex-wrap: wrap; }
	.volume-acts { width: 100%; }
	.volume-acts .btn { flex: 1; }
}

/* ═══════════════════════════════════════════════════
   生成记录 · 抽屉与「接着写」小条
   ───────────────────────────────────────────────────
   两块面板头部各开一扇：从右边推进来的窄抽屉，列出该面板最近十轮。
   抽屉是自建的浮层（不是 <dialog>）：压一层遮罩、点外面就收，
   z-index 排在 toast（1000）之下，报错与回执仍浮在最上面。
   ═══════════════════════════════════════════════════ */

@keyframes records-in {
	from { transform: translateX(14px); opacity: 0; }
	to { transform: none; opacity: 1; }
}

.records-layer {
	position: fixed;
	inset: 0;
	z-index: 900;
	display: flex;
	justify-content: flex-end;
}
/* 层本身用 hidden 收起：不显式写这条，上面的 display 会盖掉浏览器自带的 [hidden]。 */
.records-layer[hidden] { display: none; }

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

.records-sheet {
	position: relative;
	z-index: 1;
	display: flex;
	flex-direction: column;
	width: min(420px, 100%);
	max-width: 100%;
	height: 100%;
	border-left: 1px solid var(--rule);
	background: var(--paper);
	box-shadow: var(--shadow);
	animation: records-in var(--brush);
}

.records-head {
	display: flex;
	align-items: flex-start;
	justify-content: space-between;
	gap: var(--sp-3);
	padding: var(--sp-4);
	border-bottom: 1px solid var(--rule-soft);
}
.records-titles { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.records-title {
	margin: 0;
	font-family: var(--kai);
	font-size: var(--fs-lg);
	font-weight: 600;
	letter-spacing: 0.04em;
	color: var(--ink);
}
.records-sub { font-size: var(--fs-xs); color: var(--ink-3); }

.records-body {
	flex: 1;
	min-height: 0;
	overflow-y: auto;
	overscroll-behavior: contain;
}

.records-list { display: flex; flex-direction: column; }

.records-item {
	display: flex;
	flex-direction: column;
	gap: var(--sp-1);
	padding: var(--sp-3) var(--sp-4);
	border-bottom: 1px solid var(--rule-soft);
}
.records-item:hover { background: var(--hover); }

.records-item-head {
	display: flex;
	align-items: baseline;
	flex-wrap: wrap;
	gap: var(--sp-2);
}
.records-item-title {
	flex: 1;
	min-width: 0;
	margin: 0;
	font-family: var(--kai);
	font-size: var(--fs-md);
	font-weight: 600;
	line-height: 1.5;
	letter-spacing: 0.03em;
	color: var(--ink);
	overflow-wrap: anywhere;
}
.records-when { flex: none; font-size: var(--fs-xs); color: var(--ink-3); white-space: nowrap; }
.records-flag {
	flex: none;
	padding: 0 5px;
	border: 1px solid var(--cinnabar-edge);
	border-radius: var(--r-1);
	font-size: var(--fs-xs);
	color: var(--cinnabar-ink);
}

.records-preview {
	margin: 0;
	overflow: hidden;
	white-space: nowrap;
	text-overflow: ellipsis;
	font-size: var(--fs-sm);
	color: var(--ink-3);
}

.records-meta {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: var(--sp-2);
	margin-top: 2px;
}
.records-count { font-size: var(--fs-xs); color: var(--ink-3); }
.records-actions { display: flex; gap: var(--sp-1); }

.records-empty {
	margin: 0;
	padding: var(--sp-5) var(--sp-4);
	font-size: var(--fs-sm);
	line-height: 1.9;
	color: var(--ink-3);
}
.records-error { display: flex; flex-direction: column; align-items: flex-start; gap: var(--sp-2); }

/* 作业条上的「接着第 N 轮写」：一条窄条，跟着写法下拉排在同一行。 */
.write-record-bar {
	display: flex;
	align-items: center;
	gap: var(--sp-2);
	padding: 2px 4px 2px 10px;
	border: 1px solid var(--cinnabar-edge);
	border-radius: var(--r-3);
	background: var(--cinnabar-wash);
	font-size: var(--fs-xs);
	color: var(--cinnabar-ink);
}
.write-record-text { white-space: nowrap; }
.write-record-bar .icon-btn { color: var(--cinnabar-ink); }

/* 圆一点的小方格按钮：× 这一类只占一个字形。 */
.icon-btn {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 24px;
	height: 24px;
	padding: 0;
	line-height: 1;
}

/* 记录里「只调了工具、没说一句话」的那一轮：灰一点，别当成人说的话去读。 */
.msg.is-toolnote .msg-body {
	font-size: var(--fs-sm);
	font-style: italic;
	color: var(--ink-3);
}

/* 头部多了一颗「记录」：pane-tools 原先只放一颗按钮，现在要自己排一行。 */
.pane-tools { display: flex; align-items: center; gap: var(--sp-1); }

@media (max-width: 640px) {
	.records-sheet { width: 100%; border-left: 0; }
	.records-body { padding-bottom: calc(var(--sp-4) + var(--safe-b)); }
	.records-head { padding: var(--sp-3) var(--sp-4); }
	.records-item { padding: var(--sp-3); }
}



