/* WeebPaint — 和兄弟项目同款米色 / 夜黑 + 全屏画布 + 浮动顶栏 */

:root {
  /* ---- Surface 层级表（z-order SSoT，v232；详 ai-docs/20260611-surfaces-z-order.md）----
     全仓唯一允许出现 z-index 数字的地方。band 间不变量（结构性，不靠手填数字）：
       chrome < toolbar < window < sheet < overlay < menu < toast < modal < busy < gate < popout < dev < error
     「菜单/popup 永远在浮窗和全屏 overlay 上面」由 band 序保证。
     v0.4.11：gate 抬到 busy 之上——「冲突必 surface」（ADR-0009）优先于防误点遮罩。store 收敛后
     push 在 busy 内 surface 冲突面（push.ts 包 busy），gate<busy 会把冲突选择盖死（真机 2026-07-22 0.2）。
     新 UI 选 band 用 var(--z-*)；浮窗（window band）内的动态顺序归 src/surfaces.ts 管。
     例外（不在表内）：board-grid/board-cursor（1/2，垫底）、局部 stacking context 内的相对值
     （menu-config-popup、gallery tile 内 ⋯popup 等）。 */
  --z-chrome: 10;    /* 顶栏 / 左栏 / HUD */
  --z-toolbar: 25;   /* lasso / crop / filterBrush 顶栏条（crop-overlay = -1） */
  --z-window: 100;   /* 浮窗 band 基底：100.. 由 surfaces.ts 分配（参考/图层/颜色/调整/色板） */
  --z-sheet: 220;    /* 笔架 sheet；笔设置全屏 view = +10 */
  --z-overlay: 300;  /* 全屏 overlay：图库 / 云端 */
  --z-menu: 400;     /* 一切菜单 / popup（汉堡 / 调整 / 图库 / size popup / 回收站⋯） */
  --z-popover: 420;  /* 菜单内再弹出的下拉（主题/语言/组槽菜单）——必须压过 --z-menu（v0.5.38；深模块化 TODO） */
  --z-toast: 450;
  --z-modal: 500;    /* .backdrop / .sheet 确认对话（resample = -2/-1，确认能盖住它） */
  --z-busy: 520;     /* fullscreen-busy 防误点锁 */
  --z-gate: 540;     /* sync gate 锁屏 / 冲突选择——必须盖过 busy（冲突必 surface，ADR-0009） */
  --z-notice: 560;   /* 通知栈（toast/横幅，ui/notice.ts）：忙时错误也要看得见 → 在 busy 之上；模态开着时整条栈停靠顶部不盖按钮行 */
  --z-popout: 600;   /* anchored-popup / picker-pin：永远在 modal 之上 */
  --z-dev: 700;
  --z-error: 9999;   /* index.html __errBar 的 inline 值与此对齐 */

  --bg: #f6f4ef;
  --bg-soft: #efece4;
  --ink: #1b1b1b;
  --ink-soft: #555;
  --line: #d8d2c4;
  --line-strong: #b8af9c;
  --accent: #8a481e;
  --danger: #c0392b;
  /* 语义状态色（2026-08-25 烤进主题，收敛此前散落的主题盲硬编码；user「bake color to themes」）：
     --warn = 云侧待你处理（topbar unpushed / badge conflict / btp connecting）
     --enc  = 加密琥珀（锁；与 --warn 刻意略异，语义不同不合并）
     --ok   = 就绪绿（btp on）· --quiet = 低调状态灰（topbar synced） */
  --warn: #d99a20;
  --enc: #c98a00;
  --ok: #3a9a4a;
  --quiet: #8a8a8a;
  --info: #4c8bf5;   /* 信息蓝（登录云图标/拖放框）；两主题暂同值，暗主题以后可调 */
  /* 画布外的"空地" — 比 bg 暗一档，给画布边缘视觉边界 */
  --void: #e6e2d6;
  /* 透明显示模式：点网格+doc 细框共用色（比 void 暗一档；v0.10.6 对比×1.5 user「稍微显眼50%」，框点同色） */
  --void-dot: #cec8b8;
  --shadow: 0 6px 24px rgba(0, 0, 0, 0.08);
  --radius: 12px;
}

:root[data-theme="night"] {
  --bg: #121110;
  --bg-soft: #1c1b19;
  --ink: #e8e3d6;
  --ink-soft: #998f7a;
  --line: #2a2926;
  --line-strong: #3a3833;
  --accent: #d8b48a;
  --danger: #e57369;
  --warn: #e2ad4e;
  --enc: #d9a542;
  --ok: #5cb96b;
  --quiet: #857e70;
  --info: #4c8bf5;
  --void: #0a0a09;
  --void-dot: #252523;
  --shadow: 0 6px 24px rgba(0, 0, 0, 0.5);
}

@media (prefers-color-scheme: dark) {
  :root[data-theme="auto"] {
    --bg: #121110;
    --bg-soft: #1c1b19;
    --ink: #e8e3d6;
    --ink-soft: #998f7a;
    --line: #2a2926;
    --line-strong: #3a3833;
    --accent: #d8b48a;
    --danger: #e57369;
    --warn: #e2ad4e;
    --enc: #d9a542;
    --ok: #5cb96b;
    --quiet: #857e70;
  --info: #4c8bf5;
    --void: #0a0a09;
    --void-dot: #252523;
    --shadow: 0 6px 24px rgba(0, 0, 0, 0.5);
  }
}

* { box-sizing: border-box; }

html, body {
  margin: 0;
  padding: 0;
  width: 100vw;
  height: 100vh;
  /* iPad PWA standalone：100% 在某些情况下不包含 home indicator 区域，100dvh 才覆盖整个物理屏幕 */
  height: 100dvh;
  overflow: hidden;
  background: var(--void);
  color: var(--ink);
  font: 14px/1.4 -apple-system, BlinkMacSystemFont, "Segoe UI", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", sans-serif;
  overscroll-behavior: none;
  -webkit-user-select: none;
  user-select: none;
  /* v216 (user：「手指长按 iPad 会弹选择菜单」)：全局压死 iOS 长按 callout/放大镜，
     不止 .board——工具栏/浮窗/handle 长按也别弹。input/textarea 单独豁免见下。 */
  -webkit-touch-callout: none;
  -webkit-tap-highlight-color: transparent;
  /* 全局墙掉浏览器双击 zoom / pinch zoom。canvas 单独 touch-action: none */
  touch-action: manipulation;
}

/* i18n 字形：<html lang> 由 src/i18n 动态设（zh-CN/en/ja/tok）。默认栈（body 上面）偏中文
   （PingFang/YaHei）→ 日文共享汉字会渲成中文字形，故 :lang(ja) 显式改日文字体栈。
   zh/en/tok 用默认栈即可（tok 拉丁走 -apple-system）。详 ai-docs/20260707-i18n-architecture.md §6。 */
body:lang(ja) {
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Hiragino Sans", "Hiragino Kaku Gothic ProN", "Yu Gothic", Meiryo, "Noto Sans JP", sans-serif;
}

/* tok = sitelen pona：nasin nanpa（vendor/nasin-nanpa，MIT，用户拍板 2026-07-25）。
   ASCII ligature 把拉丁 toki pona 词自动渲成 sitelen pona 字形（liga 默认开）；
   非 tp 字面量（PNG / Ctrl+Z / 中文作品名）落到 fallback 栈。 */
@font-face {
  font-family: "nasin nanpa";
  src: url("vendor/nasin-nanpa/nasin-nanpa-4.0.2.otf") format("opentype");
  font-display: swap;
  /* v0.5.36：只认领 UCSUR sitelen pona 块——nasin-nanpa 自带 ASCII 字形（拉丁被它画成怪样，
     真机 "dev"→"d≫"），限定 range 后 ASCII 逐字符回退系统字体。ligature 路线就此彻底退役。 */
  unicode-range: U+F1900-F19FF;
}
body:lang(tok) {
  font-family: "nasin nanpa", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
}
/* v0.5.34：字体走继承，但 button/select/input 默认**不继承**字体（UA 默认）——凡没写 font:inherit 的
   控件（如 .menu-tab 小字）在 tok 下漏成拉丁。tok 域下全控件强制继承，其他语言零影响。 */
body:lang(tok) button, body:lang(tok) select, body:lang(tok) input, body:lang(tok) textarea {
  font-family: inherit;
}

/* 顶栏 / 浮窗 / sheet / toast 上的所有 button / input：也明确写一遍，防 iOS
   在某些 Safari 版本上 element 默认仍允许 double-tap zoom */
button, input, .swatch, .tool, .float-panel, .top-bar, .hud, .sheet, .backdrop, .toast {
  touch-action: manipulation;
}

/* v216：文本输入框豁免全局 callout/select 禁用，否则改名/搜索时长按无法选词/粘贴 */
input[type="text"], input[type="search"], input:not([type]), textarea, [contenteditable] {
  -webkit-touch-callout: default;
  -webkit-user-select: text;
  user-select: text;
}

.board {
  position: fixed;
  inset: 0;
  width: 100%;
  height: 100%;
  display: block;
  touch-action: none;
  cursor: crosshair;
  /* 长按 canvas 时 iOS 会弹文本定位放大镜 / context menu。两条全压住。 */
  -webkit-touch-callout: none;
  -webkit-user-select: none;
  user-select: none;
}

/* v163：像素栅格 = 独立 canvas（仅视口变时重画，device-px 对齐 → 清晰均匀）+ 光标 div。
   主画布之上、UI(≥10) 之下。backing store 由 board.js 按需分配（隐藏时释放）。 */
.board-grid {
  position: fixed;
  inset: 0;
  width: 100%;
  height: 100%;
  display: none;
  pointer-events: none;
  z-index: 1;
}
body[data-mode="gallery"] .board-grid { display: none !important; }
.board-cursor {
  position: fixed;
  left: 0; top: 0;
  box-sizing: border-box;
  border-radius: 50%;
  border: 1px solid rgba(0, 0, 0, 0.65);
  box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.7);
  pointer-events: none;
  z-index: 2;
  display: none;
  will-change: transform;
}
body[data-mode="gallery"] .board-cursor { display: none !important; }
/* v232：像素笔（pixelMode）的 stamp 是方的，preview 跟着方，不再用圆误导 */
.board-cursor.square { border-radius: 0; }

body[data-tool="hand"] .board { cursor: grab; }
body[data-panning="1"] .board { cursor: grabbing !important; }
/* 橡皮 / 吸色 都跟画笔同 pointer style（默认 crosshair）；不再用 cell / copy 那种出戏光标 */
body[data-tool="lasso"] .board { cursor: crosshair; }
body[data-tool="fill"] .board { cursor: crosshair; }
/* （v0.6.31 回滚：长按蓄力动画与 tool-slot-open 互斥规则随组槽一起撤） */   /* v0.6.24：fill 与 lasso 同为选区族（审计#13 光标缺口） */

/* 套索浮层工具栏 —— 浮在顶栏下方居中，floating 选区存在时显示 */
/* 两行 stack 容器：1 行 = 选区方式，2 行 = 选区操作 / 变换 */
.lasso-toolbar-stack {
  position: fixed;
  /* v124 (user：「LASSO toolbar 和上面距离太高了」) 收 68 → 44 (top-bar 30 + 6 padding + 8 gap) */
  top: calc(max(env(safe-area-inset-top, 0px), 6px) + 44px);
  left: 50%;
  transform: translateX(-50%);
  display: flex;
  flex-direction: column;
  align-items: center;
  /* 两行间距也收 8 → 4 */
  gap: 4px;
  z-index: var(--z-toolbar);
  max-width: calc(100vw - 24px);
}

.lasso-toolbar {
  /* 内部 pill；stack 里堆两行。v124 padding 6→4 收一格 */
  display: flex;
  align-items: center;
  gap: 4px;
  padding: 4px;
  background: color-mix(in srgb, var(--bg) 94%, transparent);
  backdrop-filter: blur(16px) saturate(180%);
  -webkit-backdrop-filter: blur(16px) saturate(180%);
  border: 1px solid var(--line);
  border-radius: 999px;
  box-shadow: var(--shadow);
  /* 单行内若超长仍横滚兜底 */
  max-width: 100%;
  overflow-x: auto;
  scrollbar-width: none;
  -webkit-overflow-scrolling: touch;
  overscroll-behavior-x: contain;
}
.lasso-toolbar::-webkit-scrollbar { display: none; }
.lasso-tool-btn {
  background: transparent;
  border: none;
  /* v124 收 6×14 → 4×10 (user：「padding 都收一下」) */
  padding: 4px 10px;
  font: inherit;
  font-size: 13px;
  color: var(--ink);
  cursor: pointer;
  border-radius: 999px;
  white-space: nowrap;
}
.lasso-tool-btn:hover { background: color-mix(in srgb, var(--ink) 8%, transparent); }
/* 图标按钮：等宽方框，比文字按钮窄一半（user 反馈选区栏太宽）。 */
.lasso-tool-icon {
  padding: 4px 0;
  min-width: 32px;
  text-align: center;
  font-size: 16px;
  line-height: 20px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}
/* v123: lasso 子工具 / set-op 改 SVG */
.lasso-tool-icon svg {
  width: 20px;
  height: 20px;
}
.lasso-tool-btn[aria-pressed="true"] {
  background: color-mix(in srgb, var(--accent) 14%, transparent);
  color: var(--accent);
  font-weight: 600;
}
/* v0.6.34 自由度记账制：降不回去的变换模式置灰（用过更高自由度后） */
.lasso-tool-btn:disabled {
  opacity: 0.35;
  cursor: default;
  pointer-events: none;
}
.lasso-tool-sep { color: var(--ink-soft); margin: 0 4px; opacity: 0.4; }
.lasso-tool-text { color: var(--ink-soft); font-size: 12px; padding: 0 2px; white-space: nowrap; }
.lasso-tool-confirm { color: var(--accent); font-weight: 600; }
.lasso-tool-cancel { color: var(--ink); }   /* v0.5.14 user：去选不要半透明观感 */
.lasso-tool-label { font-size: 13px; color: var(--ink); font-weight: 600; padding: 0 8px; }
.lasso-picker, .lasso-transform-ctrl { display: flex; align-items: center; gap: 4px; }
.lasso-section { display: flex; align-items: center; gap: 4px; }
/* v0.5.14 工具组槽：右下角小三角=「这是组 toggle 不是指令」；紧凑图标下拉（JS 锚定槽下方） */
.lasso-slot { position: relative; }
/* 2026-09-11：select-field 钮面的角标也是这一颗（.select-field-caret span 包着同一枚 svg；user「比起用下箭头不如复用小三角」） */
.lasso-slot .lasso-slot-caret, .select-field .select-field-caret { position: absolute; right: 1px; bottom: 1px; width: 8px; height: 8px; opacity: .55; pointer-events: none; }
.select-field .select-field-caret > svg { display: block; width: 100%; height: 100%; }
/* ui/context-toolbar 工厂件（2026-09-06 U1）：chrome 复用 .lasso-toolbar-stack/.lasso-toolbar，这里只补工厂特有小件 */
.ct-title { color: var(--ink-soft); font-size: 13px; padding: 0 6px 0 8px; white-space: nowrap; }
.ct-sep { color: var(--line); padding: 0 2px; user-select: none; }
/* 2026-09-06 晚 ADR-0012 修订 ③：上下文条左段（子工具栏）宿主不占 flex 位；工厂 custom 宿主同 */
.verb-segment-host, .ct-custom { display: contents; }
/* 2026-09-09 排版修（user「中间空了一大堆……排版算法应该错了」）：左段**永不伸缩**——原 min-width: max(84px, 26vw) 在宽屏把两颗图标
   撑成三百多 px 的空白，窄屏又让左段先于「…」折叠被裁。放不下 = 工厂「…」折叠 → 行自身横滚兜底（.lasso-toolbar overflow-x）。 */
.verb-segment { flex: none; }
.verb-segment > .lasso-tool-btn { flex: none; }
/* 窄屏（SE2 375）：上下文条标题让位——左段已经点明是哪个工具，顶栏钮面也亮着 */
@media (max-width: 480px) {
  .ct-toolbar .ct-title { display: none; }
  /* 2026-09-09 SE2 375：子工具下拉（pin，不折）+ 一个旋钮要在 341px 行里放下 → 旋钮轨道 90→64、数值位 36→30；多旋钮（带颜料的手指）行横滚兜底 */
  .ct-toolbar .fb-inline-slider .ramp-slider { width: 64px; }
  .ct-toolbar .fb-inline-slider .brush-slider-value { min-width: 30px; }
}
.ct-select.select-field { border-radius: 999px; }
/* 2026-09-11 工具条下拉定宽（user「工具条上的自定义下拉框应该定宽，不然遇到英文会被撑的很宽」「还可以再窄一点」）：
   宽 = 该下拉自己量的「最宽缩写 + 自身 padding」（ui/select-field sizeFixed 写 style.width）；这里只是量不到时的兜底。只图标档按内容宽。 */
