/* ==========================================================================
   节点查看器 · 共享样式
   - 控制页（device.html）与工作空间设备坞（workspace.html）共用同一份
   - 所有规则以 #uiNodeModal 前缀，避免与页面其它 .modal / 表格样式互相污染
   - 令牌全部来自 global.css（--bg-* / --panel-border* / --text-* / --primary* / 语义色），
     另有两个本文件局部衍生令牌 --ins-scrim / --ins-match-soft（见下方 :root 块）
   - 深化轮（2026-11 第二阶段）：弹窗 signature-border 低饱和渐变描边、字号阶梯对齐
     （树/表格 13-14px、表头 micro）、滚动条令牌化（thumb 0.14→0.26）、选中行渐变指示、
     交互三态补齐（深化规范 §2–§4）。纯样式值调整，不动任何类名 / id / 结构。
   ========================================================================== */

/* --------------------------------------------------------------------------
   本文件局部衍生令牌（纯增量）：由 global.css 全局令牌 color-mix 派生，
   随 --bg-base / --warning 自动适配深浅两套主题，无需 light 覆盖
   （同 global.css --panel-bg-hover 等桥令牌的思路）。
   --ins-scrim      截图区悬浮件（坐标 / 抓取状态 / 刷新按钮）的半透明底
   --ins-match-soft 属性表搜索命中行的淡警示底
   -------------------------------------------------------------------------- */
:root {
  --ins-scrim: color-mix(in srgb, var(--bg-base) 86%, transparent);
  --ins-match-soft: color-mix(in srgb, var(--warning) 8%, transparent);
}

/* 面板尺寸：宽屏四列布局需要足够的横向空间。
   实际尺寸由 JS 写到 --ins-panel-w / --ins-panel-h（用户拖拽或点「放大」后记住），
   没有这两个变量时退回下面的默认值 —— 用 var() 而不是直接写宽高，
   是为了让「用户偏好」和「默认值」只有一处来源，改默认值不用同时改 JS。 */
#uiNodeModal .modal-panel--wide {
  position: relative;
  width: var(--ins-panel-w, min(1440px, 97vw));
  height: var(--ins-panel-h, min(900px, 92vh));
  /*
   * 覆盖全局 .modal-panel 的 max-height: calc(100vh - 48px)。
   * 那条限制是给普通表单弹窗的，放在这里会让「放大」永远差 24px 够不到窗口边缘 ——
   * 用户点放大看到的是「按钮没反应」，因为 isPanelMaxed() 判不满就不切成「还原」。
   * 真正的上限由 JS 的 panelMaxSize() 按 .modal 的 padding 算，比这里写死更准。
   */
  max-height: none;
  padding: 0;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  /*
   * 弹窗表皮（深化规范 §3.1 招牌 · 低饱和版）：1px 渐变描边用双层背景实现，
   * 边层引用 global.css 的 --signature-gradient-soft（浅色主题有对应的更淡变体），
   * 内层填充走 --signature-fill（= --bg-elevated）；不用 ::before 叠层，不占布局。
   */
  border: 1px solid transparent;
  background:
    linear-gradient(var(--signature-fill), var(--signature-fill)) padding-box,
    var(--signature-gradient-soft) border-box;
  border-radius: var(--radius-xl);
  box-shadow: var(--shadow-lg), var(--card-highlight);
}

/* 遮罩：深化规范 §4 弹窗口径 —— --backdrop 底 + 6px blur。global.css 的
   .modal-backdrop 已有同值规则，这里就地钉死，保证本弹窗单独取用时不掉模糊。 */
#uiNodeModal .modal-backdrop {
  background: var(--backdrop);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
}

/* ---- 四角缩放手柄 ----
   每个角单独定位，光标方向与角一致（nw/se 是主对角线，ne/sw 是副对角线）。
   斜纹用同一个渐变，靠 transform: rotate 翻转，省掉四份重复的 linear-gradient。 */
#uiNodeModal .node-resize-handle {
  position: absolute;
  width: 18px;
  height: 18px;
  z-index: 5;
  opacity: 0.65;
  transition: opacity var(--transition);
  /* 手柄本身不接收文本选择，拖动时也不会选中面板里的节点文字 */
  user-select: none;
}

#uiNodeModal .node-resize-handle::before {
  content: "";
  position: absolute;
  inset: 0;
  /* 两道斜线暗示可拖拽，和原生窗口角标一个语义 */
  background-image: linear-gradient(
    135deg,
    transparent 0 52%,
    var(--panel-border-strong) 52% 60%,
    transparent 60% 72%,
    var(--panel-border-strong) 72% 80%,
    transparent 80%
  );
}

#uiNodeModal .node-resize-handle--se {
  right: 0;
  bottom: 0;
  cursor: nwse-resize;
  border-bottom-right-radius: var(--radius-xl);
}

#uiNodeModal .node-resize-handle--nw {
  left: 0;
  top: 0;
  cursor: nwse-resize;
  border-top-left-radius: var(--radius-xl);
}

/* 右上 / 左下：斜纹转 90°，看起来像是从那个角往里长 */
#uiNodeModal .node-resize-handle--ne {
  right: 0;
  top: 0;
  cursor: nesw-resize;
  border-top-right-radius: var(--radius-xl);
}

#uiNodeModal .node-resize-handle--ne::before {
  transform: rotate(90deg);
}

#uiNodeModal .node-resize-handle--sw {
  left: 0;
  bottom: 0;
  cursor: nesw-resize;
  border-bottom-left-radius: var(--radius-xl);
}

#uiNodeModal .node-resize-handle--sw::before {
  transform: rotate(90deg);
}

#uiNodeModal .node-resize-handle:hover,
#uiNodeModal .node-resize-handle:focus-visible,
#uiNodeModal .node-resize-handle.is-dragging {
  opacity: 1;
  outline: none;
}

/* 拖拽中禁掉整页文本选择，否则会选到面板里的节点文字 */
#uiNodeModal.is-resizing,
#uiNodeModal.is-resizing * {
  user-select: none !important;
}

#uiNodeModal .modal-head {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  padding: var(--space-3) var(--space-4);
  border-bottom: 1px solid var(--panel-border);
}

#uiNodeModal .modal-head-left {
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 2px;
}

#uiNodeModal .modal-head-left h2 {
  margin: 0;
  /* 字号阶梯（深化规范 §2）：弹窗标题 = h2 档（16px / 650 / -0.01em） */
  font-size: var(--fs-h2);
  font-weight: 650;
  line-height: var(--lh-h2);
  letter-spacing: var(--ls-h2);
  color: var(--text-main);
}

#uiNodeModal .modal-sub {
  font-size: var(--fs-micro);
  color: var(--text-muted);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

#uiNodeModal .modal-head-actions {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  flex: 0 0 auto;
}

#uiNodeModal .modal-close {
  width: 28px;
  height: 28px;
  font-size: var(--fs-body); /* 14px = 阶梯 body 档（✕ 字形） */
}

/* ==================== 节点查看器 ==================== */

/*
 * 设备控制条（导航 / 电源）。
 *
 * 从工作空间调试台迁过来：调试台只管「选设备 + 跑脚本」，
 * 而按返回键、亮屏解锁这些动作是在挑节点的过程中随手要用的，
 * 每次都要关掉面板回调试台点一下再打开，是这块最别扭的地方。
 *
 * 横向两组并排，窄屏自动换行；不设 max-width —— 这里横跨整个弹窗宽度，
 * 按钮被拉长反而更好点。
 */
#uiNodeModal .node-device-bar {
  flex: 0 0 auto;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px var(--space-4);
  padding: var(--space-2) var(--space-4);
  border-bottom: 1px solid var(--panel-border);
  background: var(--bg-sunken);
}

#uiNodeModal .node-device-group {
  display: flex;
  align-items: center;
  gap: 5px;
  min-width: 0;
}

#uiNodeModal .node-device-label {
  flex: 0 0 auto;
  /* micro 微标签（深化规范 §2）：11px / 600 / +0.08em（中文无大小写形态，大写变换为空操作） */
  font-size: var(--fs-micro);
  font-weight: 600;
  letter-spacing: var(--ls-micro);
  text-transform: uppercase;
  color: var(--text-muted);
  white-space: nowrap;
}

#uiNodeModal .node-device-btn {
  flex: 0 0 auto;
  min-width: 48px;
  min-height: 26px;
  padding: 0 10px;
  font-family: var(--font-sans);
  font-size: var(--fs-caption);
  color: var(--text-main);
  background: var(--bg-elevated);
  border: 1px solid var(--panel-border);
  border-radius: var(--radius-sm);
  cursor: pointer;
  white-space: nowrap;
  transition: background var(--transition), border-color var(--transition), color var(--transition),
    transform var(--transition);
}

/* hover 对齐规范 §4 次要按钮：换亮边框 + 悬浮底（不动主色，主色留给 accent 变体） */
#uiNodeModal .node-device-btn:hover:not(:disabled) {
  background: var(--bg-hover);
  border-color: var(--panel-border-strong);
  color: var(--text-main);
}

#uiNodeModal .node-device-btn:active:not(:disabled) {
  background: var(--bg-active);
  /* 深化规范 §4 次按钮按下：scale(.98) */
  transform: scale(0.98);
}

/* 亮屏解锁是熄屏设备的常用入口，单独给主色 */
#uiNodeModal .node-device-btn--accent {
  color: var(--primary);
  border-color: var(--primary-ring);
}

/* accent 变体的 hover：基类 hover 会把边框换回中性亮边，这里保住主色辨识度 */
#uiNodeModal .node-device-btn--accent:hover:not(:disabled) {
  border-color: var(--primary);
  color: var(--primary);
}

#uiNodeModal .node-device-btn:disabled {
  opacity: 0.45;
  cursor: not-allowed;
}

/* 键盘焦点（深化规范 §4 三态）：统一焦点环；圆角沿用基类 --radius-sm */
#uiNodeModal .node-device-btn:focus-visible {
  outline: none;
  box-shadow: var(--focus-ring);
}

#uiNodeModal .node-toolbar {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  padding: var(--space-2) var(--space-4);
  border-bottom: 1px solid var(--panel-border);
  background: var(--bg-base);
}

#uiNodeModal .node-search {
  position: relative;
  display: flex;
  align-items: center;
  gap: 6px;
  flex: 1 1 auto;
  min-width: 0;
  max-width: 460px;
}

#uiNodeModal .node-search svg {
  position: absolute;
  left: 9px;
  width: 13px;
  height: 13px;
  fill: none;
  stroke: var(--text-muted);
  stroke-width: 1.6;
  stroke-linecap: round;
  pointer-events: none;
}

#uiNodeModal .node-search input {
  width: 100%;
  padding: 6px 8px 6px 28px;
  font-family: var(--font-sans);
  font-size: var(--fs-secondary);
  color: var(--text-main);
  background: var(--bg-input);
  border: 1px solid var(--panel-border);
  border-radius: var(--radius-sm);
}

/* hover 边框变亮（深化规范 §4 输入框行）：本文件基础规则特异性高于 global 的
   input:hover，必须在同前缀下显式补一份，否则 hover 永远不变亮 */
#uiNodeModal .node-search input:hover {
  border-color: var(--panel-border-strong);
}

/* 输入聚焦对齐 global.css 裸表单基线：主色边框 + 主色外圈 */
#uiNodeModal .node-search input:focus {
  outline: none;
  border-color: var(--primary);
  box-shadow: 0 0 0 3px var(--primary-ring);
}

#uiNodeModal .node-search-hint {
  position: absolute;
  right: 8px;
  font-size: var(--fs-micro);
  color: var(--text-muted);
  pointer-events: none;
  background: var(--bg-input);
  padding-left: 6px;
}

/* 命中/无结果用 -text 可读变体（规范 §2：块用 -soft 底，文字用 -text） */
#uiNodeModal .node-search-hint.is-match {
  color: var(--success-text);
}

#uiNodeModal .node-search-hint.is-empty {
  color: var(--danger-text);
}

#uiNodeModal .node-toolbar-right {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  flex: 0 0 auto;
}

/* 输入文本（工具条中部，原工作空间调试台的「输入文本」按钮迁来）：
   与左侧搜索框同一行、同高、同边框语言，宽度弹性收缩，窄屏优先让搜索框保留空间 */
#uiNodeModal .node-inputtext {
  display: flex;
  align-items: center;
  gap: 6px;
  flex: 0 1 300px;
  min-width: 140px;
}

#uiNodeModal .node-inputtext input {
  width: 100%;
  min-width: 0;
  padding: 6px 8px;
  font-family: var(--font-sans);
  font-size: var(--fs-secondary);
  color: var(--text-main);
  background: var(--bg-input);
  border: 1px solid var(--panel-border);
  border-radius: var(--radius-sm);
}

#uiNodeModal .node-inputtext input:hover {
  border-color: var(--panel-border-strong);
}

#uiNodeModal .node-inputtext input:focus {
  outline: none;
  border-color: var(--primary);
  box-shadow: 0 0 0 3px var(--primary-ring);
}

#uiNodeModal .node-inputtext .node-tool-btn {
  flex: 0 0 auto;
  white-space: nowrap;
}

#uiNodeModal .node-toggle {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font-size: var(--fs-caption);
  color: var(--text-muted);
  cursor: pointer;
  user-select: none;
  white-space: nowrap;
  transition: color var(--transition-fast);
}

#uiNodeModal .node-toggle:hover {
  color: var(--text-regular);
}

#uiNodeModal .node-toggle input {
  width: 13px;
  height: 13px;
  margin: 0;
  accent-color: var(--primary);
  cursor: pointer;
}

#uiNodeModal .node-tool-btn {
  padding: 4px 9px;
  font-family: var(--font-sans);
  font-size: var(--fs-caption);
  color: var(--text-muted);
  background: transparent;
  border: 1px solid var(--panel-border);
  border-radius: var(--radius-sm);
  cursor: pointer;
  transition: all var(--transition);
  white-space: nowrap;
}

#uiNodeModal .node-tool-btn:hover {
  color: var(--text-main);
  background: var(--bg-hover);
  border-color: var(--panel-border-strong); /* 对齐规范 §4 次要按钮 hover 口径 */
}

#uiNodeModal .node-tool-btn:active {
  background: var(--bg-active);
  transform: scale(0.98);
}

#uiNodeModal .node-tool-btn:focus-visible {
  outline: none;
  box-shadow: var(--focus-ring);
}

#uiNodeModal .node-body {
  flex: 1 1 auto;
  min-height: 0;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}

#uiNodeModal .node-empty {
  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--space-3);
  color: var(--text-muted);
  font-size: var(--font-size-sm);
}