:root { --select-fixed-w: 72px; }
.select-field--fixed { width: var(--select-fixed-w); flex: none; box-sizing: border-box; }
.ct-toolbar .fb-inline-slider { padding: 0 4px; }
.ct-more svg { width: 18px; height: 18px; }
.lasso-icon-menu {
  position: fixed; display: flex; gap: 2px; padding: 4px;
  z-index: var(--z-popover);   /* v0.5.38：菜单内弹层要压过 menuPanel（同 z 时 DOM 序不可靠） */
  background: var(--bg-soft); border: 1px solid var(--line); border-radius: 8px; box-shadow: var(--shadow);
  color: var(--ink);
}
.lasso-icon-menu.lasso-icon-grid { display: grid; grid-template-columns: repeat(3, max-content); }
.lasso-icon-menu.lasso-icon-list { flex-direction: column; align-items: stretch; min-width: 168px; }
.lasso-icon-menu.lasso-icon-list > button { display: flex; align-items: center; justify-content: flex-start; gap: 8px; padding: 5px 8px; font-size: 12px; }
.lasso-icon-menu.lasso-icon-list > button svg { width: 18px; height: 18px; flex: 0 0 auto; }
/* v0.5.12 魔棒配置内联（阈值滑条+扩张toggle+px）+ ⋯ 菜单禁用态 */
.lasso-magic-ctx { display: flex; align-items: center; gap: 6px; }
.lasso-magic-ctx input[type="range"] { width: 88px; }
#lassoSelEditMenu button[disabled] { opacity: .38; pointer-events: none; }
/* 其他工具模式下有选区：lasso 工具栏只露"取消选区"（选区只是蒙板，不给 lasso 全套） */
#lassoSubToolBar.lasso-deselect-only > *:not(#lassoDeselectBtn) { display: none !important; }
/* v218 没选区：选区操作行只露"变换"（点了会隐式全选），其余需选区的按钮藏起来 */
#lassoSelectionActions.transform-only .lasso-needs-sel { display: none !important; }
.lasso-tool-threshold {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: 12px; color: var(--ink-soft);
  padding: 0 8px;
}
.lasso-tool-threshold input[type="range"] { width: 100px; }
/* 魔术棒设置弹出小卡片：位于 lasso-toolbar 下方居中 */
/* v271 (user)：弹框外观统一成「实底」——所有锚定/菜单类弹框共享这一套观感（去毛玻璃）。
   坐标走 positionPopup(JS)，外观走这里(CSS)；各 popup 规则只留 position/layout 特化。
   .menu-panel 覆盖了图层 ⋯/+ 菜单、图库各菜单（都带 menu-panel 类）。 */
.lasso-popup, .menu-panel, .menu-config-popup, .size-popup, .gallery-tile-menu-popup {
  background: var(--bg);
  border: 1px solid var(--line);
  border-radius: 8px;
  box-shadow: var(--shadow);
  color: var(--ink);
}
.lasso-popup {
  position: fixed;
  top: calc(max(env(safe-area-inset-top, 0px), 8px) + 116px);
  left: 50%;
  transform: translateX(-50%);
  display: flex; flex-direction: column;
  gap: 8px;
  padding: 10px 14px;
  z-index: var(--z-menu);  /* 菜单 band：高于 toolbar 和一切浮窗 */
  font-size: 12px;
  color: var(--ink);
  min-width: 220px;
}
.lasso-popup-row {
  display: grid;
  grid-template-columns: 32px 1fr 28px;
  align-items: center;
  gap: 8px;
}
.lasso-popup-row > span:first-child { color: var(--ink-soft); }
/* v0.7.3 扳手算法配置行：flex 布局走类不走 inline style——inline display 会压死 .hidden，
   行按当前算法显隐就失效（v0.7.2 两套参数同显的根因） */
.algo-cfg-row { display: flex; align-items: center; gap: 6px; }
.algo-cfg-row > span:first-child { color: var(--ink-soft); }
/* v0.7.21 容差滑条外提到 Row1（user：值要一直可见）；v0.7.22 换 ramp-slider 分段模式：
   宿主是 .brush-slider-row（grid 100px 标签列），内联场景压成 flex、空标签不占位 */
.lasso-tol-inline { display: inline-flex; align-items: center; gap: 6px; }
.lasso-tol-inline .brush-slider-row { display: flex; align-items: center; gap: 6px; }
.lasso-tol-inline .brush-slider-label { display: none; }
.lasso-tol-inline .ramp-slider { width: 120px; }
.lasso-tol-inline .brush-slider-value { min-width: 24px; }
/* 滤镜笔条内联旋钮（2026-09-05 手指「揉匀」）：复用 lasso 容差滑条样式，但标签要露出来 */
.fb-inline-slider .brush-slider-label { display: inline; color: var(--ink-soft); font-size: 12px; white-space: nowrap; }
.fb-inline-slider .ramp-slider { width: 90px; }
/* 2026-09-09：thumb 半径 8px 会压到左边标签 / 右边数值（真机截图「Dul●」）→ 间距 ≥ 8；数值定宽 + 等宽数字——
   "0%"→"100%" 不再改条宽（条居中，宽一变整条左右抖）。 */
.fb-inline-slider .brush-slider-row { gap: 10px; }
.fb-inline-slider .brush-slider-value { min-width: 36px; font-variant-numeric: tabular-nums; }
.lasso-popup-val { text-align: right; font-variant-numeric: tabular-nums; }
.lasso-popup-row input[type="range"] { width: 100%; }

/* 顶栏：浮动毛玻璃胶囊 */
.top-bar {
  position: fixed;
  top: max(env(safe-area-inset-top, 0px), 6px);
  left: 50%;
  transform: translateX(-50%);
  display: flex;
  align-items: center;
  /* v124 (user：「app 各种 padding 都收一下，小屏笔架空间不够」) */
  gap: 2px;
  padding: 4px 6px;
  background: color-mix(in srgb, var(--bg) 80%, transparent);
  backdrop-filter: blur(16px) saturate(180%);
  -webkit-backdrop-filter: blur(16px) saturate(180%);
  border: 1px solid var(--line);
  border-radius: 999px;
  box-shadow: var(--shadow);
  z-index: var(--z-chrome);
  max-width: calc(100% - 24px);
  flex-wrap: nowrap;
  overflow-x: auto;
  scrollbar-width: none;
}
.top-bar::-webkit-scrollbar { display: none; }

.tool-group, .color-group {
  display: flex;
  align-items: center;
  gap: 2px;
  padding: 0 4px;
}
/* 顶栏 separator —— vertical hairline，替代旧 .group border-right */
.top-bar-sep {
  width: 1px;
  height: 24px;
  background: var(--line);
  margin: 0 4px;
}
/* hand 工具：触屏设备双指 pan 已足够，不显示 */
body[data-input-touchscreen="1"] .tool-hand-conditional { display: none; }

/* v415 删：smudge / shapes 两个工具按钮早已从 index.html purge（v309 / v120），
   .tool[data-tool="smudge"|"shapes"] 和 .tool-disabled 都已无 DOM 命中。
   将来真做这两个功能时 greenfield 重来，别复活这些残骸。 */

/* 左侧栏 (drawing 时常驻) */
/* v134 (user：「左 panel 还是有点粗」) 紧 12px：52→40
   brush 缩到 32×32（笔名 2 字 8px font 仍可见）；slider 24，足够 thumb tap */
.left-sidebar {
  position: fixed;
  left: max(env(safe-area-inset-left, 0px), 8px);
  top: 50%;
  transform: translateY(-50%);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
  padding: 8px 4px;
  background: color-mix(in srgb, var(--bg) 80%, transparent);
  backdrop-filter: blur(16px) saturate(180%);
  -webkit-backdrop-filter: blur(16px) saturate(180%);
  border: 1px solid var(--line);
  border-radius: 12px;
  box-shadow: var(--shadow);
  z-index: calc(var(--z-chrome) - 1);   /* < top-bar */
  width: 40px;
  box-sizing: border-box;
}
/* gallery 模式隐藏 */
body[data-mode="gallery"] .left-sidebar { display: none; }

/* 竖滑块 ——iPad Safari + Chrome 都支持 -webkit-appearance: slider-vertical */
.left-sidebar-slider {
  -webkit-appearance: slider-vertical;
  appearance: slider-vertical;
  writing-mode: vertical-lr;
  direction: rtl;
  width: 24px;
  max-width: 24px;       /* 防 Firefox / appearance 不支持时撑宽 */
  height: 120px;
  background: transparent;
  padding: 0;
  margin: 0;
}
.left-sidebar-label {
  font-size: 11px;
  color: var(--ink-soft);
  user-select: none;
  margin-top: -4px;
}
/* v0.6.16 笔压 toggle = 笔粗图标本体（user：不要多一个难受的按钮）：
   禁用时图标换 brush-width-locked + accent 着色 */
.left-sidebar-label-btn { background: none; border: none; padding: 2px; cursor: pointer; }
.left-sidebar-label-btn[aria-pressed="true"] { color: var(--accent); }
.left-sidebar-label-btn:disabled { opacity: .4; cursor: default; }
/* 当前笔指示器 + 编辑入口 */
.left-sidebar-brush {
  width: 32px;
  height: 32px;
  padding: 2px;
  background: var(--bg-soft);
  border: 1px solid var(--line);
  border-radius: 6px;
  cursor: pointer;
  font: inherit;
  color: var(--ink);
  display: flex; align-items: center; justify-content: center;
  font-size: 8px;
  line-height: 1.1;
  text-align: center;
  overflow: hidden;
}
.left-sidebar-brush:hover { filter: brightness(0.95); }
/* 2026-09-06 左栏一次性取样钮：取样态反色（同顶栏工具钮 pressed） */
.left-sidebar-pick[aria-pressed="true"] { background: var(--ink); color: var(--bg); border-color: var(--ink); }
.cw-pick { background: transparent; border: 1px solid var(--line); border-radius: 6px; width: 28px; height: 28px; padding: 0; display: inline-flex; align-items: center; justify-content: center; color: var(--ink); cursor: pointer; flex: none; }
.cw-pick svg { width: 16px; height: 16px; }
.cw-pick:hover { background: var(--bg-soft); }
/* v134 (user：「笔刷名碰到超级长不应变形」) 强制内容不撑父容器 */
.left-sidebar-brush {
  flex-shrink: 0;
  min-width: 0;       /* flex 子默认 min-width=auto，会被内容撑大；归 0 */
}
.left-sidebar-brush-name {
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
  word-break: break-all;
  max-width: 100%;
}

/* v124b dev 环境 chip：HUD 里的小红标签 (user：「让我们知道是 dev」) */
.env-chip {
  background: #dc2626;
  color: #fff;
  font-size: 10px;
  font-weight: 700;
  padding: 1px 6px;
  border-radius: 4px;
  letter-spacing: 0.6px;
  margin-left: 4px;
}

.tool {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  /* v124 收 36 → 32 (user) */
  width: 32px;
  height: 32px;
  padding: 0;
  border: none;
  background: transparent;
  color: var(--ink);
  border-radius: 8px;
  cursor: pointer;
  transition: background 0.12s ease;
}
.tool { position: relative; }   /* 2026-09-06 动词位小三角定位锚 */
.tool .tool-caret { position: absolute; right: 2px; bottom: 2px; width: 8px; height: 8px; opacity: .55; pointer-events: none; }
.tool:hover { background: var(--bg-soft); }
.tool:active { background: var(--line); }
.tool[aria-pressed="true"] {
  background: var(--ink);
  color: var(--bg);
}
.tool:disabled { opacity: 0.35; cursor: default; }
.tool:disabled:hover { background: transparent; }
.tool svg { width: 20px; height: 20px; }

.swatch {
  width: 22px;
  height: 22px;
  border-radius: 50%;
  border: 2px solid var(--line);
  background: var(--c, #000);
  cursor: pointer;
  padding: 0;
  margin: 0 2px;
  transition: transform 0.12s ease, border-color 0.12s ease;
}
.swatch:hover { transform: scale(1.08); }
.swatch[aria-pressed="true"] {
  border-color: var(--ink);
  transform: scale(1.12);
}
.swatch.active-color {
  width: 28px;
  height: 28px;
  border-color: var(--ink);
  margin-right: 6px;
  /* 当前颜色由 JS 设 background */
}

input[type=range] {
  accent-color: var(--ink);
}
#sizeSlider { width: 100px; }
#opacitySlider { width: 80px; }

.spacer {
  width: 1px;
  height: 24px;
  background: var(--line);
  margin: 0 4px;
}

/* HUD 右下角 */
.hud {
  position: fixed;
  right: max(env(safe-area-inset-right, 0px), 12px);
  bottom: max(env(safe-area-inset-bottom, 0px), 12px);
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 4px 10px;
  background: color-mix(in srgb, var(--bg) 80%, transparent);
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
  border: 1px solid var(--line);
  border-radius: 999px;
  font-size: 12px;
  color: var(--ink-soft);
  z-index: var(--z-chrome);
  pointer-events: none;
}
.hud .sep { opacity: 0.5; }
.hud .version { opacity: 0.55; font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; }

/* Sheets / dialogs */
.backdrop {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.35);
  /* modal band > overlay band —— 在图库里点新建/改名也看得到 sheet */
  z-index: var(--z-modal);
  opacity: 1;
  transition: opacity 0.18s ease;
}
.backdrop:not([data-open]) {
  opacity: 0;
  pointer-events: none;
}

.sheet {
  position: fixed;
  left: 50%;
  bottom: max(env(safe-area-inset-bottom, 0px), 20px);
  transform: translateX(-50%);
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding: 10px;   /* v0.5.21 user：sheet 极简省空间——不妨碍点击就省 */
  width: min(320px, calc(100% - 32px));
  background: var(--bg);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  z-index: calc(var(--z-modal) + 1);
  transition: transform 0.22s ease, opacity 0.18s ease;
}
.sheet:not([data-open]) {
  transform: translate(-50%, 20px);
  opacity: 0;
  pointer-events: none;
}
.sheet h3 {
  margin: 0 0 4px 0;
  font-size: 16px;
  font-weight: 600;
}
/* v124 sheet 通用 head（close 在右）+ body 滚动 */
.sheet-head { display: flex; align-items: center; justify-content: space-between; }
.sheet-title { font-size: 16px; font-weight: 600; }
.sheet-close {
  background: transparent; border: none; cursor: pointer;
  font-size: 22px; line-height: 1; color: var(--ink-soft);
  padding: 0 4px;
}
.sheet-close:hover { color: var(--ink); }
/* v124 (user 小屏)：用 dvh 单位 + sheet 自身 max-height + body 内滚 */
.sheet-body { max-height: calc(75dvh - 60px); overflow-y: auto; }

/* v124 快捷键 sheet：稍宽，list 网格 */
.shortcuts-sheet { width: min(420px, calc(100% - 24px)); max-height: 80dvh; }
.shortcuts-category {
  font-size: 11px; color: var(--ink-soft); text-transform: uppercase;
  letter-spacing: 0.6px; margin: 10px 0 4px;
}
.shortcuts-row {
  display: flex; justify-content: space-between; align-items: center;
  padding: 4px 0; font-size: 13px;
}
/* 2026-09-02 内置说明书（readme-panel.ts）：宽一点、md-lite 排版；深链进来的节闪一下底色 */
.readme-sheet { width: min(520px, calc(100% - 24px)); }
.readme-body { font-size: 13px; line-height: 1.5; }
.readme-section { padding: 6px 2px 10px; border-radius: 6px; }
.readme-section + .readme-section { border-top: 1px solid var(--line); margin-top: 6px; }
.readme-section h3 { margin: 0 0 6px; font-size: 14px; font-weight: 600; }
.readme-section h4 { margin: 8px 0 4px; font-size: 13px; font-weight: 600; }
.readme-section p { margin: 0 0 8px; }
.readme-section ul { margin: 0 0 8px; padding-left: 18px; }
.readme-section li { margin: 2px 0; }
.readme-section a { color: var(--accent); }
.readme-section code { font-family: ui-monospace, Menlo, Consolas, monospace; font-size: 12px; padding: 1px 4px; border-radius: 4px; background: color-mix(in srgb, var(--ink) 8%, transparent); }
.readme-section.flash { animation: readme-flash 1.6s ease-out; }
@keyframes readme-flash { 0% { background: color-mix(in srgb, var(--accent) 22%, transparent); } 100% { background: transparent; } }
.shortcuts-combo {
  font-family: ui-monospace, Menlo, Consolas, monospace;
  font-size: 12px;
  padding: 2px 6px; border-radius: 4px;
  background: color-mix(in srgb, var(--ink) 8%, transparent);
  color: var(--ink);
}
.sheet-hint {
  margin: 0 0 8px 0;
  font-size: 13px;
  color: var(--ink-soft);
}
.sheet-action {
  display: block;
  width: 100%;
  padding: 12px 14px;
  border: 1px solid var(--line);
  background: var(--bg-soft);
  color: var(--ink);
  border-radius: 8px;
  font-size: 14px;
  cursor: pointer;
  text-align: left;
  transition: background 0.12s ease;
}
.sheet-action:hover { background: var(--line); }
.sheet-action.ghost {
  background: transparent;
  border-color: transparent;
  text-align: center;
  color: var(--ink-soft);
}
.sheet-action.danger {
  background: var(--danger);
  border-color: var(--danger);
  color: #fff;
}
.sheet-action.danger:hover {
  filter: brightness(0.92);
}
/* v0.7.9 按颜色拆分 sheet：带图标的动作按钮 + 中心色 swatch 行（chip 底色 = 簇心，em = 采样占比） */
.sheet-action-with-icon { display: flex; align-items: center; justify-content: center; gap: 8px; }
.sheet-action-with-icon svg { width: 18px; height: 18px; flex: none; }
/* （explodeCultureMenu 静态节点已退役 2026-09-02：sheet 内下拉走 popup-menu band:"modal"，见下 .popup-menu.band-modal） */
.explode-swatches {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin: 4px 0 10px 0;
  min-height: 44px;   /* 两档 k 之间行数不跳（≤8 个 swatch 单行放得下） */
  align-content: flex-start;
}
.explode-swatch { display: flex; flex-direction: column; align-items: center; gap: 2px; }
.explode-swatch i {
  width: 28px;
  height: 28px;
  border-radius: 6px;
  border: 1px solid var(--line);
  /* 深浅主题下都能看清极浅/极深的簇心：底衬棋盘由边框兜底即可，纯色 chip 不再加纹理 */
}
.explode-swatch em {
  font-style: normal;
  font-size: 11px;
  color: var(--ink-soft);
}
/* 文本框 IntelliSense（共享控件 input-sense，usage-agnostic）：media 前导块 + label 候选。
   z 走 popover band（420，压过菜单/浮窗；⚠ 在 sheet(500) 内用会被盖住——现消费者只有色轮浮窗）。 */