#uiNodeModal .node-empty p {
  margin: 0;
}

/* 三栏工作区 */
#uiNodeModal .node-workspace {
  flex: 1 1 auto;
  /* 截图区至少留这么高：选择器面板展开时 grid 会被压到 0 高度，
     用户看到的是「截图不见了」。给个下限后，挤压发生在下方面板内部（它可滚）。 */
  min-height: 220px;
  display: grid;
  grid-template-columns: minmax(0, 0.9fr) minmax(0, 1.15fr) minmax(0, 0.85fr);
  gap: 1px;
  background: var(--panel-border);
  overflow: hidden;
}

/* ---- 左：截图 ---- */

#uiNodeModal .node-preview {
  display: flex;
  flex-direction: column;
  min-height: 0;
  min-width: 0;
  background: var(--bg-base);
  padding: var(--space-3);
  gap: var(--space-2);
}

#uiNodeModal .node-shot-wrap {
  position: relative;
  flex: 1 1 auto;
  min-height: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  /* 截图留白底：用凹陷色令牌（规范 §5「截图缩略图区内嵌 --bg-sunken」），深浅主题各自成立 */
  background: var(--bg-sunken);
  border: 1px solid var(--panel-border);
  border-radius: var(--radius-sm);
  overflow: hidden;
}

#uiNodeModal .node-shot {
  display: block;
  max-width: 100%;
  max-height: 100%;
  object-fit: contain;
  user-select: none;
  cursor: crosshair;
}

#uiNodeModal .node-shot-overlay {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
}

#uiNodeModal .node-shot-coords {
  position: absolute;
  right: 6px;
  bottom: 6px;
  padding: 2px 7px;
  font-family: var(--font-mono);
  font-size: var(--fs-micro);
  color: var(--text-main);
  background: var(--ins-scrim);
  border-radius: 3px;
  pointer-events: none;
}

/* ---- 截图右上角：抓取状态 + 重抓按钮 ----
   放在截图内部而不是顶栏：抓一次要「截图 → 遍历 → 回传」几秒，
   用户视线在截图上，状态就该在那儿，旁边直接就能重抓。 */
#uiNodeModal .node-shot-tools {
  position: absolute;
  top: 6px;
  right: 6px;
  display: flex;
  align-items: center;
  gap: 4px;
  z-index: 2;
}

#uiNodeModal .node-shot-status {
  padding: 2px 8px;
  font-family: var(--font-mono);
  font-size: var(--fs-micro);
  line-height: 1.6;
  color: var(--text-muted);
  background: var(--ins-scrim);
  border: 1px solid var(--panel-border-strong);
  border-radius: 3px;
  white-space: nowrap;
  max-width: 200px;
  overflow: hidden;
  text-overflow: ellipsis;
  pointer-events: none;
}

/* 四态各用一个语义色（文字用 -text 可读变体），扫一眼就知道这次抓成功没有 */
#uiNodeModal .node-shot-status[data-state="loading"] {
  color: var(--warning-text);
  border-color: var(--warning);
}

#uiNodeModal .node-shot-status[data-state="ok"] {
  color: var(--success-text);
  border-color: var(--success);
}

#uiNodeModal .node-shot-status[data-state="error"] {
  color: var(--danger-text);
  border-color: var(--danger);
}

#uiNodeModal .node-shot-refresh {
  padding: 2px 9px;
  font-family: var(--font-sans);
  font-size: var(--fs-caption);
  line-height: 1.6;
  color: var(--text-main);
  background: var(--ins-scrim);
  border: 1px solid var(--panel-border-strong);
  border-radius: 3px;
  cursor: pointer;
  transition: background var(--transition), border-color var(--transition), color var(--transition),
    transform var(--transition);
}

/* hover 升级为主操作底色：强调底上的文字一律 --text-on-primary（规范 §2） */
#uiNodeModal .node-shot-refresh:hover:not(:disabled) {
  background: var(--primary);
  border-color: var(--primary);
  color: var(--text-on-primary);
}

#uiNodeModal .node-shot-refresh:active:not(:disabled) {
  background: var(--primary-active);
  border-color: var(--primary-active);
  transform: scale(0.97);
}

#uiNodeModal .node-shot-refresh:focus-visible {
  outline: none;
  box-shadow: var(--focus-ring);
}

#uiNodeModal .node-shot-refresh:disabled {
  opacity: 0.55;
  cursor: wait;
}

/* 七个动作按钮：flex 换行而不是固定三列 —— 固定列在窄栏会排成三行，
   把截图压成一条；按内容宽度排能塞五个一行，最多两行。 */
#uiNodeModal .node-preview-actions {
  flex: 0 0 auto;
  display: flex;
  flex-wrap: wrap;
  gap: 5px;
}

#uiNodeModal .node-preview-actions .hud-btn {
  flex: 1 1 auto;
  padding: 6px 4px;
  font-size: var(--fs-caption);
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* ---- 中：节点树 ---- */

#uiNodeModal .node-tree-col {
  display: flex;
  flex-direction: column;
  min-height: 0;
  min-width: 0;
  background: var(--bg-base);
}

#uiNodeModal .node-col-head {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2);
  padding: 6px var(--space-3);
  /* 表头 micro 化（深化规范 §2）：11px / 600 / +0.08em */
  font-size: var(--fs-micro);
  font-weight: 600;
  letter-spacing: var(--ls-micro);
  text-transform: uppercase;
  color: var(--text-muted);
  border-bottom: 1px solid var(--panel-border);
}

#uiNodeModal .node-count {
  font-family: var(--font-mono);
  font-weight: 400;
  color: var(--text-muted);
  letter-spacing: normal; /* 数字计数不继承 micro 的 +0.08em，保持等宽紧凑 */
}

/* 树容器：纵向滚 + 横向滚。
   横向滚动条由下面那条自绘的 .node-tree-hscroll 承担，这里把原生横条藏掉。

   ⚠ 不要在这里加标准滚动条的两个简写属性（规范铁律 4 明令禁止的那对）。
   Chrome 121+ 只要元素上出现这两个标准属性，就会切到「标准滚动条」渲染模式，
   并把该元素的所有 ::-webkit-scrollbar 规则整体忽略 —— 包括下面那条
   `:horizontal { height: 0 }`。结果就是原生横条和自绘横条同时出现，
   树底下变成两条滑块（用户反馈的「有两个滑动了」就是这么来的）。 */
#uiNodeModal .node-tree {
  flex: 1 1 auto;
  min-height: 0;
  overflow-x: auto;
  overflow-y: auto;
  padding: 4px 0;
  font-family: var(--font-mono);
  /* 字号阶梯（深化规范 §2）：树/表格正文 13-14px —— 树取 13px（--fs-secondary） */
  font-size: var(--fs-secondary);
  line-height: var(--lh-body);
}

/* 原生横条整条收掉，横向只留自绘那一条 */
#uiNodeModal .node-tree::-webkit-scrollbar:horizontal {
  height: 0;
}

/* ---- 节点树横向滚动条 ----
   树行是 nowrap 的，深层节点 + 长 text/id 会超出右边界被裁掉。
   原生横条要 Shift+滚轮或触控板才拖得到，鼠标用户基本用不上，
   所以单独做一条常驻的：拖滑块、点轨道、滚轮都能横向移动。 */