.menu-panel.input-sense-menu {   /* 双类提 specificity：本规则在 .menu-panel 定义之前，单类会被其 z 反杀 */
  z-index: var(--z-popover);
  min-width: 150px;
  max-height: 240px;
}
.input-sense-item {
  display: flex;
  align-items: center;
  gap: 8px;
  width: 100%;
  padding: 6px 10px;
  background: none;
  border: none;
  border-radius: 6px;
  color: var(--ink);
  font-size: 13px;
  cursor: pointer;
  text-align: left;
}
.input-sense-item.active,
.input-sense-item:hover { background: var(--line); }
.color-chip {   /* 色名数据源的 media：色板小方块（explode swatch 同族视觉） */
  width: 16px;
  height: 16px;
  border-radius: 4px;
  border: 1px solid var(--line);
  flex: none;
}
/* sense 下拉滚动条：对齐家规（galleryMount 同款）——移动端保系统 overlay，
   桌面（pointer:fine）常显窄条 + color-mix 圆角 thumb，不用默认粗滚动条。 */
@media (pointer: fine) {
  .input-sense-menu {
    scrollbar-width: thin;
    scrollbar-gutter: stable;
  }
  .input-sense-menu::-webkit-scrollbar { width: 10px; }
  .input-sense-menu::-webkit-scrollbar-thumb {
    background: color-mix(in srgb, var(--ink) 22%, transparent);
    border-radius: 6px;
    border: 2px solid transparent;
    background-clip: padding-box;
  }
  .input-sense-menu::-webkit-scrollbar-thumb:hover {
    background: color-mix(in srgb, var(--ink) 36%, transparent);
    background-clip: padding-box;
  }
}

.explode-swatch-name {   /* 颜色名（iPad 无 hover，不能只藏 title）——窄列省略号截断 */
  font-size: 10px;
  color: var(--ink-soft);
  max-width: 52px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* 2026-09-02 C5 可见性唯一规则（src/ui/visibility.ts）：.hidden / [hidden] 永远赢——组件的 display:flex 曾多次压过它
   （v419 menu-item、v0.6.54 crop-toolbar-icon、v0.10.21 menuGallery…），逐组件「hidden 时 display none」补丁 ×41 已全删，
   build.sh lint 禁再加。动画类面（sheet/backdrop）改 data-open 状态属性，不借用 .hidden。 */
.hidden { display: none !important; }
[hidden] { display: none !important; }

/* v217 新建文件 preset 按钮组（取代 <select>） */
.new-doc-preset-section { display: flex; flex-direction: column; gap: 4px; }
.new-doc-preset-label {
  font-size: 11px;
  color: var(--ink-soft);
  font-weight: 600;
  letter-spacing: 0.5px;
  text-transform: uppercase;
  padding: 2px 0 0 2px;
}
.preset-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 5px;
}
.preset-chips button {
  padding: 5px 10px;
  border: 1px solid var(--line);
  background: var(--bg-soft);
  color: var(--ink);
  border-radius: 6px;
  font-size: 12px;
  cursor: pointer;
  white-space: nowrap;
  transition: background 0.1s, border-color 0.1s;
}
.preset-chips button:hover { background: var(--line); }
.preset-chips button[aria-pressed="true"] {
  background: var(--ink);
  color: var(--bg);
  border-color: var(--ink);
}

/* 汉堡菜单：低频设置 / 操作集合。文字标签 + 状态字。点空白外面关闭。 */
.menu-panel {
  position: fixed;
  top: 56px;
  /* v123 菜单按钮从右挪到左 (Procreate 顺序)，panel 也跟着挪 */
  left: 12px;
  min-width: 200px;
  /* 2026-08-21：面板宽度封顶——长 label+sub+扳手的行（导出与另存等）靠行内省略号收，不许把面板撑出屏 */
  max-width: min(320px, calc(100vw - 24px));
  /* 长菜单 + iPad mini 竖屏：限高 + 滚动 */
  max-height: calc(100vh - 80px);
  overflow-y: auto;
  /* 外观（实底 bg/border/radius/shadow）走共享规则 */
  z-index: var(--z-menu);  /* user：「主菜单 zorder 应该在 lasso 等的菜单上面」；菜单 band 结构性高于窗口/overlay */
  padding: 6px;
  -webkit-overflow-scrolling: touch;
  overscroll-behavior: contain;
}
/* 2026-09-02 popup-menu 深模块（src/ui/popup-menu.ts）：运行时挂 body 的菜单。外观复用 .menu-panel（list）/
   .lasso-icon-menu.lasso-icon-list（compact）；这里只定 z band 与几个附件。双类 specificity 压过基类的 z。 */
.popup-menu.band-menu    { z-index: var(--z-menu); }
.popup-menu.band-popover { z-index: var(--z-popover); }
.popup-menu.band-modal   { z-index: calc(var(--z-modal) + 5); }   /* sheet(--z-modal) 内的下拉：modal 之上、busy 之下 */
.popup-menu--list { top: auto; left: auto; }                       /* 坐标全由 positionPopup 写 inline */
.popup-menu-sep { border: none; border-top: 1px solid var(--line); margin: 4px 2px; }
.popup-menu-item.danger, .popup-menu-item.danger svg { color: var(--danger); }
.menu-section-label {
  font-size: 10px;
  color: var(--ink-soft);
  padding: 6px 12px 2px;
  letter-spacing: 0.6px;
  text-transform: uppercase;
  user-select: none;
  font-weight: 600;
  opacity: 0.7;
}
.menu-item {
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 10px 12px;
  background: transparent;
  border: none;
  border-radius: 6px;
  font: inherit;
  color: var(--ink);
  cursor: pointer;
  text-align: left;
}
/* （.menu-item[hidden] 补丁 2026-09-02 C5 退役：[hidden] 基类已 !important） */
.menu-item:hover { background: color-mix(in srgb, var(--ink) 8%, transparent); }
/* v132 (user：「··· 删除会有不可用的清空，要灰」) menu item disabled = 灰 + 禁交互 */
.menu-item:disabled { opacity: 0.35; cursor: not-allowed; }
.menu-item:disabled:hover { background: transparent; }
/* v419 原本用排版字符当图标的地方（× ⋯ ← ↘ ☑ ☐）换成了 sprite <use>。
   这些按钮原先靠 font-size 定大小，现在装的是 svg，得显式给尺寸。
   分组按视觉层级：关闭键 16、溢出菜单 18、调色小窗工具 20、行内小徽章 13-16。 */
.palette-close svg, .brush-rack-close svg, .float-panel-close svg,
.sheet-close svg, .close-x svg, .dismiss svg, .btp-x svg { width: 16px; height: 16px; display: block; }
.menu-item-wrench svg, .layer-tools-btn svg, .gallery-tile-menu-btn svg,
.gallery-trash-menu-btn svg, .brush-rack-tile-edit svg { width: 18px; height: 18px; display: block; }
.palette-tools button svg { width: 20px; height: 20px; display: block; }
.gallery-back-btn { display: inline-flex; align-items: center; gap: 6px; }
.gallery-back-btn svg { width: 18px; height: 18px; flex: none; }
.layer-clip-chip svg { width: 13px; height: 13px; display: block; }

/* v124 menu-item 带 SVG icon（目前只用于图库）：左对齐 + 间距 */
.menu-item.menu-item-with-icon { justify-content: flex-start; gap: 10px; }
.menu-item.menu-item-with-icon svg { width: 18px; height: 18px; flex-shrink: 0; }
/* v419 前缀图标铺开到所有菜单项。动机是 localization：菜单项文字换成英文会变长，
   图标是语言无关的锚点——也给不认字的小孩和找不到语言设置的人一个能认的入口。
   with-icon 把 space-between 换成了 flex-start+gap，所以原先靠 space-between 顶到右边的
   状态字 / 副标题 / 语言下拉，要显式 margin-left:auto 才回得去。 */
/* 没有图标的菜单项：占一个同宽空位，让这一列文字仍然对齐。
   是「留空」不是「缺图标」——user 明确要求不为了填满而硬塞图标。 */
.menu-item-icon-blank { width: 18px; height: 18px; flex: none; }
.menu-item.menu-item-with-icon .menu-item-state,
.menu-item.menu-item-with-icon .menu-item-sub,
.menu-item.menu-item-with-icon .menu-lang-select { margin-left: auto; }
/* 回收站菜单项不是 .menu-item（另一套 class），单独给一份同样的排版 */
.gallery-trash-menu-item.menu-item-with-icon { display: flex; align-items: center; gap: 10px; }
.gallery-trash-menu-item.menu-item-with-icon svg { width: 18px; height: 18px; flex-shrink: 0; }

/* 语言：⋯ 菜单里的下拉框行（label + select） */
.menu-lang-row { display: flex; align-items: center; justify-content: space-between; gap: 8px; cursor: pointer; }
.menu-lang-select { flex: 0 0 auto; max-width: 140px; }
/* v0.5.37 in-app 下拉按钮（替代原生 select）：沿用 select 的视觉位，加 caret */
.menu-inline-select {
  display: inline-flex; align-items: center; gap: 5px;
  font: inherit; font-size: 12px; padding: 4px 8px; border-radius: 6px;
  border: 1px solid color-mix(in srgb, var(--ink) 20%, transparent);
  background: transparent; color: var(--ink); cursor: pointer;
}
.menu-inline-caret { width: 8px; height: 8px; opacity: .6; flex: 0 0 auto; }
/* 2026-09-02 C6 下拉标准件（src/ui/select-field.ts）：原生 <select> 退役。按钮沿用各处既有 class 的皮（.lasso-tool-select /
   .generic-sheet-input / .crop-toolbar-btn），这里只补 label+caret 排版与分组标题。 */
.select-field { display: inline-flex; align-items: center; gap: 5px; cursor: pointer; text-align: left; position: relative; }
.select-field .select-field-label { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; }
/* 角标 = 右下角小三角（.select-field-caret，几何见 .lasso-slot-caret 共享规则）；文字给它让 12px */
button.select-field { padding-right: 12px; }
/* 2026-09-09 带图标的下拉（user「手指的几种工具用下拉框吧，图标太打哑谜了」）：钮面 = 当前项图标 + label + caret；弹层项 icon 归 popup-menu compact */
.select-field .select-field-icon { display: inline-flex; flex: none; }
.select-field .select-field-icon svg { width: 18px; height: 18px; }
.popup-menu-group { font-size: 10px; color: var(--ink-soft); padding: 6px 8px 2px; text-transform: uppercase; letter-spacing: .06em; user-select: none; }
.menu-item-state { color: var(--ink-soft); font-size: 12px; }
/* P5 scope 分区（2026-08-27 拍板「人话标题+行尾微章」）：设置项按归属分组，微章答「这设置跟谁走」 */
.menu-section-label { font-size: 11px; color: var(--ink-soft); padding: 10px 14px 2px; user-select: none; letter-spacing: .06em; opacity: .85; }
/* 微章右对齐（user 2026-08-28「放在 on 后面，整齐」）：flex order 挪到行尾最右——9 处 markup 零改 */
.menu-scope-badge { width: 13px; height: 13px; flex: none; color: var(--ink-soft); opacity: .5; margin-left: 6px; order: 3; }
/* v0.6.14 版本号（menu/图库两处）：去「版本：」前缀后再压瘦——字号降一档 + 横向 92% 压缩省行宽 */
.version-slim { display: inline-block; font-size: 10.5px; letter-spacing: -0.02em; transform: scaleX(0.92); transform-origin: right center; white-space: nowrap; }
div.version-slim { transform-origin: left center; }   /* 图库菜单的 info 行左对齐，压缩锚点跟着靠左 */
.menu-item[aria-pressed="true"] .menu-item-state { color: var(--accent); font-weight: 600; }
.menu-item.menu-danger { color: #c0392b; }

/* v120：菜单一行两钮（主操作 + 配置 🔧）。
   主钮 = 一键执行当前 sticky config；🔧 = 弹 inline popup 改 config */
.menu-item-row {
  display: flex;
  align-items: stretch;
  gap: 2px;
  position: relative;
}
.menu-item-row .menu-item-main { flex: 1 1 auto; min-width: 0; }   /* min-width:0：行内 label/sub 允许收缩（2026-08-21 user：导出行宽超了） */
.menu-item-row .menu-item-main .menu-item-label { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; min-width: 0; }
.menu-item-sub {
  color: var(--ink-soft);
  font-size: 11px;
  margin-left: 8px;
  white-space: nowrap;
  overflow: hidden; text-overflow: ellipsis; min-width: 0; flex: 0 1 auto;   /* 空间不够时 sub 先缩（带省略号），不许把行撑爆 */
}
/* v124 wrench → ⋯（user：「导入导出用 ⋯ 更合适，扳手 SVG 留备用」）
   .menu-item-wrench class 名留着——只是字符换了，将来想换回扳手只改 HTML 里那个字符即可 */
.menu-item-wrench {
  display: flex; align-items: center; justify-content: center;
  width: 36px; padding: 0;
  background: transparent; border: none; border-radius: 6px;
  color: var(--ink-soft); cursor: pointer; flex: 0 0 36px;
  font: inherit; font-size: 20px; line-height: 1;
}
.menu-item-wrench:hover { background: color-mix(in srgb, var(--ink) 8%, transparent); color: var(--ink); }
.menu-config-popup {
  /* 2026-09-02：位置/z 归 popup-menu（收养挂 body、锚到扳手、band popover）；原 absolute+裸 z 50 会被主菜单 overflow 裁 */
  padding: 10px 12px;
  /* 外观（实底）走共享规则 */
  min-width: 180px;
  display: flex; flex-direction: column; gap: 8px;
}
.menu-config-popup label { display: flex; align-items: center; gap: 6px; font-size: 13px; cursor: pointer; color: var(--ink); }
.menu-config-popup .menu-config-section { display: flex; flex-direction: column; gap: 4px; }
.menu-config-popup .menu-config-title { font-size: 11px; color: var(--ink-soft); text-transform: uppercase; }
/* v0.6C：定宽只给 ☰ 主菜单（.menu-panel 是共享类——图层 +菜单/⋯菜单也穿它，v0.5.28 真机撑宽事故） */
#menuPanel { width: 300px; max-width: calc(100vw - 16px); }

/* v0.5.28 生成式 AI 总开关接缝：未启用时一切 AI 相关 UI 隐藏（挂 .needs-gen-ai 类即受控） */
body:not([data-gen-ai="1"]) .needs-gen-ai { display: none !important; }

/* v0.6C ☰ 六 tab 分页（图库=文件页首项） */
.menu-tabs { display: flex; gap: 2px; padding: 4px 4px 3px; border-bottom: 1px solid var(--line); margin-bottom: 4px; }
.menu-tab {
  flex: 1 1 0; min-width: 0; display: flex; flex-direction: column; align-items: center; gap: 1px;
  padding: 3px 2px; background: transparent; border: none; border-radius: 6px;
  color: var(--ink-soft); cursor: pointer; font-size: 10px; line-height: 1.2;
}
/* Procreate 式定宽小字：非中文长词 nowrap+省略，不撑 tab（面板已定宽） */
.menu-tab span { max-width: 100%; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.menu-tab svg { width: 18px; height: 18px; display: block; }
.menu-tab[aria-pressed="true"] { color: var(--accent); background: color-mix(in srgb, var(--accent) 12%, transparent); }
.menu-page { display: flex; flex-direction: column; }

.menu-config-select {
  font: inherit; font-size: 12px; padding: 4px 6px; border-radius: 4px;
  border: 1px solid color-mix(in srgb, var(--ink) 20%, transparent);
  background: transparent; color: var(--ink); cursor: pointer; max-width: 100%;
}
/* v0.5.40 系统排查：所有原生 select 的 option 一次主题化（夜间白底白字这坑第三次出现，全局绝根） */
option { background: var(--bg); color: var(--ink); }
.menu-config-select:disabled { opacity: .5; }

/* v120：lasso 工具栏的 dropdown（采样模式 3 按钮 → 1 select） */
.lasso-tool-select {
  font: inherit; font-size: 12px;
  padding: 4px 6px; border-radius: 4px;
  border: 1px solid color-mix(in srgb, var(--ink) 20%, transparent);
  background: transparent; color: var(--ink); cursor: pointer;
}
/* v0.7.8 算法组槽（button.lasso-tool-select，系统 select 退役）：文字给右下角小三角让位 */
button.lasso-tool-select.lasso-slot { padding-right: 12px; }
/* v0.5.13：夜间主题下拉列表（option）修——UA 弹层默认白底，文字继承了亮色 --ink → 白底白字看不见。
   显式给 option 上主题底/字色（iPad 原生滚轮选择器不受影响，桌面 Chromium/Firefox 生效）。 */

/* 笔刷设置浮动面板（沿用 .float-panel 框架） */
.brush-panel { width: 280px; }

/* 参考小窗：浮动 panel + 可拖右下角缩放 + 内部 canvas */
/* 参考窗（C9）：chrome/手势样式全在 <wp-reference-window> shadow 内（src/frontend/reference-window.ts）。
   宿主侧只留三条：①define 前不闪 light DOM（FOUC 守卫，家族组件约定）；②slot 文案排版。
   gallery 模式隐藏见下 body[data-mode="gallery"] 段。 */
wp-reference-window:not(:defined) { display: none; }
wp-reference-window [slot="empty"] p { margin: 0; }
.brush-slider-row {
  display: grid;
  grid-template-columns: 100px 1fr 30px;
  align-items: center;
  gap: 8px;
  font-size: 13px;
  color: var(--ink);
}
.brush-slider-label { color: var(--ink-soft); }
.brush-slider-value { text-align: right; color: var(--ink); font-variant-numeric: tabular-nums; }

/* v132 (user：「色彩平衡和 HSV 看不到 colorful slider」)
   range input 默认 track 盖了 background-image，加 .color-ramp 切自定义 track
   只对显式声明的 ramp slider 生效，其他 slider 保持系统默认外观 */
input[type="range"].color-ramp {
  -webkit-appearance: none;
  appearance: none;
  height: 14px;
  border-radius: 7px;
  outline: none;
  padding: 0;
  border: 1px solid var(--line);
  background-size: 100% 100%;
  background-repeat: no-repeat;
}
input[type="range"].color-ramp::-webkit-slider-runnable-track {
  height: 14px;
  background: transparent;
  border-radius: 7px;
}
input[type="range"].color-ramp::-moz-range-track {
  height: 14px;
  background: transparent;
  border-radius: 7px;
}
input[type="range"].color-ramp::-webkit-slider-thumb {
  -webkit-appearance: none;
  width: 16px;
  height: 16px;
  border-radius: 50%;
  background: #fff;
  border: 2px solid #222;
  cursor: pointer;
  margin-top: -2px;
  box-shadow: 0 1px 2px rgba(0,0,0,0.3);
}
input[type="range"].color-ramp::-moz-range-thumb {
  width: 16px;
  height: 16px;
  border-radius: 50%;
  background: #fff;
  border: 2px solid #222;
  cursor: pointer;
  box-shadow: 0 1px 2px rgba(0,0,0,0.3);
}

/* v0.7.8 ramp-slider（ui/ramp-slider.ts + 色轮 hue 条）：自绘 track+thumb 替代原生 range——
   原生 range 做不了 shift 细调（指针动、值慢动）。外观对齐 .color-ramp 老样式。 */
.ramp-slider {
  position: relative;
  height: 14px;
  border-radius: 7px;
  border: 1px solid var(--line);
  background: var(--bg-soft, rgba(128,128,128,0.25));
  background-size: 100% 100%;
  background-repeat: no-repeat;
  touch-action: none;
  cursor: pointer;
  outline-offset: 2px;
}
.ramp-slider-thumb {
  position: absolute;
  top: 50%;
  left: 0;
  width: 16px;
  height: 16px;
  border-radius: 50%;
  background: #fff;
  border: 2px solid #222;
  box-shadow: 0 1px 2px rgba(0,0,0,0.3);
  transform: translate(-50%, -50%);
  pointer-events: none;   /* 拖动全归 track（thumb 只是指示器——shift 细调时它本就独立于光标） */
}

.menu-sep {
  border: 0;
  border-top: 1px solid var(--line);
  margin: 4px 8px;
}

/* 图层面板 */
.layers-panel {
  top: 60px;
  right: 16px;
  left: auto;        /* 覆盖 .float-panel 默认 left:16 */
  width: 240px;      /* 默认宽；#13 用户可拖右下角手柄调，随 editorState 持久化 */
}
/* #13 面板右下角调大小手柄：22px 触控热区，三道斜纹（纯 CSS，不是图标）。 */
.float-panel-resize {
  position: absolute; right: 0; bottom: 0;
  width: 22px; height: 22px;
  cursor: nwse-resize;
  touch-action: none;
  opacity: 0.55;
  background: linear-gradient(135deg,
    transparent 0 45%, var(--ink-soft) 45% 52%,
    transparent 52% 66%, var(--ink-soft) 66% 73%,
    transparent 73%);
  border-bottom-right-radius: inherit;
}
.float-panel-subtle { color: var(--ink-soft); font-weight: normal; font-size: 12px; margin-left: 6px; }
.float-panel-close {
  background: transparent;
  border: none;
  font-size: 18px;
  color: var(--ink-soft);
  cursor: pointer;
  padding: 0 4px;
}
/* 图层面板头 PiP shortcut（0830）：head 是 space-between 布局，auto margin 把双钮一起推右侧 */
#layersPanelRefBtn { margin-left: auto; }
.layers-list {
  display: flex;
  flex-direction: column;
  gap: 1px;
  padding: 4px;
  overflow-y: auto;   /* 高度恒由 _clampListHeight 写死（v0.5.23 硬高度拍板），50vh 上限退役 */
}
.layer-row {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 3px 8px;   /* v0.5.21 user：紧凑 compact——删不必要行间距 */
  background: transparent;
  border: 1px solid transparent;
  border-radius: 6px;
  cursor: pointer;
  user-select: none;
}
.layer-row:hover { background: color-mix(in srgb, var(--ink) 6%, transparent); }
.layer-row.active {
  background: color-mix(in srgb, var(--accent) 14%, transparent);
  border-color: color-mix(in srgb, var(--accent) 40%, transparent);
}
/* 图层组（batch 2 / v278）：组行底色微异 + 文件夹折叠图标（去三角）；组内层不缩进、靠左竖条标归属 */
.layer-group-row {
  background: color-mix(in srgb, var(--ink) 5%, transparent);
}
.layer-group-count { opacity: 0.55; font-weight: 400; font-size: 12px; }
.layer-folder {
  width: 22px; height: 22px;
  display: inline-flex; align-items: center; justify-content: center;
  background: transparent; border: none; cursor: pointer;
  color: var(--ink); flex: 0 0 auto; padding: 0;
}
/* 组内层（depth>0）：左侧一条竖色条标「属于上面那个组」，不靠缩进。marginLeft 只给 rail 让位。 */
.layer-nested {
  border-left: 2px solid color-mix(in srgb, var(--accent) 45%, transparent);
  border-top-left-radius: 0;
  border-bottom-left-radius: 0;
}
/* 「移入图层组」dropdown：一行 label + select，不像 N 个菜单项那样挤占空间 */
.layer-move-into { display: flex; align-items: center; gap: 8px; cursor: default; }
.layer-move-into .menu-item-label { flex: 0 0 auto; }
.layer-move-select { flex: 1 1 auto; min-width: 0; max-width: 110px; }
/* 眼睛：按钮盒子必须比图标大，否则图标被盒子卡住。
   v123 把 icon 从 16 调到 22 却没动这里的 20px，于是那次放大一直没生效（v430 修）。
   尺寸以 .layer-vis svg 为准，别再只改 layers-panel.ts 里的 size。 */
.layer-vis {
  width: 24px;
  height: 24px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: transparent;
  border: none;
  cursor: pointer;
  color: var(--ink);
  flex: 0 0 auto;
}
.layer-vis svg { width: 20px; height: 20px; display: block; }
.layer-vis.hidden-icon { opacity: 0.3; }
.layer-name {
  flex: 1;
  color: var(--ink);
  font-size: 12px;   /* v0.5.21 user：小一号 */
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.layer-tools-btn {
  width: 24px; height: 22px;
  background: transparent;
  border: 1px solid transparent;
  border-radius: 4px;
  color: var(--ink-soft);
  font-size: 16px;
  font-weight: bold;
  letter-spacing: 1px;
  cursor: pointer;
  flex: 0 0 auto;
  display: flex; align-items: center; justify-content: center;
  padding: 0;
}
.layer-tools-btn:hover { background: color-mix(in srgb, var(--ink) 8%, transparent); color: var(--ink); }

/* per-row "⋯" 工具菜单：item 内容少，让宽度自适应内容；min 用 auto 取消 .menu-panel 的 200px
   v124：覆盖 .menu-panel 的 right: 12px / top: 56px（不然 JS 设 left 也会被 right 拉宽到全屏） */
.layer-tools-popup { padding: 4px; min-width: auto; right: auto; top: auto; }
.layer-tools-popup .menu-item { padding: 5px 12px; }
/* v0.5.22 user：图层面板的菜单字号与行(12px)对齐、条目边距同步收紧 */
.layer-tools-popup .menu-item, .layer-add-popup .menu-item { font-size: 12px; padding-top: 6px; padding-bottom: 6px; }
.layer-add-popup .menu-item { padding-left: 10px; padding-right: 10px; }
/* v267 ⋯ 菜单里的层属性 toggle：勾选标记 + 标签 */
.layer-menu-toggle { display: flex; align-items: center; gap: 8px; }
/* toggle 行 = [勾选框] [前缀图标] [文字]。前缀图标是 button 的直接子 svg，
   跟 .layer-menu-check 里那个勾选框 svg 分开定尺寸。 */
.layer-menu-toggle > svg { width: 16px; height: 16px; flex: none; }
/* 开/关状态字顶到右边，跟主菜单的 menuitemcheckbox 排版一致 */
.layer-menu-toggle .menu-item-state { margin-left: auto; }

/* 通用 in-app sheet input */
.generic-sheet-input {
  width: 100%;
  padding: 10px 12px;
  font: inherit;
  background: var(--bg-soft);
  border: 1px solid var(--line);
  border-radius: 6px;
  color: var(--ink);
  box-sizing: border-box;
}

/* 内联重命名输入框。**必须与 .layer-name 等高**（2026-08-28）：行高由 .layer-vis 的 24px 撑着
   （24 + row padding 3×2 + border 1×2 = 32px）。原先 `font: inherit` + padding + border 把 input
   撑到 25.6px → 每次进出改名整行 32↔33.6 跳动、下方所有行跟着位移（实测 headless Chromium）。
   所以钉死 height:24 + box-sizing:border-box + 与名字同字号。 */
.layer-name-input {
  flex: 1;
  font: inherit;
  font-size: 12px;      /* 同 .layer-name，进出改名字形不跳 */
  height: 24px;
  box-sizing: border-box;
  background: var(--bg-soft);
  color: var(--ink);
  border: 1px solid var(--accent);
  border-radius: 4px;
  padding: 0 6px;
  min-width: 0;
}
.layer-mode-badge {
  width: 28px;
  height: 22px;
  border: 1px solid var(--line);
  border-radius: 4px;
  background: transparent;
  color: var(--ink-soft);
  font-size: 11px;
  font-weight: 600;
  cursor: pointer;
  flex: 0 0 auto;
  display: flex; align-items: center; justify-content: center;
}
.layer-mode-badge:hover { background: color-mix(in srgb, var(--ink) 8%, transparent); }
.layer-mode-badge.active { color: var(--accent); border-color: var(--accent); }

/* 2026-09-11 图层调整弹层（user「layer 的调整下拉抽屉，换 layer 的时候就自动关掉……更喜欢 context 菜单的，和菜单一样会自动关」）：
   点 badge 弹出、挂 body 走 ui/popup-menu 收养（外点关 / Escape / 栈）、换活动层自动关；行内抽屉 .layer-row-expand 退役。 */
.layer-adjust-popup { min-width: auto; width: 232px; padding: 8px 10px; display: flex; flex-direction: column; gap: 6px; }
.layer-slider-row {
  display: grid;
  grid-template-columns: 36px 1fr 30px;
  align-items: center;
  gap: 6px;
  font-size: 12px;
  color: var(--ink);
}
.layer-slider-row > span:first-child { color: var(--ink-soft); }
/* 混合模式下拉：定宽缩写档（.select-field--fixed），皮同 lasso-tool-select */
.layer-mode-select { justify-self: start; font: inherit; font-size: 12px; padding: 3px 12px 3px 6px; border-radius: 4px; border: 1px solid color-mix(in srgb, var(--ink) 20%, transparent); background: transparent; color: var(--ink); }
.layer-slider-val { text-align: right; font-variant-numeric: tabular-nums; }
/* Clipping mask 视觉：剪裁层缩进一点 + 加 chip。基底层无样式。 */
.layer-row.clipping { padding-left: 18px; }
.layer-clip-chip {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 18px;
  height: 18px;
  font-size: 12px;
  color: var(--ink-soft);
  margin-left: 4px;
  user-select: none;
}
.layer-clip-hint { color: var(--ink-soft); font-size: 11px; }
.layer-lock-chip {
  display: inline-flex; align-items: center; justify-content: center;
  width: 18px; height: 18px;
  color: var(--accent);
  margin-left: 4px;
  user-select: none;
}
.layer-ref-chip {
  display: inline-flex; align-items: center; justify-content: center;
  width: 18px; height: 18px;
  color: #fff;
  background: var(--accent);
  border-radius: 4px;
  margin-left: 4px;
  user-select: none;
}
/* v0.5.7：文字「参/R」→ SVG（#reference-layer），语言中性 */
.layer-ref-chip svg { width: 13px; height: 13px; }
/* v0.5.8：透明度滑条标签「透」→ #opacity 图标（语言中性；文字留 title 提示） */
.layer-slider-icon { display: inline-flex; align-items: center; color: var(--ink-soft); }
.layer-slider-icon svg { width: 15px; height: 15px; }
.layer-clip-toggle {
  font: inherit;
  background: var(--bg-soft);
  color: var(--ink);
  border: 1px solid var(--line);
  border-radius: 4px;
  padding: 2px 8px;
  cursor: pointer;
}
.layer-clip-toggle[aria-pressed="true"] {
  background: color-mix(in srgb, var(--accent) 18%, transparent);
  border-color: var(--accent);
  color: var(--accent);
}
.layers-foot {
  display: flex;
  gap: 3px;
  padding: 4px;
  border-top: 1px solid var(--line);
}
.layers-foot-btn {
  flex: 1;
  padding: 3px;   /* v0.5.22 user：跟紧凑后的图层行高对齐 */
  background: transparent;
  border: 1px solid var(--line);
  border-radius: 6px;
  color: var(--ink);
  cursor: pointer;
  display: inline-flex; align-items: center; justify-content: center;
}
.layers-foot-btn svg { width: 16px; height: 16px; display: block; }
.layers-foot-btn:hover { background: color-mix(in srgb, var(--ink) 6%, transparent); }
.layers-foot-btn:disabled { opacity: 0.35; cursor: not-allowed; }
/* v267 "+" 弹出菜单：浮在底栏上方、左对齐（layers-panel 是 position:fixed → 作绝对定位容器） */
.layer-add-popup {
  position: absolute;
  bottom: 48px; left: 6px;
  min-width: auto; right: auto; top: auto;
  padding: 4px;
}
.layer-add-popup .menu-item { padding: 6px 14px; }

/* 图库 / 云端：全屏 grid */
.gallery-full,
.cloud-full {
  position: fixed; inset: 0; z-index: var(--z-overlay);
  background: var(--bg);
  display: flex; flex-direction: column;
  padding-top: env(safe-area-inset-top, 0);
  padding-bottom: env(safe-area-inset-bottom, 0);
}
/* z-index 层级表已收敛到文件顶部 :root 的 --z-* band 变量（v232 surfaces 深模块）。
   图库内的 popup（加号 / 云端账号 / 图库菜单）都是 .menu-panel → menu band，天然 > overlay。 */

/* v50 重做：左标题 + 右对齐 icon 组。无返回键，点 active tile 关闭。 */
.gallery-header {
  display: flex; align-items: center;
  padding: 12px 16px;
  border-bottom: 1px solid var(--line);
}
.gallery-title { font-size: 20px; font-weight: 600; color: var(--ink); flex: 1; display: flex; align-items: baseline; gap: 8px; min-width: 0; }
/* 图库名：大标题旁小字下对齐（user 2026-08-28；替代 ☰ 里的「当前图库」信息行） */
.gallery-title-sub { font-size: 12px; font-weight: 400; color: var(--ink-soft); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; }
/* 「回到图库」行尾的图库名简写（截断） */
.gallery-name-clip { max-width: 110px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.gallery-actions { display: flex; align-items: center; gap: 6px; }
.gallery-icon-btn {
  width: 36px; height: 36px;
  background: transparent;
  border: 1px solid transparent;
  border-radius: 8px;
  color: var(--ink); cursor: pointer;
  display: inline-flex; align-items: center; justify-content: center;
  padding: 0;
}
.gallery-icon-btn svg { width: 22px; height: 22px; display: block; }
.gallery-icon-btn:hover { background: color-mix(in srgb, var(--ink) 8%, transparent); }
.gallery-icon-btn[aria-pressed="true"] { background: color-mix(in srgb, var(--accent) 14%, transparent); color: var(--accent); }
.gallery-icon-btn[data-cloud-state="signedin"] { color: var(--info); }
.gallery-icon-btn[data-cloud-state="unconfigured"] { color: var(--ink-soft); opacity: 0.5; }

/*
 * #galleryMount = Vue 挂载点：内含 .gallery-breadcrumb(自然高) + .gallery-grid(flex:1 滚动) + .gallery-empty。
 * 它夹在 header/trash-bar(顶) 与 foot(底) 之间，必须自己 flex:1 撑满剩余高度并 min-height:0，
 * 否则它按内容撑高、.gallery-grid 的 flex:1/overflow-y 失效，图多了就溢出裁切、滚不动。
 */
#galleryMount {
  flex: 1; min-height: 0;
  display: flex; flex-direction: column;
  /* **滚动视口在这一层**（不在 .gallery-grid）：网格本身做内容高、不收缩，行永不被压扁
   *   → 内容超高就在本层溢出滚动。把「滚动器」和「网格内容」分离，是 aspect-ratio 卡片能正常滚的关键
   *   （aspect-ratio 元素在会收缩的受限上下文里会**丢比例自我压扁以避免溢出**，故网格不能既是网格又是
   *   会收缩的滚动器——v284-289 的压扁根因）。 */
  overflow-y: auto;
}

.gallery-foot {
  display: flex; align-items: center; justify-content: space-between;
  padding: 8px 16px;
  border-top: 1px solid var(--line);
  font-size: 12px; color: var(--ink-soft);
  background: var(--bg-soft);
}
.gallery-foot-usage { font-variant-numeric: tabular-nums; }
.gallery-foot-version { opacity: 0.55; font-variant-numeric: tabular-nums; letter-spacing: 0.02em; }
.gallery-foot-usage.usage-warn { color: #d97706; font-weight: 600; }
.gallery-foot-usage.usage-critical { color: #dc2626; font-weight: 700; }
/* 文档版本警告：身体一圈细红边 + 顶栏染色，提示用户当前 doc 来自更新版本 */
body[data-doc-newer="1"] .top-bar { border-color: #dc2626; box-shadow: 0 0 0 2px rgba(220, 38, 38, .25), var(--shadow); }
body[data-doc-newer="1"] #statusLabel { color: #dc2626; font-weight: 600; }

/* Brush rack sheet（v83，v102 改 CSS grid 布局）—— 底部弹出
   v100/101 用 flex column + min-height: 0 hack 在 iPad PWA 上和 max-height 打架
   改 CSS grid auto/auto/1fr 后 grid 区天然 1fr 不受 head 增删按钮影响 */
.brush-rack-sheet {
  position: fixed;
  left: 50%;
  bottom: max(env(safe-area-inset-bottom, 0px), 12px);
  transform: translateX(-50%);
  width: min(720px, calc(100% - 24px));
  /* 关键：只 max-height 不 height — sheet 按内容自适应高度，少笔时不撑满 */
  max-height: 70dvh;
  background: var(--bg);
  border: 1px solid var(--line);
  border-radius: 14px;
  box-shadow: var(--shadow);
  z-index: var(--z-sheet);
  display: grid;
  grid-template-rows: auto auto 1fr;
  overflow: hidden;
}
.brush-rack-head {
  display: flex; align-items: center;
  /* v124 (user：「小屏 brush rack 空间不够」) 10×12 → 6×10 */
  padding: 6px 10px; gap: 6px;
  border-bottom: 1px solid var(--line);
  flex-wrap: wrap;
}
.brush-rack-head > span { font-weight: 600; flex: 1 1 100px; min-width: 80px; }
/* v100r2：回退 text 按钮，允许 head 内换行（窄屏 6 个按钮换 2 行） */
.brush-rack-actions {
  display: flex; gap: 4px; align-items: center;
  flex-wrap: wrap;
  justify-content: flex-end;
}
.brush-rack-action-dev {
  opacity: 0.55;
  font-size: 11px !important;
}
.brush-rack-action {
  font: inherit; font-size: 12px;
  padding: 4px 10px;
  background: var(--bg-soft); color: var(--ink);
  border: 1px solid var(--line); border-radius: 6px;
  cursor: pointer;
}
.brush-rack-action:hover { filter: brightness(0.95); }
/* v134 icon-only variant */
.brush-rack-action-icon {
  padding: 4px;
  display: inline-flex; align-items: center; justify-content: center;
  width: 30px; height: 28px;
}
.brush-rack-action-icon svg { width: 18px; height: 18px; display: block; }
.brush-rack-close {
  font: inherit; font-size: 18px;
  width: 28px; height: 28px;
  background: transparent; color: var(--ink-soft);
  border: none; border-radius: 6px; cursor: pointer;
  margin-left: 4px;
}
.brush-rack-close:hover { background: var(--bg-soft); color: var(--ink); }
.brush-rack-folders {
  display: flex; gap: 4px;
  padding: 8px 12px 4px;
  overflow-x: auto;
  scrollbar-width: thin;
  /* grid auto 行天然不会被挤；这里不再需要 flex-shrink */
}
.brush-rack-folder {
  font: inherit; font-size: 12px;
  padding: 4px 12px;
  background: transparent; color: var(--ink-soft);
  border: 1px solid var(--line); border-radius: 999px;
  cursor: pointer; white-space: nowrap;
}
.brush-rack-folder[aria-pressed="true"] {
  background: var(--ink); color: var(--bg);
  border-color: var(--ink);
}
.brush-rack-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(96px, 1fr));
  align-content: start;        /* tiles 顶对齐，不在 1fr 里居中 */
  gap: 8px;
  padding: 8px 12px 14px;
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  min-height: 0;               /* grid 1fr 里也需要这个保 scroll */
  touch-action: pan-y;
}
.brush-rack-tile {
  display: flex; flex-direction: column;
  align-items: center;
  gap: 4px;
  padding: 10px 6px;
  background: var(--bg-soft);
  border: 1px solid var(--line); border-radius: 10px;
  cursor: pointer;
  font: inherit;
  color: var(--ink);
  transition: transform 0.06s ease;
}
.brush-rack-tile:hover { background: color-mix(in srgb, var(--ink) 4%, var(--bg-soft)); }
.brush-rack-tile:active { transform: scale(0.98); }
.brush-rack-tile[aria-pressed="true"] {
  border-color: var(--accent);
  background: color-mix(in srgb, var(--accent) 8%, var(--bg-soft));
}
.brush-rack-tile-preview {
  width: 56px; height: 56px;
  border-radius: 50%;
  background: var(--ink);
  flex-shrink: 0;
}
.brush-rack-tile-name { font-size: 11px; text-align: center; line-height: 1.2; }
/* gear icon 浮在 tile 右上角，user 不喜欢长按入设置 */
.brush-rack-tile { position: relative; }
.brush-rack-tile-edit {
  position: absolute;
  top: 2px; right: 2px;
  width: 22px; height: 22px;
  /* v124b ⋯ 比 svg gear 视觉更突出，字号大一点 */
  font-size: 18px;
  line-height: 1;
  background: transparent;
  border: none;
  color: var(--ink-soft);
  cursor: pointer;
  border-radius: 4px;
  display: flex; align-items: center; justify-content: center;
}
.brush-rack-tile-edit:hover { background: color-mix(in srgb, var(--ink) 8%, transparent); color: var(--ink); }

/* Brush settings 全屏 view（v83，v102 改 CSS grid）
   v99/100/101 用 flex column + min-height: 0 在 iPad 上常有"旁边触摸不滚"问题
   改 grid auto/1fr + pan-y 让 body 整块（含两侧 padding）都吃 vertical pan */
.brush-settings-view {
  position: fixed;
  inset: 0;
  height: 100dvh;
  width: 100vw;
  background: var(--bg);
  z-index: calc(var(--z-sheet) + 10);   /* > 笔架 sheet */
  display: grid;
  grid-template-rows: auto 1fr;
  overflow: hidden;
  touch-action: pan-y;        /* 全 view 允许竖向 pan，body 触摸侧边也能滚 */
}
.brush-settings-head {
  display: flex; align-items: center;
  padding: 12px 16px; gap: 12px;
  border-bottom: 1px solid var(--line);
  background: var(--bg-soft);
}
.brush-settings-head > .brush-settings-title { flex: 1; text-align: center; font-weight: 600; }
.brush-settings-back, .brush-settings-save {
  font: inherit; font-size: 14px;
  padding: 6px 14px;
  background: transparent; color: var(--ink);
  border: 1px solid var(--line); border-radius: 6px;
  cursor: pointer;
}
.brush-settings-save {
  background: var(--accent); color: #fff;
  border-color: var(--accent); font-weight: 600;
}
.brush-settings-body {
  /* v102 grid layout 改了：body 在 grid 1fr cell，宽度天然 100% */
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  overscroll-behavior: contain;
  touch-action: pan-y;
  /* v104：用 dynamic padding 居中代替 max-width，body 真正吃满宽度，两侧空白也算 body
     → touch-action pan-y 真正生效，user 在左右空白也能拖滚动（之前 max-width 把
     两侧排除出 body，空白触摸落在 view 上不滚） */
  padding: 16px max(20px, calc(50% - 300px));
  padding-bottom: max(env(safe-area-inset-bottom, 0px), 32px);
  box-sizing: border-box;
  scrollbar-width: thin;
}
.brush-settings-section {
  margin-bottom: 22px;
}
.brush-settings-section-title {
  font-size: 12px; font-weight: 600;
  color: var(--ink-soft);
  text-transform: uppercase;
  letter-spacing: 0.4px;
  padding-bottom: 6px;
  border-bottom: 1px solid var(--line);
  margin-bottom: 10px;
}
.brush-settings-row {
  display: grid;
  grid-template-columns: 80px 1fr 50px;
  align-items: center;
  gap: 10px;
  font-size: 13px;
  padding: 6px 0;
}
.brush-settings-row > label { color: var(--ink-soft); }
.brush-settings-row > .brush-settings-val { text-align: right; font-variant-numeric: tabular-nums; }
.brush-settings-row > input[type="range"] { width: 100%; }
.brush-settings-row > input[type="text"], .brush-settings-row > input[type="number"], .brush-settings-row > select {
  font: inherit;
  padding: 4px 8px;
  background: var(--bg-soft); color: var(--ink);
  border: 1px solid var(--line); border-radius: 4px;
}
.brush-settings-row.brush-settings-row-full {
  grid-template-columns: 80px 1fr;
}

/* v110 重采样对话框 */
/* （.resample-backdrop 2026-09-02 C3 退役：唯一 backdrop 由 ui/sheet 建，z 随最上层 sheet 的 band） */
.resample-sheet {
  position: fixed; z-index: calc(var(--z-modal) - 1);
  top: 50%; left: 50%; transform: translate(-50%, -50%);
  width: min(360px, calc(100% - 32px));
  background: var(--bg);
  border: 1px solid var(--line); border-radius: 12px;
  box-shadow: var(--shadow);
  display: flex; flex-direction: column;
  overflow: hidden;
}
.resample-sheet:not([data-open]) { display: none; }
.resample-head {
  padding: 12px 16px; font-weight: 600;
  border-bottom: 1px solid var(--line);
  background: var(--bg-soft);
}
.resample-body { padding: 14px 16px; display: flex; flex-direction: column; gap: 10px; }
.resample-row { display: flex; align-items: center; gap: 10px; font-size: 13px; }
.resample-row > label { min-width: 60px; color: var(--ink-soft); }
.resample-row > input[type="number"], .resample-row > select {
  flex: 1;
  font: inherit; padding: 4px 8px;
  background: var(--bg-soft); color: var(--ink);
  border: 1px solid var(--line); border-radius: 4px;
}
.resample-row-link > label { display: flex; align-items: center; gap: 6px; min-width: 0; }
.resample-foot {
  display: flex; gap: 8px; justify-content: flex-end;
  padding: 12px 16px;
  border-top: 1px solid var(--line);
}
.resample-foot > button {
  font: inherit; font-size: 13px;
  padding: 6px 14px;
  background: var(--bg-soft); color: var(--ink);
  border: 1px solid var(--line); border-radius: 6px;
  cursor: pointer;
}
.resample-foot > .primary {
  background: var(--accent); color: #fff;
  border-color: var(--accent); font-weight: 600;
}

/* v110 颜色调整面板 (float)；adjust-panel + foot
   宽度 380px（2026-08-19 user QoL）：滑条列是 1fr，面板加宽 = 全部 adjust 滑条
   track 变长 → 拖动精度高。positionPopup 按 offsetWidth 动态 clamp，窄屏不溢出。
   选择器带 .float-panel 是特异度需要：通用 .float-panel { width:264px } 在本规则之后，
   单靠 .adjust-panel 会被盖掉（v0.9.7 就这么哑火的——面板从来不是 280 而是 264）。 */
.float-panel.adjust-panel {
  position: fixed;
  z-index: var(--z-window);
  width: min(380px, calc(100vw - 32px));
  background: var(--bg);
  border: 1px solid var(--line);
  border-radius: 12px;
  box-shadow: var(--shadow);
  display: flex; flex-direction: column;
}
/* 2026-09-06 整窗 grip：只有声明 onBodyResize 的滤镜（曲线）露；其余滤镜内容定高，拖大无意义 */
.adjust-panel .float-panel-resize { display: none; }
/* 2026-09-06 图库卡住态三钮（重试 / 诊断日志 / 重新载入） */
.gallery-stalled-actions { display: flex; gap: 8px; flex-wrap: wrap; justify-content: center; margin-top: 8px; }
.adjust-panel.resizable .float-panel-resize { display: block; }
/* 排版紧凑（2026-08-19 user）：标签列 6.4em（=76px@12px；em 随字号缩放，user 拍板）。
   宽度地板 = コントラスト / ボケ ⟷ 鮮鋭 / 模糊 ⟷ 锐化 三条 72px（playwright 实测），
   其余标签已按语言缩写（cb 三轴 en/ja=CMY/RGB 单字母，v0.9.10）；长说明走 section title 整行。
   行字号 13→12 对齐 v0.5.23「浮窗字号与图层面板一致」；gap 8→6——省下的全喂给 1fr 的 track。 */
.adjust-panel .brush-slider-row {
  grid-template-columns: 6.4em 1fr 2.5em;
  gap: 6px;
  font-size: 12px;
}
.adjust-panel-foot {
  display: flex; gap: 8px; justify-content: flex-end;
  margin-top: 4px;
  padding-top: 6px;
  border-top: 1px solid var(--line);
}
.adjust-panel-foot > button {
  font: inherit; font-size: 12px;
  padding: 4px 12px;
  background: var(--bg-soft); color: var(--ink);
  border: 1px solid var(--line); border-radius: 6px;
  cursor: pointer;
}
.adjust-panel-foot > .primary {
  background: var(--accent); color: #fff;
  border-color: var(--accent); font-weight: 600;
}
/* v131 filter 面板：section title / curves canvas / curves tabs */
.adjust-section-title {
  font-size: 11px; color: var(--ink-muted, #888);
  margin: 6px 0 2px;
  padding-bottom: 2px;
  border-bottom: 1px solid var(--line);
  letter-spacing: 0.5px;
}
.curves-tabs {
  display: flex; gap: 4px; margin-bottom: 8px;
}
.curves-tab {
  flex: 1;
  font: inherit; font-size: 12px;
  padding: 4px 0;
  background: var(--bg-soft); color: var(--ink);
  border: 1px solid var(--line);
  border-bottom-width: 3px;
  border-radius: 4px;
  cursor: pointer;
}
.curves-tab[aria-pressed="true"] {
  background: var(--accent); color: #fff;
}
/* 曲线编辑器（ui/curve-editor.ts，2026-09-05）：SVG 曲线 + HTML 键/把手 + 右上角 gizmo 钮（参考窗语言）。
   颜色全走主题变量；--curve-accent 由宿主按通道注入。edited by Claude Fable 5.1 */
.curve-editor { display: flex; flex-direction: column; gap: 6px; outline: none; user-select: none; -webkit-user-select: none; }
.curve-editor:focus-visible .ce-plot { box-shadow: 0 0 0 2px color-mix(in srgb, var(--accent) 45%, transparent); }
.ce-plot {
  position: relative; width: 200px; height: 200px;   /* 边长由 curve-editor inline 写（默认 200，宿主 setPlotSize 改）；这里只是兜底 */
  margin: 8px auto;                        /* 居中；端点键半径露出 plot 边界，留白别裁 */
  border: 1px solid var(--line); border-radius: 4px;
  background: var(--bg-soft);
  touch-action: none;
}
.ce-plot > svg { position: absolute; inset: 0; width: 100%; height: 100%; overflow: visible; pointer-events: none; display: block; }   /* 只钉直接子 svg：gizmo 钮里的图标 svg 不许中招（曾把两图标叠到一个钮上） */
.ce-grid line { stroke: var(--line); stroke-width: 1; vector-effect: non-scaling-stroke; }
.ce-identity { stroke: var(--line-strong); stroke-width: 1; stroke-dasharray: 4 4; vector-effect: non-scaling-stroke; }
.ce-curve { fill: none; stroke: var(--curve-accent, var(--accent)); stroke-width: 2; stroke-linejoin: round; vector-effect: non-scaling-stroke; }
.ce-hline { stroke: var(--ink); stroke-width: 2; vector-effect: non-scaling-stroke; }
.ce-keys { position: absolute; inset: 0; pointer-events: none; }
.ce-key {
  position: absolute; width: 12px; height: 12px; margin: -6px 0 0 -6px; border-radius: 50%;
  background: var(--curve-accent, var(--accent)); border: 2px solid var(--bg);
  box-shadow: 0 0 0 1px var(--line-strong);
  pointer-events: auto; cursor: grab; touch-action: none;
}
.ce-key::before { content: ""; position: absolute; inset: -11px; border-radius: 50%; }   /* 触屏命中面 ≥ 30px */
.ce-key.selected { width: 16px; height: 16px; margin: -8px 0 0 -8px; box-shadow: 0 0 0 2px var(--ink); }
.ce-key.locked { border-radius: 2px; }
.ce-knob {
  position: absolute; width: 16px; height: 16px; margin: -8px 0 0 -8px; border-radius: 50%;   /* user 0905「手柄太小」：12→16 */
  background: var(--bg); border: 2px solid var(--ink);
  cursor: grab; touch-action: none; z-index: 2;
}
.ce-knob::before { content: ""; position: absolute; inset: -8px; border-radius: 50%; }   /* 命中面 32px */
.ce-knob.weighted { border-radius: 3px; }   /* 加权把手钮 = 方形（Unity 同款区分），拖它同时改斜率与长度 */
/* gizmo 落左上角：右上角 (1,1) 是恒等曲线的末端键，放那儿会盖住键（截图实测）。 */
.ce-gizmos { position: absolute; top: 4px; left: 4px; z-index: 3; display: flex; gap: 4px; transition: opacity 0.35s; }
.ce-gizmo {
  width: 28px; height: 28px; padding: 0; border: none; border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  background: color-mix(in srgb, var(--bg) 72%, transparent); color: var(--ink); cursor: pointer;
}
.ce-gizmo svg { width: 16px; height: 16px; pointer-events: none; }
.ce-gizmo:hover { background: color-mix(in srgb, var(--bg) 90%, transparent); }
.ce-gizmo:disabled { opacity: 0.3; cursor: default; }
.curve-editor.idle .ce-gizmos { opacity: 0.35; }
.curve-editor.away .ce-gizmos { opacity: 0; }
.ce-row { display: flex; align-items: center; gap: 6px; font-size: 12px; color: var(--ink); min-height: 22px; }
.ce-row-readout { justify-content: flex-end; color: var(--ink-soft); font-variant-numeric: tabular-nums; min-height: 16px; }
.ce-label { color: var(--ink-soft); }
.ce-select-slot { flex: 1; display: flex; }
.ce-select-slot .select-field { flex: 1; }
.ce-btn {
  font: inherit; font-size: 12px; padding: 3px 8px;
  background: var(--bg-soft); color: var(--ink);
  border: 1px solid var(--line); border-radius: 6px; cursor: pointer;
}
.ce-btn[aria-pressed="true"] { background: var(--accent); color: #fff; border-color: var(--accent); }
.ce-btn:disabled { opacity: 0.4; cursor: default; }
.ce-row-end { justify-content: flex-end; }
.brush-settings-curve { padding: 2px 0 6px; }   /* 笔设置里的压感曲线编辑器（批 4） */
.brush-settings-curve .curve-editor { max-width: 380px; margin: 0 auto; }   /* 设置表很宽（600px），方形编辑器别撑成 600 高（截图实测） */
/* 色带编辑器（ui/ramp-editor.ts，2026-09-05）：条 + 条下小旗色标；gizmo/行控件复用 .ce-* 标准件 */
.ramp-editor { display: flex; flex-direction: column; gap: 6px; outline: none; user-select: none; -webkit-user-select: none; }
.ramp-editor:focus-visible .re-bar-wrap { box-shadow: 0 0 0 2px color-mix(in srgb, var(--accent) 45%, transparent); }
.re-bar-wrap {
  position: relative; height: 36px; margin: 6px 8px 0;   /* 两侧 8px：端点小旗（半宽 7px）不被面板边裁 */
  border: 1px solid var(--line); border-radius: 4px; overflow: hidden;
  /* alpha 棋盘底（色带带透明时可见） */
  background: repeating-conic-gradient(var(--line) 0 25%, var(--bg-soft) 0 50%) 0 0 / 12px 12px;
}
.re-bar { position: absolute; inset: 0; }
.re-stops { position: relative; height: 22px; margin: 0 8px; touch-action: none; }
.re-tools { display: flex; gap: 4px; margin-left: 8px; }
.re-tools .ce-gizmo { background: var(--bg-soft); border: 1px solid var(--line); }
.re-stop {
  position: absolute; top: 4px; width: 14px; height: 16px; margin-left: -7px;
  background: var(--stop-color, #000); border: 2px solid var(--bg); border-radius: 0 0 3px 3px;
  box-shadow: 0 0 0 1px var(--line-strong);
  cursor: grab; touch-action: none;
}
.re-stop::before {   /* 小旗尖：指向色带 */
  content: ""; position: absolute; left: -2px; top: -8px;
  border-left: 7px solid transparent; border-right: 7px solid transparent; border-bottom: 7px solid var(--stop-color, #000);
}
.re-stop::after { content: ""; position: absolute; inset: -10px -8px -8px -8px; }   /* 触屏命中面 */
.re-stop.selected { box-shadow: 0 0 0 2px var(--ink); z-index: 1; }

/* v110 自由裁切 overlay：全屏覆盖，rect+handles 在屏幕坐标 */
.crop-overlay {
  position: fixed;
  inset: 0;
  z-index: calc(var(--z-toolbar) - 1);  /* < crop-toolbar */
  touch-action: none;
  /* crop 时仍可两指缩放/平移画布 + 滚轮缩放：overlay 透传，只有 handle 捕获。
     空白/单指落到 canvas 由 EditMode canDraw gate（crop→false）拦掉，不会误起笔触。 */
  pointer-events: none;
  /* 外圈 dim：用 box-shadow 大边框模拟（rect 自己挖洞） */
}
.crop-handle { pointer-events: auto; }   /* 只有 handle 捕获指针（拖动裁切框） */
/* 裁切框实时分辨率标签（L69） */
.crop-dim {
  position: absolute; left: 50%; top: -22px; transform: translateX(-50%);
  font: 600 11px/1 ui-monospace, monospace; color: #fff;
  background: rgba(0,0,0,0.6); padding: 2px 6px; border-radius: 3px;
  white-space: nowrap; pointer-events: none;
}
.crop-rect {
  position: absolute;
  border: 2px dashed #fff;
  box-shadow: 0 0 0 9999px rgba(0, 0, 0, 0.5),
              0 0 0 1px rgba(0, 0, 0, 0.6) inset;
  box-sizing: border-box;
  /* v125 (user：「裁切时空白不应该可拖动」)：cursor 不再 move */
  cursor: default;
}
/* v125 (user：「crop 的 handler 改成黑色的直线和直角」)：
   corner = 直角 L 形（2 条粗黑边）；edge = 短粗黑横/竖线
   背景不再实心白方块 */
.crop-handle {
  position: absolute;
  background: transparent;
  border: none;
  border-radius: 0;
}
/* v126 (user：「裁剪的 Gizmos 可点击区域太窄」)：
   ::after 拉一圈透明 hit-area 让指尖好按。不影响视觉 L / 短线 */
.crop-handle::after {
  content: "";
  position: absolute;
  inset: -16px;
  pointer-events: auto;
}
.crop-handle[data-handle="nw"],
.crop-handle[data-handle="ne"],
.crop-handle[data-handle="se"],
.crop-handle[data-handle="sw"] {
  width: 20px; height: 20px;
}
.crop-handle[data-handle="nw"] { top: -3px;    left: -3px;
  border-top:   3px solid #000; border-left:  3px solid #000; cursor: nwse-resize; }
.crop-handle[data-handle="ne"] { top: -3px;    right: -3px;
  border-top:   3px solid #000; border-right: 3px solid #000; cursor: nesw-resize; }
.crop-handle[data-handle="se"] { bottom: -3px; right: -3px;
  border-bottom: 3px solid #000; border-right: 3px solid #000; cursor: nwse-resize; }
.crop-handle[data-handle="sw"] { bottom: -3px; left: -3px;
  border-bottom: 3px solid #000; border-left:  3px solid #000; cursor: nesw-resize; }
.crop-handle[data-handle="n"]  { top: -2px;    left: 50%; transform: translateX(-50%);
  width: 28px; height: 3px; background: #000; cursor: ns-resize; }
.crop-handle[data-handle="s"]  { bottom: -2px; left: 50%; transform: translateX(-50%);
  width: 28px; height: 3px; background: #000; cursor: ns-resize; }
.crop-handle[data-handle="w"]  { top: 50%; left: -2px;    transform: translateY(-50%);
  width: 3px; height: 28px; background: #000; cursor: ew-resize; }
.crop-handle[data-handle="e"]  { top: 50%; right: -2px;   transform: translateY(-50%);
  width: 3px; height: 28px; background: #000; cursor: ew-resize; }

/* v110 自由裁切 toolbar (顶栏下方居中) */
/* （.crop-toolbar 容器皮 2026-09-06 U1 退役：裁切/滤镜笔条统一走 .lasso-toolbar-stack；控件类 .crop-toolbar-btn 等保留给裁切条的输入框） */
.crop-toolbar-label { color: var(--ink-soft); }
.crop-toolbar-sep { color: var(--line); }
.crop-toolbar-btn {
  font: inherit; font-size: 12px;
  padding: 4px 10px;
  background: var(--bg-soft); color: var(--ink);
  border: 1px solid var(--line); border-radius: 6px;
  cursor: pointer;
}
.crop-toolbar-cancel { color: #dc2626; }

/* v124 吸色 pin (Google Maps 风格)：head 圆显采样色 + 下方 triangle 尖端指 pixel */
.picker-pin {
  position: fixed;
  z-index: var(--z-popout);
  pointer-events: none;
  /* v124 修 (user：「pin 尖尖头位置没扎对」)：
     ::after triangle 用 bottom:-8 凸到 pin div 之外，tip 比 pin div 底再下 8px。
     translate(-50%, -100%) 让 pin div 底贴 (sx, sy) → tip 实际在 sy+8。
     补偿：再上移 8px 让 tip 落在 (sx, sy)。
     padding-bottom 拉开 head 与 tip 的距离（加长杆），让 head 抬离手指不被挡。 */
  transform: translate(-50%, calc(-100% - 8px));
  padding-bottom: 56px;
  transition: opacity 0.15s ease-out;
}
.picker-pin-head {
  width: 36px; height: 36px; border-radius: 50%;
  background: var(--head-color, #fff);
  border: 3px solid var(--bg);
  box-shadow: 0 2px 8px rgba(0,0,0,0.4);
}
/* 连接 head 与 tip 的细杆（让加长后的悬浮 head 视觉上仍指向采样点） */
.picker-pin::before {
  content: "";
  position: absolute;
  left: 50%; top: 36px; bottom: 2px;
  transform: translateX(-50%);
  width: 2px;
  background: #000;
  filter: drop-shadow(0 0 1px rgba(255,255,255,0.6));
}
/* tip triangle 指向 pixel。v124 user：「小三角放圆下面，黑色」固定黑色不跟色 */
.picker-pin::after {
  content: "";
  position: absolute;
  left: 50%; bottom: -8px;
  transform: translateX(-50%);
  width: 0; height: 0;
  border-left: 6px solid transparent;
  border-right: 6px solid transparent;
  border-top: 10px solid #000;
  filter: drop-shadow(0 2px 2px rgba(0,0,0,0.3));
}

/* v104 size 滑块 popup
   v123: user「太大太长，位置不对，px 放下面，不用屏 px」→ 改竖排（圆上字下），缩小 frame */
.size-popup {
  position: fixed;
  /* 外观（实底）走共享规则 */
  padding: 6px 8px;
  z-index: var(--z-menu);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
  pointer-events: none;
}
.size-popup-circle-frame {
  width: 64px; height: 64px;
  display: flex; align-items: center; justify-content: center;
  overflow: hidden;
  flex-shrink: 0;
}
.size-popup-circle {
  background: var(--ink);
  border-radius: 50%;
  flex-shrink: 0;
}
.size-popup-text {
  font-variant-numeric: tabular-nums;
  font-size: 11px;
  text-align: center;
  white-space: nowrap;
}

/* Palette 调色板小窗（v87）—— 256×256 浮动 mixer */
.palette-window {
  position: fixed;
  right: max(env(safe-area-inset-right, 0px), 12px);
  top: 80px;
  width: 280px;
  background: var(--bg);
  border: 1px solid var(--line);
  border-radius: 12px;
  box-shadow: var(--shadow);
  z-index: var(--z-window);
  display: flex; flex-direction: column;
}
.palette-head {
  display: flex; align-items: center; justify-content: space-between;
  padding: 6px 10px;
  border-bottom: 1px solid var(--line);
  cursor: move;
  user-select: none;
}
.palette-title { font-size: 12px; color: var(--ink-soft); font-weight: 600; }
.palette-close {
  font: inherit; font-size: 16px;
  width: 24px; height: 24px;
  background: transparent; color: var(--ink-soft);
  border: none; border-radius: 4px; cursor: pointer;
}
.palette-body { padding: 8px; display: flex; justify-content: center; }
.palette-canvas {
  width: 256px; height: 256px;
  border: 1px solid var(--line); border-radius: 4px;
  touch-action: none;
  cursor: crosshair;
  background: #fff;
}
.palette-tools {
  display: flex; gap: 4px;
  padding: 6px 8px 8px;
  justify-content: center;
}
.palette-tools button {
  font: inherit; font-size: 12px;
  padding: 4px 12px;
  background: var(--bg-soft); color: var(--ink);
  border: 1px solid var(--line); border-radius: 6px;
  cursor: pointer;
}
.palette-tools button:hover { filter: brightness(0.95); }
.palette-tools button[aria-pressed="true"] {
  background: var(--ink); color: var(--bg); border-color: var(--ink);
}

/* Sync gate ——— 锁屏 + 决策 sheet（见 ai-docs/20260528-sync-design.md） */
.sync-gate-backdrop { z-index: var(--z-gate); background: rgba(0, 0, 0, 0.45); }
.sync-gate-sheet { z-index: calc(var(--z-gate) + 1); max-width: 320px; }
.sync-gate-spinner {
  display: flex; align-items: center; gap: 10px;
  padding: 12px 0; color: var(--ink-soft); font-size: 12px;
}
.spinner-ring {
  width: 18px; height: 18px;
  border: 2px solid color-mix(in srgb, var(--ink) 18%, transparent);
  border-top-color: var(--accent);
  border-radius: 50%;
  animation: spinner-rot 0.8s linear infinite;
}
@keyframes spinner-rot { to { transform: rotate(360deg); } }
.sync-gate-note {
  margin: 10px 0 0 0;
  font-size: 11px;
  color: var(--ink-soft);
  opacity: 0.85;
}
.sync-gate-actions {
  display: flex; flex-direction: column;
  gap: 8px; margin-top: 8px;
}
.sync-gate-actions button {
  width: 100%; padding: 10px 14px;
  font: inherit; font-size: 14px;
  background: var(--bg-soft); color: var(--ink);
  border: 1px solid var(--line); border-radius: 8px;
  cursor: pointer; text-align: left;
}
.sync-gate-actions button.primary {
  background: var(--accent); color: #fff; border-color: var(--accent);
  font-weight: 600;
}
.sync-gate-actions button:hover { filter: brightness(0.95); }
.gallery-foot-hint { color: var(--ink-soft); font-size: 11px; opacity: 0.7; }

.menu-item-info {
  padding: 8px 12px;
  font-size: 12px;
  color: var(--ink-soft);
  border-bottom: 1px solid var(--line);
  margin-bottom: 4px;
}

/* 进入图库模式 = 主画布 UI 全 disable + 隐藏，给图库清场 */
body[data-mode="gallery"] .top-bar,
body[data-mode="gallery"] .hud,
body[data-mode="gallery"] .float-panel,
body[data-mode="gallery"] wp-reference-window,
body[data-mode="gallery"] .menu-panel:not(#galleryAddPopup):not(#cloudAccountPopup):not(#galleryMenuPopup),
body[data-mode="gallery"] .adjust-popup,
body[data-mode="gallery"] .board { display: none !important; }

/* Save 按钮 4 态视觉 */
.tool[data-state="dirty"] { color: var(--accent); position: relative; }
.tool[data-state="dirty"]::after {
  content: ""; position: absolute; top: 6px; right: 6px;
  width: 6px; height: 6px; border-radius: 50%;
  background: var(--accent);
}
/* v415 删：saving / cloud-dirty / cloud-busy / saved 四个 .tool 态**没有任何生产者**——
   store cutover 后 computeSaveState 只产 dirty | synced | local-only；
   .brush-rack-action[data-state="busy"] 同理（笔架的云备份按钮早已删）。
   wp-spin 动画本身保留：blender 连接按钮还在用（见下方 .btp-connbtn[data-state="connecting"]）。 */
@keyframes wp-spin {
  from { transform: rotate(0deg); }
  to   { transform: rotate(360deg); }
}
.tool[data-state="synced"] { color: var(--quiet); }
/* unpushed（v433）：已落本地、云端那条腿没成。**必须**和 synced 的灰区分开——
   它是「你的工作还没到安全的地方」，不是「没什么可做」。琥珀 = 提醒但不报错（离线是正常天气）。
   注意这不是上面注释里被删掉的那批「在飞中」过程态的回归，它是终态。 */
.tool[data-state="unpushed"] { color: var(--warn); }
.gallery-grid {
  /* 内容高、不伸不缩（flex:none）——滚动交给 #galleryMount。这样 aspect-ratio 卡片行不会被收缩压扁。 */
  flex: none;
  padding: 16px;
  display: grid;
  /* 宽流式（消右侧空白）；高用 aspect-ratio 跟宽走成方块（大厂现行做法，见 .gallery-tile-thumb）。
   * 列：minmax(150,1fr) auto-fill —— 塞尽量多列 + 1fr 均摊不足一列的余量撑开
   *   （旧 `repeat(auto-fill,180px)` 固定宽左对齐，余量全堆右边：SE2 竖屏只 1 列、右空 ~160px）。
   * ⚠⚠ `min-height: 0` 是命门：本网格是 flex 链里的滚动视口，少了它 → 非-rigid 卡片建不起滚动区，
   *   容器把内容强行 fit-all、卡片被压扁成一条（v284-287 用 aspect/内容高全栽在这——不是 aspect 的错，
   *   是这行漏了；当年用 rigid 238px 死高才掩盖过去）。#galleryMount 早有同一行同一注释。 */
  grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
  gap: 16px;
  align-content: start;
}
/*
 * 滚动条策略：默认（含移动/触摸）走系统 overlay/auto，不常显，保移动端观感。
 * 仅 Windows 桌面（粗略地 pointer:fine = 鼠标）常显一条窄滚动条，否则桌面上看不出能滚。
 */
@media (pointer: fine) {
  #galleryMount {
    scrollbar-width: thin;
    scrollbar-gutter: stable;
  }
  #galleryMount::-webkit-scrollbar { width: 10px; }
  #galleryMount::-webkit-scrollbar-thumb {
    background: color-mix(in srgb, var(--ink) 22%, transparent);
    border-radius: 6px;
    border: 2px solid transparent;
    background-clip: padding-box;
  }
  #galleryMount::-webkit-scrollbar-thumb:hover {
    background: color-mix(in srgb, var(--ink) 36%, transparent);
    background-clip: padding-box;
  }
}
.gallery-tile {
  /* 宽由 grid 列定（流式）；高由内容定（方形缩略图 aspect-ratio + 两行字）。同一行卡片等宽→等高。
   * display:block：缩略图 img 用 width:100%+aspect-ratio 求高须在块布局里（flex item 下百分比宽
   *   定不出 aspect 高）。能内容自适应高的前提是 .gallery-grid 有 min-height:0（已加），否则会被压扁。 */
  display: block;
  background: var(--bg-soft);
  border: 1px solid var(--line);
  border-radius: 8px;
  /* v0.5.39：overflow:hidden 退役——它是给缩略图圆角服务的，却把 tile ⋯ 菜单弹层一并裁掉（user）。
     圆角改由 thumb 自己承担（只圆上两角，贴卡片弧度）。 */
  cursor: pointer;
  position: relative;
  transition: transform 0.08s ease, box-shadow 0.08s ease, opacity 0.15s ease;
}
.gallery-tile[data-busy="1"] {
  opacity: 0.55;
  cursor: progress;
}
.gallery-tile:hover { transform: translateY(-1px); box-shadow: 0 4px 12px rgba(0,0,0,0.08); }
.gallery-tile.active {
  border-color: var(--accent);
  box-shadow: 0 0 0 2px color-mix(in srgb, var(--accent) 30%, transparent);
}
.gallery-tile-thumb {
  /* 大厂现行做法：aspect-ratio 让缩略图随卡片宽变成方块（块布局里 width:100% 先定宽、aspect 求等高）。
   * 同一行卡片等宽→等高。object-fit:contain：方图整张可见、比例正确。 */
  width: 100%; aspect-ratio: 1 / 1; height: auto;
  display: block;
  object-fit: contain;
  border-radius: 7px 7px 0 0;   /* v0.5.39：卡片放开 overflow 后圆角自理（8px 外框内贴 1px 边） */
  /* 白纸：alpha 区露白底，跟画在白纸上一样 */
  background: #ffffff;
}
/* 像素画缩略图保锐：thumb 生成侧恒不放大 → natural 长边 <128 = 原作本身就这么小（像素画），
   而 tile ≥150 CSS px 必被浏览器放大 → 默认双线性糊。JS onload 按 naturalWidth/Height 挂本 class
   （见 gallery.ts thumbLoadPixelated 的阈值论证）。纯渲染属性，暗色主题无关。 */
.gallery-tile-thumb.pixelated { image-rendering: pixelated; }
.gallery-tile-thumb.placeholder {
  display: flex; align-items: center; justify-content: center;
  color: rgba(0,0,0,0.35);
  font-size: 32px;
}
/* 加密作品锁定态：点锁可解锁预览（ADR-0012） */
.gallery-tile-thumb.placeholder.locked {
  cursor: pointer;
  color: rgba(0,0,0,0.45);
  background: repeating-linear-gradient(45deg, #f4f4f4 0 12px, #ececec 12px 24px);
}
/* 加密常驻徽章（解锁后也显示，一眼看出这张是加密的） */
.gallery-tile-state-icon.enc { color: var(--enc); }
.gallery-tile-state-icon.enc svg { width: 14px; height: 14px; }
/* 顶栏加密指示：当前画作加密时显示的小锁（点它解除加密） */
.top-enc-lock { color: var(--enc); }
.top-enc-lock svg { width: 20px; height: 20px; }
/* ⋯ 菜单按钮叠在 thumb 右上：半透明白底 + 深字 + 模糊背景 → 跨日 / 夜主题都清楚 */
.gallery-tile-menu-btn {
  position: absolute; right: 5px; top: 5px;
  width: 26px; height: 26px;
  display: flex; align-items: center; justify-content: center;
  background: rgba(255, 255, 255, 0.85);
  color: #333;
  border: 1px solid rgba(0, 0, 0, 0.1);
  border-radius: 50%;
  cursor: pointer;
  font-size: 16px; line-height: 1; font-weight: bold;
  padding: 0; z-index: 2;
  backdrop-filter: blur(4px);
  -webkit-backdrop-filter: blur(4px);
  transition: background 0.1s ease;
}
.gallery-tile-menu-btn:hover { background: rgba(255, 255, 255, 1); }
.gallery-tile-menu-popup {
  position: absolute; right: 4px; top: 34px;
  /* 外观（实底）走共享规则；圆角 6→8 随统一 */
  min-width: 140px;
  z-index: 5;
  display: flex; flex-direction: column;
  overflow: hidden;
}
/* #14：卡片贴屏幕下缘时菜单向上翻（JS 量 bbox 超视口底 → 加 .up），底部行不再伸出屏外 */
.gallery-tile-menu-popup.up { top: auto; bottom: 34px; }
.gallery-tile-menu-popup button {
  padding: 8px 12px;
  text-align: left;
  background: transparent;
  border: none;
  cursor: pointer;
  font-size: 13px;
  color: var(--ink);
  white-space: nowrap;
  /* v419 前缀图标：图标 + 文字并排 */
  display: flex;
  align-items: center;
  gap: 9px;
}
.gallery-tile-menu-popup button svg { width: 16px; height: 16px; flex: none; }
.gallery-tile-menu-popup button:hover { background: color-mix(in srgb, var(--ink) 8%, transparent); }
.gallery-tile-menu-popup button.danger { color: #c0392b; }
.gallery-tile-menu-popup button.danger:hover { background: color-mix(in srgb, #c0392b 12%, transparent); }
/* cloud-gone ghost 菜单的解释行（非按钮）：窄、灰、可折行 */
.gallery-menu-note {
  padding: 8px 12px;
  max-width: 200px;
  font-size: 12px;
  line-height: 1.4;
  color: var(--ink-soft);
  white-space: normal;
  border-bottom: 1px solid var(--line);
}
/* 第 1 行名字（ellipsis tooltip 兜底）+ 第 2 行 meta 备注（淡色） */
.gallery-tile-name-row {
  padding: 8px 10px 10px;
  position: relative;
  min-width: 0;
}
.gallery-tile-name {
  font-size: 13px; line-height: 1.32;
  color: var(--ink);
  text-align: left;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  min-width: 0;
}
.gallery-tile-meta {
  font-size: 11px; line-height: 1.3;
  color: var(--ink-soft);
  margin-top: 2px;
  display: flex; align-items: center; gap: 4px;
  white-space: nowrap; overflow: hidden;
}
.gallery-tile-meta > span { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.gallery-tile-state-icon {
  flex-shrink: 0;
  display: inline-flex; align-items: center;
  color: var(--ink-soft);
}
.gallery-tile-state-icon svg { width: 12px; height: 12px; display: block; }
/* badge 去压扁两态的染色（2026-08-25，甲方回执「conflict 可考虑黄、download 建议蓝」+ 现状 ground）：
   conflict = var(--warn)（topbar unpushed 同 token = 同一「云侧待你处理」语义族；与 --enc 锁琥珀刻意分 token）；
   newerOnCloud = var(--accent)（亮=棕/暗=浅棕——注意本仓 accent 不是蓝，旧 #4c8bf5 fallback 从不生效已全删）。
   其余 badge 保持 --ink-soft 灰。 */
.gallery-tile-state-icon.b-conflictBoth { color: var(--warn); }
.gallery-tile-state-icon.b-newerOnCloud { color: var(--accent); }
/* "编辑中" 角标叠在第 1 行（name）右侧，可压住右端文字（用户：可重叠） */
.gallery-tile.active .gallery-tile-name-row::after {
  content: "编辑中";
  position: absolute; right: 6px; top: 8px;
  pointer-events: none;
  font-size: 10px;
  color: var(--accent);
  background: color-mix(in srgb, var(--accent) 14%, transparent);
  border-radius: 3px;
  padding: 1px 6px;
  margin-left: 6px;
  vertical-align: middle;
}
.gallery-empty {
  flex: 1;
  display: flex; align-items: center; justify-content: center;
  color: var(--ink-soft);
  font-size: 14px;
  padding: 32px;
  text-align: center;
}
.gallery-loading {
  grid-column: 1 / -1;
  text-align: center;
  padding: 48px;
  color: var(--ink-soft);
  font-size: 14px;
}

/* 面包屑 —— 现在它和网格同在 #galleryMount 滚动层内，sticky 钉顶不随网格滚走 */
.gallery-breadcrumb {
  position: sticky; top: 0; z-index: 1;
  background: var(--bg);
  display: flex; flex-wrap: wrap; align-items: center;
  gap: 4px;
  padding: 8px 16px;
  border-bottom: 1px solid var(--line);
  font-size: 13px;
  color: var(--ink-soft);
}
.gallery-breadcrumb button {
  background: transparent;
  border: none;
  color: var(--ink-soft);
  padding: 4px 8px;
  cursor: pointer;
  border-radius: 4px;
  font-size: 13px;
}
.gallery-breadcrumb button:hover:not(.current) {
  background: color-mix(in srgb, var(--ink) 8%, transparent);
  color: var(--ink);
}
.gallery-breadcrumb button.current {
  color: var(--ink);
  font-weight: 500;
  cursor: default;
}
.gallery-breadcrumb .sep {
  color: var(--ink-soft);
  opacity: 0.6;
}

/* Folder tile（gallery 内显示为文件夹的特殊 tile） */
.gallery-tile.folder .gallery-tile-thumb {
  display: flex; align-items: center; justify-content: center;
  /* v232：跟日夜配色走（之前混 white，夜间模式文件夹刺眼） */
  background: color-mix(in srgb, var(--accent) 8%, var(--bg));
  color: var(--accent);
}
.gallery-tile.folder .gallery-tile-thumb svg {
  width: 80px; height: 80px;
}
.gallery-tile.folder .gallery-tile-name {
  font-weight: 500;
}
/* 图片文件次级 tile（v0.9.34 拍板：可见但视觉降级，与画作一眼可分；点击=孪生开画）
   v0.9.35（QA 1）：降级只罩缩略图+名字行——罩整 tile 会连坐 ⋯ 菜单弹层（iPad 无 hover 恢复不了） */
.gallery-tile.image-file .gallery-tile-thumb,
.gallery-tile.image-file .gallery-tile-name-row { opacity: 0.72; }
.gallery-tile.image-file:hover .gallery-tile-thumb,
.gallery-tile.image-file:hover .gallery-tile-name-row { opacity: 1; }
.gallery-tile.image-file .gallery-tile-thumb {
  /* 素材图整图看全（contain）；画作 thumb 维持既有裁切规则不动 */
  object-fit: contain;
  background: color-mix(in srgb, var(--ink, #e8eaed) 4%, var(--bg));
}
.gallery-tile.image-file .gallery-tile-name { font-weight: 400; color: var(--ink-soft, #9aa0a6); }
/* 回收站 bar：trash 视图独立 header，含返回 + 标题 + 清空按钮 */
.gallery-trash-bar {
  display: flex; align-items: center;
  gap: 12px;
  padding: 8px 16px;
  border-bottom: 1px solid var(--line);
  background: color-mix(in srgb, #c0392b 4%, var(--bg-soft));
}
.gallery-back-btn {
  background: transparent; border: 1px solid var(--line);
  color: var(--ink); padding: 4px 10px;
  border-radius: 4px; cursor: pointer; font-size: 13px;
}
.gallery-back-btn:hover { background: color-mix(in srgb, var(--ink) 6%, transparent); }
.gallery-trash-title {
  flex: 1; font-size: 14px; font-weight: 500; color: #c0392b;
}
/* 回收站 ⋯ menu：parent relative + popup absolute 右上 → 简单可靠 */
.gallery-trash-menu-wrap { position: relative; }
.gallery-trash-menu-btn {
  background: transparent; border: none;
  color: var(--ink-soft);
  font-size: 18px; font-weight: bold; line-height: 1;
  padding: 4px 10px; cursor: pointer; border-radius: 4px;
}
.gallery-trash-menu-btn:hover { background: color-mix(in srgb, var(--ink) 8%, transparent); }
.gallery-trash-menu-popup {
  position: absolute; right: 0; top: calc(100% + 4px);
  background: color-mix(in srgb, var(--bg) 96%, transparent);
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
  border: 1px solid var(--line);
  border-radius: 6px;
  box-shadow: var(--shadow);
  min-width: 140px;
  z-index: var(--z-menu);
  display: flex; flex-direction: column;
  overflow: hidden;
}
.gallery-trash-menu-item {
  padding: 10px 14px;
  text-align: left;
  background: transparent;
  border: none;
  cursor: pointer;
  font-size: 13px;
  color: var(--ink);
  white-space: nowrap;
}
.gallery-trash-menu-item:hover { background: color-mix(in srgb, var(--ink) 8%, transparent); }
.gallery-trash-menu-item.danger { color: #c0392b; }
.gallery-trash-menu-item.danger:hover { background: color-mix(in srgb, #c0392b 12%, transparent); }
/* disabled 占位项（备份箱预告）：跟 .menu-item:disabled 同款淡化 */
.gallery-trash-menu-item:disabled { opacity: 0.35; cursor: not-allowed; }
.gallery-trash-menu-item:disabled:hover { background: transparent; }

/* 全屏 block 进度（pullCloudPath 等长操作期间防误点） */
.fullscreen-busy {
  position: fixed; inset: 0;
  background: rgba(0, 0, 0, 0.6);
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 16px;
  z-index: var(--z-busy);
  color: white;
}
.fullscreen-busy-spinner {
  width: 48px; height: 48px;
  border: 4px solid rgba(255,255,255,0.2);
  border-top-color: white;
  border-radius: 50%;
  animation: fullscreen-busy-spin 0.9s linear infinite;
}
@keyframes fullscreen-busy-spin {
  to { transform: rotate(360deg); }
}
.fullscreen-busy-msg {
  font-size: 14px;
  text-align: center;
}

/* 浮动可拖面板（color picker / 未来的 layers / brush params 等都走这套） */
.float-panel {
  position: fixed;
  top: 60px;
  left: 16px;
  display: flex;
  flex-direction: column;
  width: 264px;
  background: color-mix(in srgb, var(--bg) 92%, transparent);
  backdrop-filter: blur(16px) saturate(180%);
  -webkit-backdrop-filter: blur(16px) saturate(180%);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  z-index: var(--z-window);
}
.float-panel-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 4px 8px;   /* v0.5.21 user：紧凑默认 */
  border-bottom: 1px solid var(--line);
  cursor: grab;
  user-select: none;
  -webkit-user-select: none;
  font-size: 13px;
  color: var(--ink-soft);
  touch-action: none;
}
.float-panel-head:active { cursor: grabbing; }
.float-panel-title { font-weight: 600; color: var(--ink); }
.float-panel-body {
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding: 8px;   /* v0.5.21 user：紧凑默认（color panel 等） */
  font-size: 12px;   /* v0.5.23 user：所有浮窗（颜色/滤镜配置…）字号与图层面板对齐 */
}
.float-panel-body input, .float-panel-body select, .float-panel-body button { font-size: 12px; }
/* Blender 同步面板（btp，插件式子功能；沿用 .float-panel 框架，紧凑 + 小屏不溢出） */
.btp-panel { width: 268px; }
/* 关键：body 封顶高度 + 滚动 → 小屏也看得全（head 常驻，body 内滚） */
.btp-panel .float-panel-body { gap: 8px; padding: 10px; max-height: calc(100vh - 92px); overflow-y: auto; }
.btp-row { display: flex; flex-direction: column; gap: 5px; }
.btp-label { font-size: 12px; color: var(--ink-soft); }
.btp-input, .btp-sizepreset {
  box-sizing: border-box;
  padding: 6px 8px;
  border-radius: var(--radius);
  border: 1px solid var(--line);
  background: var(--bg-soft);
  color: var(--ink);
  font-size: 13px;
}
.btp-input { width: 100%; }
.btp-btn {
  padding: 7px 10px;
  border-radius: var(--radius);
  border: 1px solid var(--line);
  background: color-mix(in srgb, var(--bg) 60%, transparent);
  color: var(--ink);
  font-size: 13px;
  cursor: pointer;
}
.btp-btn:hover { background: color-mix(in srgb, var(--accent, #4a90d9) 14%, transparent); }
.btp-btn:disabled { opacity: 0.55; cursor: default; }
.btp-btn.primary { background: var(--accent, #4a90d9); color: #fff; border-color: transparent; }
.btp-btn.btp-sm { padding: 6px 9px; font-size: 12px; flex: 0 0 auto; }

/* main + ⋯ 行（沿用 menu-item-row 思路：主键 flex，⋯ 36px，弹层 absolute 收在行内） */
.btp-action-row { display: flex; gap: 4px; position: relative; align-items: stretch; }
.btp-action-row > .btp-btn:first-child,
.btp-action-row > .btp-connbtn { flex: 1 1 auto; min-width: 0; }

/* 智能连接键：单键多态（off / connecting / on），图标 + 文案 */
.btp-connbtn { display: flex; align-items: center; justify-content: center; gap: 7px; }
.btp-connbtn svg { width: 17px; height: 17px; flex: none; }
.btp-connbtn[data-state="on"] { color: var(--ok); border-color: color-mix(in srgb, var(--ok) 45%, var(--line)); }
.btp-connbtn[data-state="connecting"] { color: var(--warn); }
/* 「连接中」= 静态云 + 独立弧叠放（见 blender-sync.ts 的 ICON_BUSY）。
   .spin-arc 挂在外层 <svg> 上而不是 symbol 内部——<use> 的影子内容外部选择器够不到，
   这么叠一层才能只转弧、不转云。transform-origin 对齐弧在 24×24 里的中心 (12, 13)。 */
.icon-stack { position: relative; display: inline-flex; }
.icon-stack > svg + svg { position: absolute; left: 0; top: 0; }
.icon-stack .spin-arc { transform-origin: 50% 50%; }   /* 上游 spinner 圆心已在 (12,12) */
.btp-connbtn[data-state="connecting"] .spin-arc { animation: wp-spin 1s linear infinite; }
/* v0.5.9：save 按钮「保存中」态——同款双件云 + 转弧（app 层 in-flight flag，见 save-status.ts） */
#topSaveBtn[data-state="saving"] .spin-arc { animation: wp-spin 1s linear infinite; }

/* 拉取 / 推送 主键：图标 + 标签 + 行内 sub（当前配置） */
.btp-action { display: flex; align-items: center; gap: 8px; text-align: left; }
.btp-action-ic { display: flex; flex: none; }
.btp-action-ic svg { width: 18px; height: 18px; }
.btp-action-label { flex: 1 1 auto; }
.btp-action-sub { font-size: 11px; opacity: 0.8; white-space: nowrap; }
.btp-action.primary .btp-action-sub { color: #fff; opacity: 0.85; }

/* 贴图名行：输入框 flex + 两个小键 */
.btp-namerow { display: flex; gap: 5px; align-items: center; }
.btp-namerow .btp-input { flex: 1 1 auto; min-width: 0; }

/* 尺寸行：W × H + 预设 */
.btp-sizerow { display: flex; gap: 5px; align-items: center; }
.btp-sizerow .btp-input { flex: 1 1 auto; min-width: 0; text-align: center; }
.btp-x { color: var(--ink-soft); flex: none; }
.btp-sizepreset { flex: 0 0 auto; cursor: pointer; }

/* ⋯ 弹层（复用 .menu-config-popup 外观；远程配对的更宽以容下文本框） */
.btp-popup { min-width: 168px; }
.close-x {
  background: transparent;
  border: none;
  color: var(--ink-soft);
  font-size: 20px;
  cursor: pointer;
  padding: 0 4px;
  line-height: 1;
}
.close-x:hover { color: var(--ink); }

/* HSV picker */
.sv-pad {
  display: block;
  width: 100%;
  height: auto;   /* v0.5.21：面板可调宽——canvas 属性 240×180 定比例，指针走 boundingRect 缩放安全 */
  border-radius: 6px;
  cursor: crosshair;
  touch-action: none;
}
.hue-slider {
  width: 100%;   /* v0.5.23 user：resize 时 hue 跟着动 */
  height: 18px;
  appearance: none;
  border-radius: 999px;
  background: linear-gradient(to right,
    hsl(0 100% 50%), hsl(60 100% 50%), hsl(120 100% 50%),
    hsl(180 100% 50%), hsl(240 100% 50%), hsl(300 100% 50%), hsl(360 100% 50%));
}
.hue-slider::-webkit-slider-thumb {
  appearance: none;
  width: 18px;
  height: 18px;
  border-radius: 50%;
  background: var(--bg);
  border: 2px solid var(--ink);
  cursor: grab;
}
.picker-row {
  display: flex;
  align-items: center;
  gap: 8px;
}
.picker-row input[type="text"] { flex: 1 1 auto; min-width: 0; }   /* v0.5.23 user：hex 跟面板宽 */
.picker-preview {
  width: 36px;
  height: 36px;
  border-radius: 8px;
  border: 1px solid var(--line);
}
.picker-row input {
  flex: 1;
  padding: 8px;
  border-radius: 6px;
  border: 1px solid var(--line);
  background: var(--bg-soft);
  color: var(--ink);
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
}

/* Update toast */
.toast {
  position: fixed;
  left: 50%;
  bottom: max(env(safe-area-inset-bottom, 0px), 20px);
  transform: translateX(-50%);
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 12px;
  background: var(--ink);
  color: var(--bg);
  border-radius: 999px;
  box-shadow: var(--shadow);
  z-index: var(--z-toast);
  font-size: 13px;
}
.toast button {
  background: transparent;
  border: 1px solid color-mix(in srgb, var(--bg) 40%, transparent);
  color: var(--bg);
  padding: 4px 10px;
  border-radius: 999px;
  font-size: 12px;
  cursor: pointer;
}
.toast button.dismiss {
  border: none;
  font-size: 16px;
  padding: 2px 6px;
}
/* 2026-09-02 压感 toast：与更新 toast 同位同款；两条同时在时压感条让到上一层（叠放不遮） */
/* 2026-09-02 C7 通知栈（src/ui/notice.ts）：所有 toast/横幅进同一条栈；.toast 只管外观，位置/z 归栈。
   模态/gate 开着 → .docked-top（top 由 JS 按顶栏下缘写），底部让给 sheet 的按钮行。 */
.notice-stack {
  position: fixed; left: 50%; transform: translateX(-50%);
  bottom: max(env(safe-area-inset-bottom, 0px), 20px);
  display: flex; flex-direction: column; align-items: center; gap: 8px;
  max-width: calc(100vw - 24px);
  z-index: var(--z-notice);
  pointer-events: none;
}
.notice-stack.docked-top { bottom: auto; }
.notice-stack > .toast { position: static; transform: none; pointer-events: auto; max-width: min(640px, calc(100vw - 24px)); flex-wrap: wrap; justify-content: center; }
.notice-stack > .toast .notice-text { white-space: pre-wrap; word-break: break-word; max-height: 40vh; overflow: auto; }
.toast.notice-error   { background: #c0392b; color: #fff; }
.toast.notice-warning { background: #b7791f; color: #fff; }
.toast.notice-error button, .toast.notice-warning button { color: #fff; border-color: rgba(255, 255, 255, 0.4); }
.toast button.primary { background: rgba(255, 255, 255, 0.18); font-weight: 600; }

/* 移动端紧凑 */
@media (max-width: 540px) {
  .top-bar { gap: 2px; padding: 4px 6px; }
  .tool { width: 32px; height: 32px; }
  .tool svg { width: 18px; height: 18px; }
  .swatch { width: 20px; height: 20px; }
  .swatch.active-color { width: 26px; height: 26px; }
  #sizeSlider { width: 70px; }
  #opacitySlider { width: 60px; }
}

/* ═══ ADR-0006 VP 编辑手柄层：screen 坐标 fixed，只有手柄捕获指针（空白透传给画布 pan/zoom） ═══ */
.persp-handles {
  position: fixed; inset: 0;
  pointer-events: none;
  z-index: calc(var(--z-toolbar) - 1);   /* 同 crop overlay：在画布上、toolbar/弹窗下 */
}
/* （几何条 .ct-tail 右对齐 + ruler-ui 私有 top 2026-09-11 退役：user「几何对齐还会不小心变成右对齐，然后换 context 的时候会突然空出来一大堆白」——
   多条同时可见的叠放归 ui/context-toolbar 工厂 relayoutContextToolbars，owner 不再自己算 top） */
/* 形状条里的格线行列 stepper（shape-toolbar _mountGridCtl；2026-09-18 形状笔回滚复活）。
   user 2026-09-18「rows cols 两个标签删掉，然后数字和 +- 之间紧凑一点，省空间」：无文字标签、组内零 gap、钮 padding 4×4、数字 1.2em 定宽 */
.sb-grid-ctl { display: inline-flex; align-items: center; gap: 6px; }
.sb-grid-ctl .sb-grid-axis { gap: 0; }
.sb-grid-ctl .sb-grid-btn { padding: 4px 4px; min-width: 0; }
.sb-grid-ctl .sb-grid-val { min-width: 1.2em; padding: 0; text-align: center; font-variant-numeric: tabular-nums; }
.persp-handle {
  position: absolute;
  width: 15px; height: 15px; margin: -7.5px 0 0 -7.5px;
  border-radius: 50%;
  border: 1.5px solid #fff;
  background: rgba(64, 140, 255, 0.92);
  box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.55);
  color: #fff; font: 700 9px/12px system-ui, sans-serif; text-align: center;
  pointer-events: auto;
  touch-action: none;
  cursor: grab;
  user-select: none;
}
/* box 顶点分层（user：not every vertex is equal）：A 最大、B 次之、C/D 最小 */
.persp-box-handle {
  border-radius: 3px;
  background: rgba(255, 165, 0, 0.92);
  font-size: 0;
}
.persp-box-handle[data-rank="a"] { width: 13px; height: 13px; margin: -6.5px 0 0 -6.5px; }
.persp-box-handle[data-rank="b"] { width: 10px; height: 10px; margin: -5px 0 0 -5px; }
.persp-box-handle[data-rank="c"] { width: 8px; height: 8px; margin: -4px 0 0 -4px; border-radius: 2px; }

/* v0.6.48 裁剪·模板模式 */
.crop-wh-input { width: 64px; }
/* 模板下拉 compact（2026-08-19 user QoL）：<select> 天然被最长 option（如「A4 竖（2480 × 3508）」）
   撑开，把 crop 工具条拉得怪长。收口只影响闭合态显示；展开列表仍是完整文案，
   目标尺寸另有 cropDim 读数一直可见。 */
#cropTemplateSel { max-width: 130px; text-overflow: ellipsis; }
.crop-safety {
  position: absolute;
  /* inset 由 JS 设（均匀 2% 短边——CSS 百分比 inset 是按轴的，长边会出更多） */
  border: 1px dashed color-mix(in srgb, var(--info) 70%, transparent);
  pointer-events: none;
}
.crop-rect.tpl-move { pointer-events: auto; cursor: move; }
.crop-toolbar-btn { white-space: nowrap; font: inherit; font-size: 13px; }

.crop-toolbar-btn[aria-pressed="true"] {
  background: color-mix(in srgb, var(--accent) 14%, transparent);
  color: var(--accent);
  font-weight: 600;
}

.crop-toolbar-icon {
  min-width: 32px; padding: 4px 0;
  display: inline-flex; align-items: center; justify-content: center;
}
/* 本规则与全局 .hidden 同特异性且靠后 → 必须显式补回（否则 fit 钮在自由模式漏显，v0.6.54 修） */
.crop-toolbar-icon svg { width: 20px; height: 20px; }

/* ── timelapse（宣发轮 2026-08-19，spec=ai-docs/20260819-timelapse-spec.md） ── */
/* 录制指示 chip：HUD 内唯一可点元素（HUD 本体 pointer-events:none）。只有红点+短词，不显示体积。 */
.tl-rec-chip {
  pointer-events: auto;
  display: inline-flex; align-items: center; gap: 5px;
  padding: 1px 8px; margin-left: 2px;
  border: 1px solid var(--line); border-radius: 999px;
  background: transparent; color: var(--ink-soft);
  font-size: 11px; line-height: 1.6; cursor: pointer;
}
.tl-rec-dot {
  width: 8px; height: 8px; border-radius: 50%;
  background: #e5484d;
  animation: tl-breathe 2s ease-in-out infinite;
}
@keyframes tl-breathe { 0%, 100% { opacity: 1; } 50% { opacity: 0.35; } }
@media (prefers-reduced-motion: reduce) { .tl-rec-dot { animation: none; } }
/* 停录态（护栏 C，2026-08-25）：chip 常显但灰点静止——「关了」必须一眼可见 */
.tl-rec-chip.tl-rec-paused .tl-rec-dot { background: var(--ink-soft); animation: none; }

/* 录制面板 */
.float-panel.tl-panel { width: 300px; }
.tl-panel-body { display: flex; flex-direction: column; gap: 10px; padding: 10px 12px 12px; }
.tl-row-label { font-size: 12px; color: var(--ink-soft); }
.tl-chips { display: flex; flex-wrap: wrap; gap: 6px; }
.tl-chip {
  padding: 4px 10px; border: 1px solid var(--line); border-radius: 999px;
  background: transparent; color: var(--ink); font-size: 12px; cursor: pointer;
}
.tl-chip[aria-pressed="true"] { border-color: var(--accent); color: var(--accent); font-weight: 600; }
.tl-chip .tl-chip-sub { opacity: 0.6; font-size: 11px; margin-left: 4px; }
.tl-actions { display: flex; flex-wrap: wrap; gap: 8px; }
.tl-btn {
  flex: 1 1 auto; padding: 7px 10px; border: 1px solid var(--line); border-radius: 8px;
  background: transparent; color: var(--ink); font-size: 13px; cursor: pointer;
}
.tl-btn.tl-primary { border-color: var(--accent); color: var(--accent); font-weight: 600; }
.tl-btn.tl-danger { color: #e5484d; border-color: color-mix(in srgb, #e5484d 50%, var(--line)); }
.tl-btn:disabled { opacity: 0.45; cursor: default; }
.tl-statusline { font-size: 12px; color: var(--ink-soft); display: flex; align-items: center; gap: 6px; }
.tl-note { font-size: 11px; color: var(--ink-soft); opacity: 0.8; }
.tl-video { width: 100%; border-radius: 8px; border: 1px solid var(--line); background: #000; }

/* timelapse 二轮返工（user 2026-08-19）：一行控制 + 全屏回放 overlay */
.tl-btn.tl-more { flex: 0 0 auto; min-width: 40px; }
.tl-preview-overlay {
  position: fixed; inset: 0; z-index: 9000;
  background: rgba(0, 0, 0, 0.88);
  display: flex; align-items: center; justify-content: center;
}
.tl-preview-video {
  max-width: min(96vw, 100%); max-height: 92vh;
  background: #000; border-radius: 6px;
}
.tl-preview-close {
  position: absolute; top: max(env(safe-area-inset-top, 0px), 12px); right: max(env(safe-area-inset-right, 0px), 12px);
  width: 40px; height: 40px; border-radius: 50%;
  border: 1px solid rgba(255,255,255,0.3); background: rgba(0,0,0,0.5); color: #fff; cursor: pointer;
  display: flex; align-items: center; justify-content: center;
}
.tl-preview-close svg { width: 20px; height: 20px; }

/* timelapse 控制排 svg 图标化（user 2026-08-19；宽度均分好看） */
.tl-icon-row { flex-wrap: nowrap; }
.tl-icon-row .tl-btn { flex: 1 1 0; min-width: 0; }   /* 等宽均分（覆盖 .tl-more 的 min-width） */
.tl-icon-btn { display: flex; align-items: center; justify-content: center; padding: 9px 0; }
.tl-icon-btn svg { width: 20px; height: 20px; }
.tl-menu-item.danger { color: #c0392b; }
.tl-menu-item.danger:hover { background: color-mix(in srgb, #c0392b 12%, transparent); }

/* ---- P3 图库管理面（gallery-manage-ui） ---- */
/* history 行（gallery-manage-ui 连接内容「最近连接过的」；0830 终形拍板回归）：行主体 + 忘记✕ */
.gm-row { display: flex; align-items: stretch; gap: 2px; }
.gm-row .menu-item { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.gm-x { flex: 0 0 auto; background: none; border: none; color: inherit; opacity: .55; cursor: pointer; padding: 0 8px; border-radius: 6px; }
.gm-x:hover { opacity: 1; background: color-mix(in srgb, currentColor 12%, transparent); }
/* P6 无库轻折叠：gallery scope 徽章在无库语境藏起（行经 cascade 落 device 层，挂图库徽章=撒谎） */
body[data-no-gallery] svg.menu-scope-badge[data-i18n-title="menu.scopeGalleryTip"] { display: none; }

/* #24 杂物 tile（2026-08-28）：非画作非图片的文件——展示不提供打开（诚实性：夹不再看似空）。 */
.gallery-tile.other-file { opacity: .55; cursor: default; }
.gallery-tile.other-file .gallery-tile-thumb { display: flex; align-items: center; justify-content: center; }
.gallery-tile.other-file .gallery-tile-thumb svg { width: 40%; height: 40%; color: var(--ink-soft); }

/* A2 首帧看门狗（2026-08-31）：loading 卡住时网格内显原因 + 重试（.gallery-loading 已 grid-column 1/-1 居中） */
.gallery-stalled { margin-bottom: 12px; color: var(--ink-soft); }
.gallery-retry-btn { display: inline-block; width: auto; padding: 8px 20px; }
/* dev 诊断日志窗口（diag-log-sheet.ts） */
.diag-log-sheet { max-width: 720px; }
/* 2026-09-06 user「手动 copy 也选不中」：全局 user-select:none 把日志 <pre> 也压死了 → 豁免（同 input/textarea） */
.diag-log-pre { -webkit-touch-callout: default; -webkit-user-select: text; user-select: text; cursor: text; }
.diag-log-pre {
  max-height: 50vh; overflow: auto; margin: 8px 0; padding: 8px; border-radius: 8px;
  font: 11px/1.4 ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  white-space: pre-wrap; word-break: break-word; text-align: left;
  background: rgba(127, 127, 127, 0.12);
  -webkit-user-select: text; user-select: text;
}