#uiNodeModal .node-tree-hscroll {
  flex: 0 0 auto;
  position: relative;
  height: 11px;
  margin: 0 4px 4px;
  border-radius: 6px;
  background: var(--bg-sunken);
  cursor: pointer;
  touch-action: none;
}

#uiNodeModal .node-tree-hthumb {
  position: absolute;
  top: 2px;
  left: 0;
  height: 7px;
  min-width: 28px;
  border-radius: 4px;
  /* 与 webkit 滚动条同源令牌：暗 rgba(255,255,255,.14) / 悬停 .26 */
  background: var(--scrollbar-thumb);
  cursor: grab;
  transition: background var(--transition);
}

#uiNodeModal .node-tree-hscroll:hover .node-tree-hthumb {
  background: var(--scrollbar-thumb-hover);
}

#uiNodeModal .node-tree-hthumb.is-dragging {
  background: var(--primary);
  cursor: grabbing;
}

/* 内容没有溢出时整条隐藏，不占视觉噪音 */
#uiNodeModal .node-tree-hscroll.is-idle {
  display: none;
}

#uiNodeModal .node-tree::-webkit-scrollbar,
#uiNodeModal .node-props-scroll::-webkit-scrollbar,
#uiNodeModal .node-raw::-webkit-scrollbar {
  width: 8px;
  height: 8px;
}

/* thumb 走 global 滚动条令牌：暗 rgba(255,255,255,.14) / 悬停 .26，
   浅色主题由 :root[data-theme="light"] 自动换成黑系（0.18 / 0.3） */
#uiNodeModal .node-tree::-webkit-scrollbar-thumb,
#uiNodeModal .node-props-scroll::-webkit-scrollbar-thumb,
#uiNodeModal .node-raw::-webkit-scrollbar-thumb {
  background: var(--scrollbar-thumb);
  border-radius: var(--radius-pill);
}

#uiNodeModal .node-tree::-webkit-scrollbar-thumb:hover,
#uiNodeModal .node-props-scroll::-webkit-scrollbar-thumb:hover,
#uiNodeModal .node-raw::-webkit-scrollbar-thumb:hover {
  background: var(--scrollbar-thumb-hover);
}

#uiNodeModal .ui-tree-node {
  display: block;
}

#uiNodeModal .ui-tree-row {
  display: flex;
  align-items: center;
  gap: 4px;
  padding: 1px 8px 1px calc(8px + var(--tree-depth, 0) * 13px);
  cursor: pointer;
  white-space: nowrap;
  /*
   * 行宽跟着内容走，不裁到容器宽度。
   *
   * 原来这里是 overflow:hidden + 容器 overflow:auto：行的宽度永远等于容器宽，
   * 溢出的文字被直接切掉，树也就永远没有横向溢出 —— 于是长 id、长 text 只能看半截，
   * 底下那条横向滚动条也没内容可滚。改成 max-content 之后整行按内容撑开，
   * 容器负责横向滚动，配合下面常驻的滑块就能看到完整文本。
   */
  width: max-content;
  min-width: 100%;
  border-left: 2px solid transparent;
  transition: background var(--transition-fast);
}

#uiNodeModal .ui-tree-row:hover {
  background: var(--bg-hover);
}

#uiNodeModal .ui-tree-row.selected {
  background: var(--primary-soft);
  /*
   * 深化规范 §3.4「选中行左缘 2px 渐变条」：border-image 引用 --accent-gradient，
   * 其余三边宽度为 0 不受影响（slice:1 时 2px 左边条内显示的是渐变左缘的纵向过渡）。
   * border-left-color 保留作回退：变量失效时退化为纯主色条而不是消失。
   */
  border-left-color: var(--primary);
  border-image: var(--accent-gradient) 1;
}

/* 搜索命中的节点：警示色文字变体高亮（树文字语义沿用 -text 系列） */
#uiNodeModal .ui-tree-row--match .ui-tree-cls {
  color: var(--warning-text);
}

#uiNodeModal .ui-tree-toggle {
  flex: 0 0 auto;
  width: 13px;
  height: 13px;
  padding: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  /* 折叠指示是文本字符「▸/▾」：阶梯最小 11px（深化规范 §2），在 13px 盒内仍是轻量符号 */
  font-size: var(--fs-micro);
  line-height: 1;
  color: var(--text-muted);
  background: transparent;
  border: none;
  border-radius: 2px;
  cursor: pointer;
}

#uiNodeModal .ui-tree-toggle:hover {
  color: var(--text-main);
  background: var(--bg-hover);
}

#uiNodeModal .ui-tree-toggle--empty {
  pointer-events: none;
}

/* 标签容器不再裁字：整行按内容撑开，超出部分交给下面那条横向滚动条。
   文字本身仍保留在 title 里，鼠标悬停也能看全。 */
#uiNodeModal .ui-tree-label {
  display: flex;
  align-items: baseline;
  gap: 5px;
  flex: 0 0 auto;
}

#uiNodeModal .ui-tree-cls {
  color: var(--primary-hover);
  flex: 0 0 auto;
}

#uiNodeModal .ui-tree-text {
  color: var(--success-text);
  flex: 0 0 auto;
}

#uiNodeModal .ui-tree-id {
  color: var(--warning-text);
  flex: 0 0 auto;
  font-size: var(--fs-caption);
}

#uiNodeModal .ui-tree-meta {
  color: var(--text-muted);
  font-size: var(--fs-micro);
  flex: 0 0 auto;
}

#uiNodeModal .ui-tree-children.collapsed {
  display: none;
}

/* ---- 右：属性 ---- */

#uiNodeModal .node-props-col {
  display: flex;
  flex-direction: column;
  min-height: 0;
  min-width: 0;
  background: var(--bg-base);
}

#uiNodeModal .node-props-scroll {
  flex: 1 1 auto;
  min-height: 0;
  overflow: auto;
}

#uiNodeModal .node-props-table {
  width: 100%;
  border-collapse: collapse;
  /* 字号阶梯（深化规范 §2）：表格正文 13px */
  font-size: var(--fs-secondary);
}

#uiNodeModal .node-props-table tr {
  border-bottom: 1px solid var(--panel-border);
}

#uiNodeModal .node-props-table tr:last-child {
  border-bottom: none;
}

#uiNodeModal .node-props-table td {
  padding: 5px 8px;
  vertical-align: top;
  word-break: break-all;
  line-height: var(--lh-secondary);
}

#uiNodeModal .node-props-table td:first-child {
  width: 1%;
  white-space: nowrap;
  color: var(--text-muted);
  font-family: var(--font-mono);
  font-size: var(--fs-caption);
}

#uiNodeModal .node-props-table td:last-child {
  font-family: var(--font-mono);
  color: var(--text-main);
}

#uiNodeModal .node-props-table tr.is-match td {
  background: var(--ins-match-soft);
}

/* 行 hover（深化规范 §4 表格行）：辅助扫读长属性列表；命中行的 td 淡警示底
   盖在 tr 之上、且 ：not(.is-match) 双保险，悬浮不会冲掉搜索命中高亮 */
#uiNodeModal .node-props-table tbody tr {
  transition: background var(--transition-fast);
}

#uiNodeModal .node-props-table tbody tr:not(.is-match):hover {
  background: var(--bg-hover);
}

#uiNodeModal .node-props-table .props-empty {
  text-align: center;
  color: var(--text-muted);
  font-family: var(--font-sans);
  padding: var(--space-5) var(--space-3);
}

#uiNodeModal .node-props-table .prop-bool-true {
  color: var(--success-text);
}

#uiNodeModal .node-props-table .prop-bool-false {
  color: var(--text-muted);
}

/* 原始 JSON 兜底 */
#uiNodeModal .node-raw {
  flex: 0 0 auto;
  max-height: 40vh;
  margin: 0;
  padding: var(--space-3) var(--space-4);
  font-family: var(--font-mono);
  font-size: var(--fs-caption);
  line-height: var(--lh-body);
  color: var(--text-muted);
  background: var(--bg-sunken);
  border-top: 1px solid var(--panel-border);
  overflow: auto;
  white-space: pre-wrap;
  word-break: break-all;
}

#uiNodeModal .node-raw:empty {
  display: none;
}


/* ==================== 节点查看器 · 选择器构造 ==================== */
/*
 * 通栏放在三栏工作区下方：≤1180px 时 .node-props-col 被整体隐藏，
 * 选择器构造放进属性列会在窄屏上直接消失。
 */

#uiNodeModal .ins-selector-panel {
  flex: 0 0 auto;
  min-height: 0;
  max-height: 42vh;
  overflow: auto;
  padding: var(--space-2) var(--space-4) var(--space-3);
  background: var(--bg-base);
  border-top: 1px solid var(--panel-border);
}

#uiNodeModal .ins-selector-panel::-webkit-scrollbar {
  width: 8px;
  height: 8px;
}

/* 收起后只留标题栏：截图区自动长高，挑节点时看得更清 */
#uiNodeModal .ins-selector-panel.is-collapsed {
  max-height: none;
  padding-bottom: var(--space-2);
}

#uiNodeModal .ins-selector-body.is-collapsed {
  display: none;
}

#uiNodeModal .ins-selector-panel::-webkit-scrollbar-thumb {
  background: var(--scrollbar-thumb);
  border-radius: var(--radius-pill);
}

#uiNodeModal .ins-selector-panel::-webkit-scrollbar-thumb:hover {
  background: var(--scrollbar-thumb-hover);
}

#uiNodeModal .ins-selector-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2);
  flex-wrap: wrap;
  margin-bottom: var(--space-2);
}

#uiNodeModal .ins-selector-title {
  /* micro 微标签（深化规范 §2）：11px / 600 / +0.08em */
  font-size: var(--fs-micro);
  font-weight: 600;
  letter-spacing: var(--ls-micro);
  text-transform: uppercase;
  color: var(--text-muted);
}

#uiNodeModal .ins-selector-head-actions {
  display: flex;
  align-items: center;
  gap: 5px;
  flex-wrap: wrap;
}

#uiNodeModal .ins-selector-head-actions .btn {
  padding: 0 9px;
}

/* 字段区：六项两行三列，窄屏自动降列，避免每个字段被压成一条细线 */
/* 三项一行：再宽就会把 className/packageName 的输入框压到看不全值 */
#uiNodeModal .ins-selector-fields {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(360px, 1fr));
  gap: 5px var(--space-3);
}

#uiNodeModal .ins-field {
  display: grid;
  grid-template-columns: 13px 74px minmax(0, 1fr) 78px;
  align-items: center;
  gap: 5px;
}

/* 启用勾选框：不参与匹配的字段整行压暗，避免用户以为填了就会生效 */
#uiNodeModal .ins-field-on {
  width: 13px;
  height: 13px;
  margin: 0;
  padding: 0;
  accent-color: var(--primary);
  cursor: pointer;
}

#uiNodeModal .ins-field.is-off .ins-field-label,
#uiNodeModal .ins-field.is-off .ins-field-input {
  opacity: 0.45;
}

#uiNodeModal .ins-field.is-off .ins-field-mode {
  opacity: 0.45;
}

#uiNodeModal .ins-field-label {
  font-family: var(--font-mono);
  font-size: var(--fs-micro);
  color: var(--text-muted);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/*
 * 覆盖全局裸表单基线（14px + 8px 内边距），否则两行字段就撑爆面板。
 *
 * 必须带 #uiNodeModal 前缀：global.css 里是 `input[type="text"]`，特异性 (0,1,1)，
 * 而裸 `.ins-field-input` 只有 (0,1,0) —— 光靠「后加载」赢不了，字号和内边距会一直是全局值，
 * 同一行的 select（带前缀，1,1,0）却生效，input 与 select 高度对不齐。
 */
#uiNodeModal .ins-field-input,
#uiNodeModal .ins-field-mode {
  width: 100%;
  padding: 4px 7px;
  font-family: var(--font-mono);
  font-size: var(--fs-caption);
  line-height: 1.5;
  color: var(--text-main);
  background: var(--bg-input);
  border: 1px solid var(--panel-border);
  border-radius: var(--radius-sm);
}

/* hover 边框变亮（深化规范 §4；同上，基础规则特异性高，必须显式补） */
#uiNodeModal .ins-field-input:hover,
#uiNodeModal .ins-field-mode:hover {
  border-color: var(--panel-border-strong);
}

/* 聚焦对齐规范 §4：主色边框 + 主色外圈 */
#uiNodeModal .ins-field-input:focus,
#uiNodeModal .ins-field-mode:focus {
  outline: none;
  border-color: var(--primary);
  box-shadow: 0 0 0 3px var(--primary-ring);
}

#uiNodeModal .ins-field-mode {
  font-family: var(--font-sans);
  cursor: pointer;
}

#uiNodeModal .ins-field-mode option:disabled {
  color: var(--text-muted);
}

#uiNodeModal .ins-selector-preview {
  display: flex;
  align-items: stretch;
  gap: var(--space-3);
  margin-top: var(--space-2);
  min-width: 0;
}

#uiNodeModal .ins-selector-json {
  flex: 0 1 auto;
  min-width: 0;
  max-width: 46%;
  max-height: 112px;
  margin: 0;
  padding: 5px 8px;
  overflow: auto;
  font-family: var(--font-mono);
  font-size: var(--fs-caption);
  line-height: 1.5;
  color: var(--primary-hover);
  background: var(--bg-sunken);
  border: 1px solid var(--panel-border);
  border-radius: var(--radius-sm);
  white-space: pre;
}

#uiNodeModal .ins-selector-json::-webkit-scrollbar {
  width: 8px;
  height: 8px;
}

#uiNodeModal .ins-selector-json::-webkit-scrollbar-thumb {
  background: var(--scrollbar-thumb);
  border-radius: var(--radius-pill);
}

#uiNodeModal .ins-selector-json::-webkit-scrollbar-thumb:hover {
  background: var(--scrollbar-thumb-hover);
}

#uiNodeModal .ins-selector-summary {
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  align-items: center;
  font-size: var(--fs-caption);
  line-height: 1.6;
  color: var(--text-muted);
  word-break: break-word;
}

#uiNodeModal .ins-selector-summary.is-empty {
  color: var(--text-muted);
}

/*
 * 歧义提示：告诉用户这个选择器在本页会命中几个、序号指向的是不是他选的那个。
 * 三态用左边框 + 文字色区分，不铺背景色块 —— 面板本身已有底色，
 * 再叠一层色块在深色主题下对比度很难同时照顾到。
 */
#uiNodeModal .ins-ambiguity {
  flex: 1 1 100%;
  margin-top: 4px;
  padding: 5px 8px;
  border-left: 3px solid var(--border-strong);
  border-radius: 0 4px 4px 0;
  font-size: var(--fs-caption);
  line-height: 1.6;
  color: var(--text-muted);
  word-break: break-word;
}

#uiNodeModal .ins-ambiguity.hidden {
  display: none;
}

#uiNodeModal .ins-ambiguity.is-ok {
  border-left-color: var(--success);
  color: var(--text-regular);
}

#uiNodeModal .ins-ambiguity.is-warn {
  border-left-color: var(--warning);
  color: var(--text-regular);
}

#uiNodeModal .ins-ambiguity.is-error {
  border-left-color: var(--danger);
  color: var(--danger-text);
  font-weight: 600;
}

/* 按钮行吸底：面板内容超过 max-height 要滚动，而「写入脚本库」是主操作，
   不能因为用户还没滚到底就看不见。吸底后任何滚动位置都能点到。 */
#uiNodeModal .ins-selector-buttons {
  position: sticky;
  bottom: 0;
  z-index: 2;
  display: flex;
  align-items: center;
  gap: 5px;
  flex-wrap: wrap;
  margin-top: var(--space-2);
  padding: var(--space-2) 0 2px;
  background: var(--bg-base);
  border-top: 1px solid var(--panel-border);
}

#uiNodeModal .ins-selector-buttons .btn {
  padding: 0 10px;
}

/* 查询结果条：三态各用语义色，不写死色值 */
#uiNodeModal .ins-test-result {
  margin-top: var(--space-2);
  padding: 5px 9px;
  font-size: var(--fs-secondary);
  line-height: 1.5;
  border: 1px solid var(--panel-border);
  border-radius: var(--radius-sm);
  word-break: break-all;
}

#uiNodeModal .ins-test-result.is-pending {
  color: var(--text-muted);
  background: var(--bg-hover);
  border-color: var(--panel-border-strong);
}

/* 命中/失败按规范 §4 徽标口径：-soft 底 + -text 字，边框用主语义色 */
#uiNodeModal .ins-test-result.is-ok {
  color: var(--success-text);
  background: var(--success-soft);
  border-color: var(--success);
}

#uiNodeModal .ins-test-result.is-error {
  color: var(--danger-text);
  background: var(--danger-soft);
  border-color: var(--danger);
}

/* 状态条件行：十项紧凑排布，窄屏自动降列。
   这一排是「同名控件怎么区分」的主要手段，和上面的字符串条件同等重要，所以同字号同高度。

   排版要点：每个条件是一个独立小卡片（标签在上、下拉在下）。
   原先是「标签 左 | 下拉 右」横向两列挤在 118px 里，相邻两组在视觉上
   连成「不限 可长按 不限」这样一串，读起来像是「不限可长按」这个值。
   改成上下两行 + 卡片底 + 明确的组间距后，每组边界一眼可辨。 */
#uiNodeModal .ins-state-row {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(104px, 1fr));
  gap: var(--space-2);
  margin-top: var(--space-2);
  padding-top: var(--space-2);
  border-top: 1px dashed var(--panel-border);
}

#uiNodeModal .ins-state-item {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: 3px;
  min-width: 0;
  padding: 5px 7px 6px;
  background: var(--bg-sunken);
  border: 1px solid var(--panel-border);
  border-radius: var(--radius-sm);
  transition: border-color 0.15s var(--ease-standard);
}

#uiNodeModal .ins-state-item:hover {
  border-color: var(--panel-border-strong);
}

#uiNodeModal .ins-state-item > span {
  font-family: var(--font-mono);
  font-size: var(--fs-micro);
  color: var(--text-muted);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  /* 标签独立成行，与下方下拉左对齐；不再和「不限」抢同一行 */
  line-height: 1.25;
}

#uiNodeModal .ins-state-select {
  width: 100%;
  padding: 3px 4px;
  font-family: var(--font-sans);
  font-size: var(--fs-caption);
  color: var(--text-main);
  background: var(--bg-input);
  border: 1px solid var(--panel-border);
  border-radius: var(--radius-sm);
  cursor: pointer;
}

#uiNodeModal .ins-state-select:hover {
  border-color: var(--panel-border-strong);
}

#uiNodeModal .ins-state-select:focus {
  outline: none;
  border-color: var(--primary);
  box-shadow: 0 0 0 3px var(--primary-ring);
}

/* 已选「是/否」的下拉高亮，一眼看出哪几项真的会发出去 */
#uiNodeModal .ins-state-item.is-set .ins-state-select {
  color: var(--primary-hover);
  border-color: var(--primary-ring);
}

/* 已设置的条件整体提亮，与「不限」的暗色卡片形成对比 */
#uiNodeModal .ins-state-item.is-set {
  background: var(--primary-soft);
  border-color: var(--primary-ring);
}

#uiNodeModal .ins-state-item.is-set > span {
  color: var(--text-main);
}

/* 写入参数行：动作 / 序号 / 超时 / 文本 / 方向，与当前动作无关的项压暗禁用 */
#uiNodeModal .ins-step-row {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: 6px var(--space-3);
  margin-top: var(--space-2);
  padding-top: var(--space-2);
  border-top: 1px dashed var(--panel-border);
}

#uiNodeModal .ins-step-item {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}

#uiNodeModal .ins-step-item > span {
  font-size: var(--fs-micro);
  color: var(--text-muted);
  white-space: nowrap;
}

#uiNodeModal .ins-step-item--grow {
  flex: 1 1 160px;
  min-width: 140px;
}

#uiNodeModal .ins-step-input {
  padding: 3px 6px;
  font-family: var(--font-mono);
  font-size: var(--fs-caption);
  color: var(--text-main);
  background: var(--bg-input);
  border: 1px solid var(--panel-border);
  border-radius: var(--radius-sm);
}

#uiNodeModal .ins-step-input:hover {
  border-color: var(--panel-border-strong);
}

#uiNodeModal .ins-step-item select.ins-step-input {
  font-family: var(--font-sans);
  cursor: pointer;
}

#uiNodeModal .ins-step-input:focus {
  outline: none;
  border-color: var(--primary);
  box-shadow: 0 0 0 3px var(--primary-ring);
}

#uiNodeModal .ins-step-item.is-off {
  opacity: 0.42;
}

#uiNodeModal .ins-step-item.is-off .ins-step-input {
  cursor: not-allowed;
}

/* 文档入口是 <a>，借用按钮外观时要抹掉链接默认样式 */
#uiNodeModal .ins-doc-link {
  text-decoration: none;
  height: 32px;
  padding: 0 12px;
  font-size: var(--font-size-xs);
}
/* ==================== 响应式 ==================== */

@media (max-width: 1180px) {
  #uiNodeModal .node-workspace {
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  }

  #uiNodeModal .node-props-col {
    display: none;
  }
}

@media (max-width: 900px) {
  #uiNodeModal .modal-panel--wide {
    width: 97vw;
    height: 94vh;
  }

  #uiNodeModal .node-workspace {
    grid-template-columns: minmax(0, 1fr);
    overflow: auto;
  }

  #uiNodeModal .node-preview {
    min-height: 42vh;
  }

  #uiNodeModal .node-tree-col {
    min-height: 32vh;
  }

  #uiNodeModal .node-toolbar {
    flex-wrap: wrap;
  }

  #uiNodeModal .ins-selector-panel {
    max-height: none;
  }

  #uiNodeModal .ins-selector-preview {
    flex-direction: column;
    gap: var(--space-2);
  }

  #uiNodeModal .ins-selector-json {
    max-width: none;
    max-height: 140px;
  }
}

@media (max-width: 560px) {
  #uiNodeModal .node-preview-actions {
    grid-template-columns: 1fr;
  }

  #uiNodeModal .ins-selector-fields {
    grid-template-columns: minmax(0, 1fr);
  }

  #uiNodeModal .ins-field {
    grid-template-columns: 13px 52px minmax(0, 1fr) 74px;
  }
}

/* ==================== 模式页签：控件节点 / 图色识别 ==================== */

/*
 * 页签放在工具条最左边：它是「这个面板现在干哪件事」的总开关，
 * 比搜索框更靠前的位置才符合阅读顺序。
 *
 * 视觉用分段控件（seg）而不是两个独立按钮：两者互斥，
 * 分段的连体外观本身就在表达「二选一」。
 */
#uiNodeModal .node-mode-tabs {
  display: inline-flex;
  flex: 0 0 auto;
  padding: 2px;
  gap: 2px;
  background: var(--bg-sunken);
  border: 1px solid var(--panel-border);
  border-radius: var(--radius-sm);
}

#uiNodeModal .node-mode-tab {
  appearance: none;
  border: 0;
  background: transparent;
  color: var(--text-muted);
  font-family: inherit;
  font-size: var(--font-size-xs);
  font-weight: 600;
  line-height: 1;
  padding: 6px 12px;
  border-radius: calc(var(--radius-sm) - 2px);
  cursor: pointer;
  transition: background var(--transition), color var(--transition);
  white-space: nowrap;
}

#uiNodeModal .node-mode-tab:hover {
  color: var(--text-main);
  background: var(--bg-hover);
}

#uiNodeModal .node-mode-tab.is-active {
  color: var(--text-on-primary);
  background: var(--primary);
}

#uiNodeModal .node-mode-tab:focus-visible {
  outline: none;
  box-shadow: var(--focus-ring);
}

/* 图色模式下搜索框无意义（它搜的是节点属性），隐藏但保留 DOM */
#uiNodeModal .node-toolbar.is-vision-mode #nodeSearchWrap,
#uiNodeModal .node-toolbar.is-vision-mode .node-inputtext,
#uiNodeModal .node-toolbar.is-vision-mode .node-toolbar-right {
  display: none;
}

/* ==================== 图色识别工作区 ==================== */

#uiNodeModal .node-vision {
  flex: 1 1 auto;
  min-height: 0;
  display: grid;
  /*
   * 截图列给大比例：图色的全部操作都发生在截图上（取色要看清像素、
   * 框选要贴边界），右侧只是数据展示。
   * 用 minmax(0, 1fr) 而不是固定宽度：面板可拖拽缩放，
   * 固定宽度在大屏上浪费、在小屏上会把截图挤没。
   */
  grid-template-columns: minmax(0, 1fr) 300px;
  gap: 1px;
  background: var(--panel-border);
  overflow: hidden;
}

/* ---- 左：截图舞台 ---- */
#uiNodeModal .node-vision-stage {
  display: flex;
  flex-direction: column;
  min-width: 0;
  min-height: 0;
  background: var(--bg-base);
}

#uiNodeModal .node-vision-bar {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  gap: var(--space-2);
  flex-wrap: wrap;
  padding: var(--space-2) var(--space-3);
  border-bottom: 1px solid var(--border-faint);
}

/* 取色 / 框选：与模式页签同一套分段控件语义，但尺寸小一档 */
#uiNodeModal .node-vision-modes {
  display: inline-flex;
  padding: 2px;
  gap: 2px;
  background: var(--bg-sunken);
  border: 1px solid var(--panel-border);
  border-radius: var(--radius-sm);
}

#uiNodeModal .node-vision-mode {
  appearance: none;
  border: 0;
  background: transparent;
  color: var(--text-muted);
  font-family: inherit;
  font-size: var(--font-size-xs);
  line-height: 1;
  padding: 5px 10px;
  border-radius: calc(var(--radius-sm) - 2px);
  cursor: pointer;
  transition: background var(--transition), color var(--transition);
}

#uiNodeModal .node-vision-mode:hover {
  color: var(--text-main);
  background: var(--bg-hover);
}

#uiNodeModal .node-vision-mode.is-active {
  color: var(--text-on-primary);
  background: var(--primary);
}

#uiNodeModal .node-vision-mode:focus-visible {
  outline: none;
  box-shadow: var(--focus-ring);
}

#uiNodeModal .node-vision-sep {
  width: 1px;
  height: 18px;
  background: var(--border-faint);
}

#uiNodeModal .node-vision-canvas {
  position: relative;
  flex: 1 1 auto;
  min-height: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--space-3);
  overflow: hidden;
}

/*
 * 截图：contain 适配容器。
 * 坐标换算必须按 naturalWidth / 显示尺寸的比例算（node-vision.js 里做），
 * 因为面板宽度会随用户拖动变化，写死比例一定会错位。
 */
#uiNodeModal .node-vision-shot {
  display: block;
  /*
   * 宽度优先：手机截图是竖长条（540×1170 ≈ 1:2.17），
   * 容器是横的。只写 max-width/max-height 时，浏览器会按**高度**先触顶
   * （容器高 640，图片就缩到 296 宽），于是截图又窄又小，
   * 取色时连按钮边界都看不清。
   *
   * 这里让宽度吃满容器、高度按比例溢出后由 max-height 兜住：
   * 面板够高时截图就宽；面板矮时仍然按高度收缩，不会溢出。
   */
  width: 100%;
  height: auto;
  max-width: 100%;
  max-height: 100%;
  object-fit: contain;
  user-select: none;
  -webkit-user-drag: none;
  cursor: crosshair;
  border-radius: var(--radius-sm);
}

#uiNodeModal .node-vision-shot.is-rect-mode {
  cursor: cell;
}

/* 框选矩形：绝对定位在容器内，坐标由 JS 按显示尺寸换算 */
#uiNodeModal .node-vision-sel {
  position: absolute;
  border: 1px solid var(--primary);
  background: var(--primary-soft);
  pointer-events: none;
  border-radius: 2px;
}

/*
 * 取消框选的 X：钉在框的右上角外侧。
 *
 * 父元素是 pointer-events:none（框本身不该挡住截图的取色点击），
 * 子元素显式设成 auto 才能接收点击 —— 这是 CSS 里唯一能让
 * 「装饰层整体穿透、只有按钮可点」的写法。
 *
 * 位置用 translate 往外挪半个按钮：框小的时候（比如只框住一个图标）
 * 按钮不会盖住框里的内容，也不会被框裁掉。
 */
#uiNodeModal .node-vision-sel-x {
  position: absolute;
  top: 0;
  right: 0;
  transform: translate(50%, -50%);
  pointer-events: auto;
  width: 20px;
  height: 20px;
  padding: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  border: 1px solid var(--primary);
  border-radius: var(--radius-pill);
  background: var(--bg-elevated);
  color: var(--primary);
  font-size: 14px;
  font-weight: 700;
  line-height: 1;
  cursor: pointer;
  box-shadow: var(--shadow-lg);
  transition: background var(--transition), color var(--transition);
}

#uiNodeModal .node-vision-sel-x:hover {
  background: var(--primary);
  color: var(--text-on-primary);
}

#uiNodeModal .node-vision-sel-x:focus-visible {
  /* --focus-ring 是 box-shadow 公式（不是颜色），直接拿来当 outline 会失效 */
  outline: 2px solid var(--primary);
  outline-offset: 1px;
}

#uiNodeModal .node-vision-marks {
  position: absolute;
  inset: 0;
  pointer-events: none;
}

/* 命中标记：圆点 + 序号，颜色用主色，避免与截图像素混淆 */
#uiNodeModal .node-vision-mark {
  position: absolute;
  min-width: 16px;
  height: 16px;
  padding: 0 3px;
  transform: translate(-50%, -50%);
  border-radius: var(--radius-pill);
  background: var(--primary);
  color: var(--text-on-primary);
  font-size: 10px;
  font-weight: 700;
  line-height: 16px;
  text-align: center;
  box-shadow: var(--shadow-lg);
}

/* 找图命中的方框：比圆点更能表达「这块区域」 */
#uiNodeModal .node-vision-mark-box {
  position: absolute;
  border: 2px solid var(--primary);
  border-radius: 3px;
  background: var(--primary-soft);
}

#uiNodeModal .node-vision-empty {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--text-muted);
  font-size: var(--font-size-sm);
  text-align: center;
  padding: var(--space-5);
}

#uiNodeModal .node-vision-empty.hidden {
  display: none;
}

#uiNodeModal .node-vision-foot {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  padding: 6px var(--space-3);
  border-top: 1px solid var(--border-faint);
  font-family: var(--font-mono);
  font-size: var(--font-size-xs);
  color: var(--text-muted);
}

#uiNodeModal .node-vision-selinfo {
  color: var(--primary);
}

/* ---- 右：数据列 ---- */
#uiNodeModal .node-vision-side {
  display: flex;
  flex-direction: column;
  min-width: 0;
  min-height: 0;
  overflow-y: auto;
  background: var(--bg-base);
  padding: var(--space-3);
  gap: var(--space-3);
}

#uiNodeModal .node-vision-sec {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  padding-bottom: var(--space-3);
  border-bottom: 1px solid var(--border-faint);
}

#uiNodeModal .node-vision-sec:last-of-type {
  border-bottom: 0;
}

/* 识别结果这一段吃掉剩余高度：它内容最多，用户最需要空间看 */
#uiNodeModal .node-vision-sec--grow {
  flex: 1 1 auto;
  min-height: 120px;
}

#uiNodeModal .node-vision-sec-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2);
  font-size: var(--fs-micro);
  font-weight: 600;
  letter-spacing: var(--ls-micro);
  text-transform: uppercase;
  color: var(--text-muted);
}

#uiNodeModal .node-vision-region {
  padding: var(--space-2);
  background: var(--bg-sunken);
  border: 1px solid var(--panel-border);
  border-radius: var(--radius-sm);
  font-size: var(--font-size-xs);
  line-height: 1.6;
  color: var(--text-regular);
  white-space: pre-wrap;
  word-break: break-word;
}

#uiNodeModal .node-vision-region.is-empty {
  color: var(--text-dim);
}

#uiNodeModal .node-vision-row {
  display: flex;
  align-items: center;
  gap: var(--space-2);
}

#uiNodeModal .node-vision-row .form-input {
  flex: 1 1 auto;
  min-width: 0;
}

#uiNodeModal .node-vision-tol {
  display: flex;
  align-items: center;
  gap: 4px;
  font-size: var(--font-size-xs);
  color: var(--text-muted);
  flex: 0 0 auto;
}

#uiNodeModal .node-vision-tol .form-input {
  width: 56px;
  flex: 0 0 auto;
}

/* 取色列表：一行一个色块，点击复制 */
#uiNodeModal .node-vision-colors {
  display: flex;
  flex-direction: column;
  gap: 4px;
  max-height: 150px;
  overflow-y: auto;
}

#uiNodeModal .node-vision-color {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding: 4px 6px;
  background: var(--bg-sunken);
  border: 1px solid var(--panel-border);
  border-radius: var(--radius-sm);
  cursor: pointer;
  font-family: var(--font-mono);
  font-size: var(--font-size-xs);
  color: var(--text-regular);
  transition: border-color var(--transition), background var(--transition);
  text-align: left;
}

#uiNodeModal .node-vision-color:hover {
  border-color: var(--panel-border-strong);
  background: var(--bg-hover);
}

#uiNodeModal .node-vision-color.is-active {
  border-color: var(--primary);
  background: var(--primary-soft);
}


#uiNodeModal .node-vision-dot {
  flex: 0 0 auto;
  width: 14px;
  height: 14px;
  border-radius: 3px;
  border: 1px solid var(--panel-border-strong);
}

#uiNodeModal .node-vision-color-pos {
  margin-left: auto;
  color: var(--text-dim);
}

#uiNodeModal .node-vision-compare {
  font-size: var(--font-size-xs);
  color: var(--text-muted);
  font-family: var(--font-mono);
}

/* 模板库 */
#uiNodeModal .node-vision-tpls {
  display: flex;
  flex-direction: column;
  gap: 4px;
  max-height: 132px;
  overflow-y: auto;
}

#uiNodeModal .node-vision-tpl {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding: 4px 6px;
  background: var(--bg-sunken);
  border: 1px solid var(--panel-border);
  border-radius: var(--radius-sm);
  font-size: var(--font-size-xs);
  color: var(--text-regular);
}

#uiNodeModal .node-vision-tpl.is-active {
  border-color: var(--primary);
  background: var(--primary-soft);
}

#uiNodeModal .node-vision-tpl-name {
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-family: var(--font-mono);
}

#uiNodeModal .node-vision-tpl button {
  flex: 0 0 auto;
}

/* 结果区：等宽字体 + 可滚。OCR 与找色结果都是坐标密集的文本 */
#uiNodeModal .node-vision-result {
  flex: 1 1 auto;
  min-height: 100px;
  padding: var(--space-2);
  background: var(--bg-sunken);
  border: 1px solid var(--panel-border);
  border-radius: var(--radius-sm);
  font-family: var(--font-mono);
  font-size: var(--font-size-xs);
  line-height: 1.6;
  color: var(--text-regular);
  white-space: pre-wrap;
  word-break: break-word;
  overflow-y: auto;
}

#uiNodeModal .node-vision-result.is-empty {
  color: var(--text-dim);
}

#uiNodeModal .node-vision-result.is-err {
  color: var(--danger-text);
}

#uiNodeModal .node-vision-engine {
  font-size: var(--font-size-xs);
  font-weight: 400;
  letter-spacing: 0;
  text-transform: none;
  color: var(--text-dim);
}

#uiNodeModal .node-vision-actions {
  flex: 0 0 auto;
  display: flex;
  gap: var(--space-2);
  padding-top: var(--space-2);
}

#uiNodeModal .node-vision-actions .btn {
  flex: 1 1 0;
}

/* 图色模式下节点专属区块整体隐藏（选择器构造 / 原始 JSON） */
#uiNodeModal.is-vision-mode #insSelectorPanel {
  display: none !important;
}

@media (max-width: 1180px) {
  #uiNodeModal .node-vision {
    grid-template-columns: minmax(0, 1fr) 300px;
  }
}

@media (max-width: 900px) {
  #uiNodeModal .node-vision {
    grid-template-columns: minmax(0, 1fr);
    overflow-y: auto;
  }

  #uiNodeModal .node-vision-canvas {
    min-height: 40vh;
  }

  #uiNodeModal .node-vision-side {
    overflow: visible;
  }
}
