/* ============================================================================
   app-ui.css — 上岸脚控运营后台 · 「仪器面板」全站视觉覆盖层
   ----------------------------------------------------------------------------
   加载顺序（线上最后一个 <link>）：
     index.css → ui-patch.css → devices-ui.css → sidebar-ui.css →
     serverstatus-ui.css → login-ui.css → app-ui.css

   作用域策略（为什么这样写，不是随手加前缀）：
   1. 只写 main 里的内容。侧栏 [data-slot=sidebar*]、登录页、服务器状态页由
      别的产出负责；body 背景由 render 内联样式给出。所以每条规则都以 main
      开头，天然不碰侧栏，也不需要和 sidebar-ui.css 抢 !important。
   2. 特异性一律"高半档"，不加无意义的 !important：
      Tailwind 工具类是 0,1,0（.h-8 / .bg-[#21262d]），所以本层用
      main + 元素/属性（0,1,2 或 0,2,x）就赢；hover 态是对手的 0,2,0，
      本层写 main X:hover 即 0,2,x。全部按"后加载 + 同特异性"取胜。
      !important 只用在对手已经 !important 的地方，逐条注明文件名与行号。
   3. 不用 @layer：既有覆盖层都在层外，进层会被整体压掉（SPEC 5.6）。
   4. 品牌红（index.css 的 --primary / --ring / --chart-1 / --sidebar-*）
      在本文件里一次都不作为颜色出现。本层在 main 上重绑
      --primary→--accent-dim、--ring→--accent，再用显式按钮分级覆盖
      "红底按钮"，使开关、主按钮、focus 环全部离开品牌红。
      未重绑 --sidebar-*：侧栏不在本任务范围。

   色值只取自 SPEC 第 3 节四张表（中性阶 / 交互色 / 语义区间 / 身份色带）。
   字号只用 11 / 12 / 13 / 16 / 20，行高 1.45，数字 tabular-nums。
   圆角只用 2 / 4 / 6 / 8。过渡 ≤160ms，只过渡颜色/透明度/位移。
   无渐变、无毛玻璃、无投影、无循环动画（本任务明令禁止，这里只做状态过渡）。

   Do
     · 一张描边 + 内部 1px 发丝格：分组靠线，不靠圆角堆叠和投影
     · 正常 = 亮度差：进度条/启用/在线默认灰阶，彩色只在异常与语义处出现
     · 数字 20px、单位 11px 灰、表头 11px 大写字距、正文 13px
   Don't
     · 胶囊圆角 / 渐变 / 毛玻璃 / 循环动画 / 全属性过渡
     · 用 overflow 藏排版缺陷（表头 nowrap 后仍装不下的表格才允许容器内横滚）
     · 修改任何既有 CSS 文件、DOM、class、data-*
   ========================================================================== */

/* ------------------------------------------------- 1b. 圆角工具类归位到四档 */
/* 编译产物里的 rounded-lg / rounded-xl 在本项目分别算到 10px / 14px，
   不在 2/4/6/8 四档内。这里按"工具类 → token"的方式整批收口，不逐个找元素。 */
main .rounded-lg:not(.zqpreviewcol *),
main .rounded-xl:not(.zqpreviewcol *),
main .rounded-2xl:not(.zqpreviewcol *),
main .rounded-3xl:not(.zqpreviewcol *),
main [class*="rounded-[10px]"]:not(.zqpreviewcol *),
main [class*="rounded-[12px]"]:not(.zqpreviewcol *) {
  border-radius: var(--r8);
}

main .rounded-md:not(.zqpreviewcol *),
main .rounded:not(.zqpreviewcol *) {
  border-radius: var(--r6);
}

/* 胶囊 chip（"已停止 / 已完成"这类带点的状态块）：胶囊 → 4px 方角 */
main span[class*="rounded-full"][class*="px-2"]:not(.zqpreviewcol *) {
  border-radius: var(--r4);
}

/* 悬停提示块（group/tip）：同色系面板 + 6px 圆角，去掉投影 */
main [class*="group-hover/tip"] {
  border: 1px solid var(--line);
  border-radius: var(--r6);
  background: var(--surface2);
  color: var(--text);
  font-size: 11px;
  box-shadow: none;
}

/* ---------------------------------------------------------------- 0. token */
main {
  /* 3.1 中性阶 —— 唯一底色系统 */
  --canvas: #0d1117;
  --surface: #161b22;
  --surface2: #1c2128;
  --line: #30363d;
  --line-sub: #21262d;
  --text: #e6edf3;
  --body: #c9d1d9;
  --muted: #8b949e;
  --faint: #6e7681;
  --ghost: #484f58;

  /* 3.2 交互色 —— 可操作物的唯一颜色 */
  --accent: #58a6ff;
  --accent-hi: #79c0ff;
  --accent-dim: #1f6feb;
  --accent-bg: rgba(88, 166, 255, .10);
  --accent-line: rgba(88, 166, 255, .40);

  /* 3.3 语义区间 —— 红在这里降级为纯错误色 */
  --ok: #3fb950;
  --ok-bg: rgba(63, 185, 80, .10);
  --ok-line: rgba(63, 185, 80, .35);
  --warn: #d29922;
  --warn-bg: rgba(210, 153, 34, .10);
  --warn-line: rgba(210, 153, 34, .35);
  --danger: #f85149;
  --danger-bg: rgba(248, 81, 73, .10);
  --danger-line: rgba(248, 81, 73, .35);
  --info: #58a6ff;
  --info-bg: rgba(88, 166, 255, .10);
  --info-line: rgba(88, 166, 255, .35);

  /* 3.4 设备身份色带（6 色轮转，只做 2px 条/描边） */
  --id-1: #58a6ff;
  --id-2: #3fb950;
  --id-3: #d29922;
  --id-4: #bc8cff;
  --id-5: #39c5cf;
  --id-6: #f0883e;

  /* 节奏 */
  --r2: 2px;
  --r4: 4px;
  --r6: 6px;
  --r8: 8px;
  --dur: 120ms;
  --ease: cubic-bezier(.22, 1, .36, 1);

  /* ---- shadcn 变量重绑（只作用于 main，不污染侧栏/登录页） ----
     对手：index.css 的 :root 把 --primary / --ring / --chart-1 都绑在品牌红上
     --primary 驱动开关开态 (bg-primary) 与红底主按钮；--ring 驱动 focus 环。
     绑到 accent-dim / accent 之后，品牌红在 main 内彻底消失。 */
  --primary: #1f6feb;
  --primary-foreground: #e6edf3;
  --ring: #58a6ff;
  --chart-1: #58a6ff;
  --chart-2: #d29922;
  --chart-3: #3fb950;
  --chart-4: #58a6ff;
  --chart-5: #bc8cff;
  /* --accent 在 index.css 里是橙色 #f0883e，被 hover:bg-accent 当"悬停底色"用。
     重绑为交互蓝后，下面的 hover 规则再用 surface2 覆盖掉那层蓝底。 */
  --accent: #58a6ff;
  --accent-foreground: #e6edf3;
}

/* ------------------------------------------------------------------ 1. 版式 */
main {
  font-family: ui-sans-serif, system-ui, -apple-system, "Segoe UI", "PingFang SC",
    "Microsoft YaHei", sans-serif;
  font-size: 13px;
  line-height: 1.45;
  color: var(--body);
  -webkit-font-smoothing: antialiased;
  /* 全页数字等宽：金额、计数、时间、百分比全部对齐 */
  font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum" 1;
}

/* 字号阶梯回收：Tailwind 的 14/15/16 与散落的 text-[15px] 一律落到 13/11。
   :not(.zqpreviewcol *) 保护 APK 构建页里的「手机屏幕预览」——那是被缩放到
   0.26 的内容截图（安卓浅色界面），属于数据而不是界面本体，改字号会破坏预览。 */
main .text-sm:not(.zqpreviewcol *),
main .text-base:not(.zqpreviewcol *),
main .text-lg:not(.zqpreviewcol *),
main [class*="text-[15px]"]:not(.zqpreviewcol *),
main [class*="text-[14px]"]:not(.zqpreviewcol *),
main [class*="text-[13px]"]:not(.zqpreviewcol *) {
  font-size: 13px;
}

main .text-xs:not(.zqpreviewcol *),
main [class*="text-[12px]"]:not(.zqpreviewcol *),
main [class*="text-[11px]"]:not(.zqpreviewcol *),
main [class*="text-[10px]"]:not(.zqpreviewcol *),
main [class*="text-[9px]"]:not(.zqpreviewcol *) {
  font-size: 11px;
}

/* 标题：页名 16，卡名 13 —— 面板里没有 24px 的大字 */
main h1[class]:not(.zqpreviewcol *),
main .text-2xl:not(.zqpreviewcol *) {
  font-size: 16px;
  font-weight: 600;
  line-height: 1.45;
  letter-spacing: .01em;
  color: var(--text);
}

main .text-xl:not(.zqpreviewcol *),
main [class*="text-[17px]"]:not(.zqpreviewcol *),
main [class*="text-[18px]"]:not(.zqpreviewcol *) {
  font-size: 16px;
}

main h2[class],
main h3[class],
main [data-slot="card-title"] {
  font-size: 13px;
  font-weight: 600;
  line-height: 1.45;
  letter-spacing: .01em;
  color: var(--text);
}

main .font-bold:not(.zqpreviewcol *),
main strong[class] {
  font-weight: 600;
}

/* 语义文字色：把散落的 Tailwind 命名色收进四档语义区间。
   红色只剩 danger 一档（失败/过期/封禁/删除确认）。 */
main .text-red-400,
main .text-red-300,
main .text-red-500 {
  color: var(--danger);
}
main .text-orange-400, main .text-orange-300,
main .text-amber-300, main .text-amber-400, main .text-yellow-400 {
  color: var(--warn);
}
main .text-green-400, main .text-green-300, main .text-emerald-400 { color: var(--ok); }
main .text-blue-400,
main .text-blue-300,
main .text-blue-500 {
  color: var(--accent);
}
main .text-cyan-400, main .text-teal-400,
main .text-purple-400, main .text-purple-300 { color: var(--info); }
main .text-gray-400, main .text-slate-400 { color: var(--faint); }
main .text-white { color: var(--text); }

/* ------------------------------------------------------------------ 2. 顶栏 */
/* 高 48px、控件统一 30px、gap 8：汇率/时区/双时钟先收进一条 surface2 长条 */
main > header {
  height: 48px;
  min-height: 48px;
  padding: 0 16px;
  gap: 8px;
  border-bottom: 1px solid var(--line-sub);
  background: var(--canvas);
}

main > header :is(button, input, [data-slot="select-trigger"]) {
  height: 30px;
  min-height: 30px;
  border-radius: var(--r6);
}

main > header button[class] {
  padding: 0 8px;
  font-size: 11px;
  color: var(--muted);
  background: transparent;
  border: 1px solid transparent;
}

main > header button[class]:hover {
  color: var(--text);
  background: var(--surface2);
}

/* 汇率换算条：整条一个 surface2 底 + 1px 描边，内部控件全部透明 */
main > header div[class*="justify-end"] > div {
  height: 34px;
  padding: 0 6px;
  gap: 6px;
  border: 1px solid var(--line);
  border-radius: var(--r6);
  background: var(--surface2);
}

main > header div[class*="justify-end"] > div button[class] {
  height: 30px;
  padding: 0 6px;
  background: transparent;
  border-color: transparent;
  color: var(--text);
  font-size: 11px;
}

main > header div[class*="justify-end"] > div button[class]:hover {
  background: var(--line);
  color: var(--text);
}

main > header div[class*="justify-end"] > div input[class] {
  width: 88px;
  height: 26px;
  min-height: 26px;
  background: var(--canvas);
  border-color: var(--line);
  text-align: right;
  font-size: 12px;
}

/* 「=」与时钟：等号降成 --faint，时间给 12px 等宽 */
main > header div[class*="justify-end"] > div > span {
  font-size: 11px;
  color: var(--faint);
  white-space: nowrap;
}

main > header div[class*="justify-end"] > div > span > span,
main > header div[class*="justify-end"] > div > span .text-\[e6edf3\] {
  font-size: 12px;
  color: var(--text);
}

/* 顶栏的分隔竖线（div.bg-[#30363d] 1px）压到 line-sub */
main > header div[class*="bg-[#30363d]"] {
  height: 14px;
  background: var(--line);
}

/* 换算条里的输入框：焦点必须可见。上面那条 (0,2,4) 的描边规则会盖掉
   通用 :focus 的 accent 描边，这里同结构补一条 focus。 */
main > header div[class*="justify-end"] > div input[class]:focus {
  border-color: var(--accent);
  box-shadow: 0 0 0 2px var(--accent-bg);
}

/* 头像：胶囊 → 6px 方角瓦片；缺图时也是块瓦片而不是碎图标 */
main > header span[data-slot="avatar"] {
  width: 30px;
  height: 30px;
  border-radius: var(--r6);
  background: var(--surface2);
  border: 1px solid var(--line);
  overflow: hidden;
}

main > header span[data-slot="avatar"] img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

main > header [data-slot="dropdown-menu-trigger"] {
  width: 30px;
  height: 30px;
  padding: 0;
  border-radius: var(--r6);
  background: transparent;
}

main > header [data-slot="dropdown-menu-trigger"]:hover { background: var(--surface2); }

/* 面包屑：13px，末级亮、分隔线静音 */
main > header [data-slot="breadcrumb-list"] {
  gap: 6px;
  font-size: 13px;
}

main > header [data-slot="breadcrumb-page"] { color: var(--text); font-weight: 500; }

main > header [data-slot="separator-root"] {
  width: 1px;
  height: 14px;
  margin-right: 6px;
  background: var(--line);
}

/* --------------------------------------------------------------- 3. 卡片/面板 */
main [data-slot="card"] {
  border: 1px solid var(--line);
  border-radius: var(--r8);
  background: var(--surface);
  box-shadow: none;
  padding: 0;
  gap: 0;
  min-width: 0;
}

main [data-slot="card-header"] {
  display: flex;
  align-items: center;
  height: 40px;
  min-height: 40px;
  padding: 0 12px;
  gap: 6px;
  border-bottom: 1px solid var(--line-sub);
}

main [data-slot="card-content"] {
  padding: 12px;
  min-width: 0;
}

/* 无 card-header 的卡片（strategy / sms / inject / notifications / injdata）：
   标题行写在 card-content 里，给它补一条发丝线，让"卡片头"在视觉上成立。
   只在标题行是内容区第一个子元素时生效，避免误伤表单行。 */
main [data-slot="card-content"] > div > div[class*="justify-between"]:first-child {
  padding-bottom: 8px;
  border-bottom: 1px solid var(--line-sub);
  margin-bottom: 2px;
}

main [data-slot="card-content"] > div > div[class*="justify-between"]:first-child > div:first-child {
  min-width: 0;
}

/* 卡内「一串图标按钮」的组（users 的用户行 5 个操作钮）：允许换行。
   1280 视口下卡片只有 ~279px，5×30+间距 装不下；换行比把按钮推出卡片外好。 */
main [data-slot="card-content"] div[class*="items-center"][class*="gap-1"] {
  flex-wrap: wrap;
  min-width: 0;
}

/* 标题不换行：strategy 三栏里「全局敏感App」被按钮挤成两行的问题在这里收口。
   标题块允许收缩，按钮块不许收缩，两者用 8px gap 分开。 */
main [data-slot="card-title"],
main [data-slot="card-title"] span,
main h2[class],
main h3[class] {
  white-space: nowrap;
}

/* 面板内"盒中盒"：卡内一票 rounded-lg + bg-[#0d1117] + border 的行块，
   在仪器面板里应是一张发丝格里的行，不是又一圈描边盒子。 */
main [data-slot="card-content"] div[class*="rounded-lg"][class*="bg-[#0d1117]"][class*="border"],
main [data-slot="card-content"] div[class*="rounded-lg"][class*="border"][class*="bg-transparent"]:not(:has([data-slot="card"])),
main [data-slot="card-content"] div[class*="rounded-lg"][class*="border-[#30363d]"]:not(:has([data-slot="card"])) {
  border-radius: 0;
  border-color: transparent;
  background: transparent;
}

/* 行块之间用 1px 发丝分隔（原先是靠盒子间距，改线之后靠线） */
main [data-slot="card-content"] div[class*="rounded-lg"] + div[class*="rounded-lg"] {
  border-top: 1px solid var(--line-sub);
}

/* 卡片内的小标题（"绑定状态""AI 服务"这类 label）统一 11px 灰字 */
main [data-slot="card-content"] label[class],
main [data-slot="card-content"] p[class*="text-[#8b949e]"][class*="text-xs"] {
  font-size: 11px;
  letter-spacing: .02em;
  color: var(--muted);
}

/* ---------------------------------------------------------------- 4. 按钮 */
/* 四档 + icon：高度 30、圆角 6、13px/500、120ms。
   "红底按钮"（index.css 里 --primary 为品牌红的 .bg-primary）全部降级：
   本层把它做成 primary（白底黑字，SPEC 4.4）；删除类由 bg-red-500/10 单独走 danger。 */
main button[class],
main [data-slot="button"] {
  /* 只写 height，不写 min-height：设备页/构建页的高度由既有覆盖层的
     !important 定（devices-ui.css:191 的 28px 等），min-height 会把它们顶高。 */
  height: 30px;
  padding: 0 10px;
  gap: 6px;
  border: 1px solid transparent;
  border-radius: var(--r6);
  background: transparent;
  color: var(--muted);
  font-size: 13px;
  font-weight: 500;
  line-height: 1;
  white-space: nowrap;
  box-shadow: none;
  transition: background-color var(--dur) var(--ease),
    border-color var(--dur) var(--ease), color var(--dur) var(--ease);
}

main button[class] svg {
  width: 14px;
  height: 14px;
  flex: 0 0 auto;
}

/* primary：白底黑字（红底主按钮的归宿） */
main [data-slot="button"][class*="bg-primary"],
main button[class*="w-[40px]"].bg-primary {
  background: var(--text);
  color: var(--canvas);
  border-color: transparent;
}

main [data-slot="button"][class*="bg-primary"]:hover {
  background: #ffffff;
  color: var(--canvas);
}

main [data-slot="button"][class*="bg-primary"]:active {
  background: var(--body);
}

/* danger：删除 / 清空 / 封禁 / 移除（透明底 + danger 描边） */
main [data-slot="button"][class*="bg-red-500/10"],
main button[class*="bg-red-500/10"] {
  background: transparent;
  border-color: var(--danger-line);
  color: var(--danger);
}

main [data-slot="button"][class*="bg-red-500/10"]:hover,
main button[class*="bg-red-500/10"]:hover {
  background: var(--danger-bg);
  border-color: var(--danger-line);
  color: var(--danger);
}

/* danger icon：表格行里的纯图标删除钮（hover:bg-red-500/20 那一类） */
main button[class*="hover:bg-red-500"]:not([class*="bg-red-500/10"]) {
  background: transparent;
  border-color: transparent;
  color: var(--danger);
}

main button[class*="hover:bg-red-500"]:not([class*="bg-red-500/10"]):hover {
  background: var(--danger-bg);
  color: var(--danger);
}

/* secondary：面底 + 描边（"添加 / 编辑 / 刷新 / 下载 / 复制"这类） */
main [data-slot="button"][class*="bg-[#21262d]"],
main [data-slot="button"][class*="border-[#30363d]"]:not([class*="bg-red-500"]),
main button[class*="bg-transparent"][class*="border-input"] {
  background: var(--surface2);
  border-color: var(--line);
  color: var(--text);
}

main [data-slot="button"][class*="bg-[#21262d]"]:hover,
main [data-slot="button"][class*="border-[#30363d]"]:not([class*="bg-red-500"]):hover,
main button[class*="bg-transparent"][class*="border-input"]:hover {
  background: var(--line);
  border-color: var(--line);
  color: var(--text);
}

/* icon：方形图标钮（h-7/h-8/h-9/size-9 且没底色的），只换字色与 hover 底 */
main button[class*="size-9"]:not([class*="bg-"]),
main button[class*="h-8"][class*="w-8"]:not([class*="bg-"]),
main button[class*="h-7"][class*="w-7"]:not([class*="bg-"]),
main [data-slot="tooltip-trigger"] {
  width: 30px;
  min-width: 30px;
  height: 30px;
  padding: 0;
  border-radius: var(--r6);
  background: transparent;
  border-color: transparent;
  color: var(--muted);
}

main button[class*="size-9"]:not([class*="bg-"]):hover,
main button[class*="h-8"][class*="w-8"]:not([class*="bg-"]):hover,
main button[class*="h-7"][class*="w-7"]:not([class*="bg-"]):hover,
main [data-slot="tooltip-trigger"]:hover {
  background: var(--surface2);
  color: var(--text);
}

/* 通用 hover：被 index.css 的 hover:bg-accent（橙底）拦下的那些按钮，
   统一改成 surface2 的静音底，不再出现橙色 wash */
main button[class*="hover:bg-accent"]:hover,
main [data-slot="dropdown-menu-trigger"]:hover {
  background: var(--surface2);
  color: var(--text);
}

/* 按下要有回弹感：位移 1px，不复用 0.3s 的匀速 */
main button[class]:active { transform: translateY(.5px); }

main button[class]:disabled,
main button[class][disabled],
main button[class][aria-disabled="true"] {
  opacity: .4;
  cursor: not-allowed;
  transform: none;
}

/* 键盘焦点：全站统一的 accent 环（.outline-none 会把默认描边吃掉） */
main :is(button, input, select, textarea, a, [role="switch"], [role="tab"]):focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

/* ---------------------------------------------------------------- 5. 开关 */
/* 47 (strategy) + 50 (inject) 个 Bootstrap 红药丸 → 34×18 直角灰/蓝拨片。
   对手：index.css 的 data-[state=checked]:bg-primary（--primary 已被重绑为
   #1f6feb），以及 rounded-full / h-[1.15rem] / w-8 / border-transparent。 */
/* 选择器带 [data-state]/[aria-checked] 是有意的：这两个属性让本规则达到
   (0,2,1)，压过 index.css 的 data-[state=unchecked]:bg-input（0,2,0）与
   main button[class]（0,1,2）。少了属性，高度会被通用按钮规则改成 30。 */
main [role="switch"][data-state],
main [role="switch"][aria-checked] {
  position: relative;
  display: inline-flex;
  flex-direction: row;
  align-items: center;
  flex: 0 0 auto;
  width: 34px;
  min-width: 34px;
  max-width: 34px;
  height: 18px;
  min-height: 18px;
  padding: 2px;
  border: 1px solid var(--line);
  border-radius: var(--r2);
  background-color: var(--surface2);
  box-shadow: none;
  cursor: pointer;
  transition: background-color var(--dur) var(--ease),
    border-color var(--dur) var(--ease);
}

main [role="switch"] > span[data-slot="switch-thumb"],
main [role="switch"] > span[class][data-state],
main [role="switch"] > span[class] {
  display: block;
  flex: 0 0 auto;
  width: 12px;
  height: 12px;
  min-width: 12px;
  border-radius: var(--r2);
  background-color: var(--faint);
  box-shadow: none;
  /* Tailwind v4 的 translate-x-* 走的是独立的 translate 属性，和 transform
     不是同一条通道（两个都会生效，滑块会被推两次 → 溢出轨道）。
     这里把 translate 归零，位移只由 transform 给。 */
  translate: none;
  transform: translateX(0);
  transition: transform var(--dur) var(--ease),
    background-color var(--dur) var(--ease);
}

main [role="switch"][data-state="checked"],
main [role="switch"][aria-checked="true"] {
  background-color: var(--accent-dim);
  border-color: transparent;
}

main [role="switch"][data-state="checked"] > span[data-slot="switch-thumb"],
main [role="switch"][aria-checked="true"] > span[data-slot="switch-thumb"],
main [role="switch"][data-state="checked"] > span[class],
main [role="switch"][aria-checked="true"] > span[class] {
  background-color: var(--text);
  translate: none;
  transform: translateX(16px);
}

/* 悬停：关态提一档亮度，开态提到 accent（不是发光，只是色阶） */
main [role="switch"][data-state="unchecked"]:hover,
main [role="switch"][aria-checked="false"]:hover {
  background-color: var(--line-sub);
  border-color: var(--line);
}

main [role="switch"][data-state="checked"]:hover,
main [role="switch"][aria-checked="true"]:hover {
  background-color: var(--accent);
  border-color: transparent;
}

main [role="switch"]:disabled,
main [role="switch"][disabled] {
  opacity: .4;
  cursor: not-allowed;
}

/* 页面里 5 个自绘胶囊开关（users 40×22、builds 32×18）：同一套直角语言。
   它们没有 role="switch"，靠 class 签名认出来；开态由 React 换成 bg-primary。 */
main button[class*="w-[40px]"][class*="h-[22px]"],
main button[class*="w-[32px]"][class*="h-[18px]"] {
  border: 1px solid var(--line);
  border-radius: var(--r2);
  background-color: var(--surface2);
  height: 20px;
  min-height: 20px;
  padding: 0;
  transition: background-color var(--dur) var(--ease),
    border-color var(--dur) var(--ease);
}

main button[class*="w-[40px]"][class*="h-[22px]"] > span,
main button[class*="w-[32px]"][class*="h-[18px]"] > span {
  width: 14px;
  height: 14px;
  border-radius: var(--r2);
  background-color: var(--faint);
  transition: transform var(--dur) var(--ease),
    background-color var(--dur) var(--ease);
}

main button[class*="w-[40px]"][class*="bg-primary"],
main button[class*="w-[32px]"][class*="bg-primary"] {
  background-color: var(--accent-dim);
  border-color: transparent;
}

main button[class*="w-[40px]"][class*="bg-primary"] > span,
main button[class*="w-[32px]"][class*="bg-primary"] > span {
  background-color: var(--text);
}

/* ------------------------------------------------------- 6. 滑块 / 复选 / 单选 */
/* 页面里目前没有 range，按 SPEC 4.2 先备好，将来出现即为同一套语言 */
main input[type="range"] {
  -webkit-appearance: none;
  appearance: none;
  width: 100%;
  height: 4px;
  border: 1px solid var(--line);
  border-radius: var(--r2);
  background: var(--surface2);
  cursor: pointer;
}

main input[type="range"]::-webkit-slider-thumb {
  -webkit-appearance: none;
  appearance: none;
  width: 12px;
  height: 12px;
  border: 0;
  border-radius: 50%;
  background: var(--text);
  cursor: pointer;
}

main input[type="range"]:focus-visible { outline: 2px solid var(--accent); }

main input[type="checkbox"],
main input[type="radio"] {
  -webkit-appearance: none;
  appearance: none;
  width: 12px;
  height: 12px;
  margin: 0;
  border: 1px solid var(--line);
  border-radius: var(--r2);
  background: var(--surface2);
  cursor: pointer;
  transition: background-color var(--dur) var(--ease),
    border-color var(--dur) var(--ease);
}

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

main input[type="checkbox"]:checked,
main input[type="radio"]:checked {
  background: var(--accent-dim);
  border-color: var(--accent-dim);
}

/* 对勾用两条线段画，不引图标字体 */
main input[type="checkbox"]:checked::after {
  content: "";
  display: block;
  width: 6px;
  height: 3px;
  margin: 1px 0 0 2px;
  border-left: 1.5px solid var(--text);
  border-bottom: 1.5px solid var(--text);
  transform: rotate(-45deg);
}

main input[type="radio"]:checked::after {
  content: "";
  display: block;
  width: 4px;
  height: 4px;
  margin: 3px;
  border-radius: 50%;
  background: var(--text);
}

/* 设备卡上的选择方块（role=checkbox 的 40×40 按钮）：
   位置尺寸沿用 devices-ui.css，只把底色和圆角收进本体系 */
main button[role="checkbox"] {
  background: var(--surface2);
  border-color: var(--line);
  border-radius: var(--r8);
  transition: border-color var(--dur) var(--ease),
    background-color var(--dur) var(--ease);
}

main button[role="checkbox"][aria-checked="true"] {
  border-color: var(--accent-line);
  background: var(--accent-bg);
}

/* ------------------------------------------------------ 7. 输入 / 下拉 / 文本域 */
main input[class]:not([type="checkbox"]):not([type="radio"]):not([type="range"]),
main select[class],
main textarea[class] {
  /* 高度单独一条（见下）—— 设备页要把高度交还给 devices-ui.css，
     所以这里不能把 height 写进通用规则里，否则得靠更高特异性去撤 */
  padding: 0 8px;
  border: 1px solid var(--line);
  border-radius: var(--r6);
  background: var(--surface2);
  color: var(--text);
  font-family: inherit;
  font-size: 13px;
  line-height: 1.45;
  box-shadow: none;
  transition: border-color var(--dur) var(--ease),
    box-shadow var(--dur) var(--ease), background-color var(--dur) var(--ease);
}

/* 控件高度 30 只在非设备页生效；设备页的输入框高度由 devices-ui.css 定 */
main:not(:has(.zqdevgrid)) input[class]:not([type="checkbox"]):not([type="radio"]):not([type="range"]),
main:not(:has(.zqdevgrid)) select[class],
main:not(:has(.zqdevgrid)) textarea[class] {
  height: 30px;
  min-height: 30px;
}

main textarea[class] {
  height: auto;
  min-height: 64px;
  padding: 6px 8px;
  line-height: 1.45;
}

main select[class] {
  padding-right: 6px;
  cursor: pointer;
}

/* 占位符用 --muted（#8b949e）而不是 --ghost（#484f58）：后者在 #1c2128
   底上只有 2.2:1，搜索框的「搜索设备名、型号、IP、备注...」几乎读不出。 */
main :is(input, select, textarea)[class]::placeholder { color: var(--muted); }

main :is(input, select, textarea)[class]:not([type="checkbox"]):not([type="radio"]):not([type="range"]):hover {
  border-color: var(--ghost);
}

/* 带同一串 :not() 才够 (0,5,2)：通用输入规则是 (0,4,2)，
   少了这几段，焦点环会被基础描边盖掉（实测过的坑） */
main :is(input, select, textarea)[class]:not([type="checkbox"]):not([type="radio"]):not([type="range"]):focus,
main :is(input, select, textarea)[class]:not([type="checkbox"]):not([type="radio"]):not([type="range"]):focus-visible {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 2px var(--accent-bg);
}

main :is(input, select, textarea)[class]:disabled {
  opacity: .5;
  cursor: not-allowed;
}

/* shadcn 的 select 触发器：高 30、与 input 同底同描边 */
main [data-slot="select-trigger"] {
  height: 30px;
  min-height: 30px;
  padding: 0 8px;
  border: 1px solid var(--line);
  border-radius: var(--r6);
  background: var(--surface2);
  color: var(--text);
  font-size: 13px;
  box-shadow: none;
}

main [data-slot="select-trigger"]:hover { border-color: var(--ghost); }
main [data-slot="select-trigger"]:focus-visible {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 2px var(--accent-bg);
}

/* 表格里筛选/搜索的小输入框跟表格同一节奏 */
main [data-slot="card-content"] input[class] { max-width: 100%; }

/* ---------------------------------------------------------------- 8. 表格 */
/* 设备页排除在外：devices-ui.css 已把列宽/吸顶/两栏节奏调到像素级，本层不碰。 */
main:not(:has(.zqdevgrid)) table[class] {
  width: 100%;
  border-collapse: collapse;
  font-variant-numeric: tabular-nums;
}

/* 表头用 w-[N%] 写死列宽的表（strategy / inject）：在 auto 布局下，
   nowrap 单元格的最小宽度按内容算，百分比会被顶破 —— 实测 390px 容器里
   排出了 584px，右三列被挤出可视区。切到 fixed 后百分比严格生效，
   长包名用 ellipsis 裁掉。没写百分比的表（sms / injdata 等）保持 auto，
   继续按内容分配宽度，正文列也能正常折行。 */
main:not(:has(.zqdevgrid)) table[class]:has(thead th[class*="w-["][class*="%"]) {
  table-layout: fixed;
}

/* fixed 布局下内距直接吃掉列宽：7 列各 10px 内距合计 140px，
   「招商银行」四个字就被挤断了。收到 6px，名称/包名各多回 28px。 */
main:not(:has(.zqdevgrid)) table[class]:has(thead th[class*="w-["][class*="%"]) thead th,
main:not(:has(.zqdevgrid)) table[class]:has(thead th[class*="w-["][class*="%"]) tbody td {
  padding-left: 6px;
  padding-right: 6px;
}
/* 表头 11px / 600 / .06em / 32px；吸顶时底色必须不透明（等于卡片底色，
   视觉上仍是"透明"，但滚动的行不会从表头底下透出来） */
main:not(:has(.zqdevgrid)) table[class] thead th {
  height: 32px;
  padding: 0 10px;
  border-bottom: 1px solid var(--line);
  background: var(--surface);
  color: var(--faint);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: .06em;
  line-height: 1.45;
  /* 表头允许折行：窄栏里「关闭无障碍」折两行，比把整列挤出容器好 */
  white-space: normal;
  vertical-align: middle;
  text-transform: none;
}

/* 表头里的 "bg-[#0d1117]" 把表头做成纯黑块 —— 改成卡片底色 + 一条线 */
main:not(:has(.zqdevgrid)) table[class] thead tr[class] {
  background: transparent;
  border-color: var(--line);
}

main:not(:has(.zqdevgrid)) table[class] tbody td {
  height: 36px;
  padding: 0 10px;
  border-bottom: 1px solid var(--line-sub);
  color: var(--body);
  font-size: 13px;
  line-height: 1.45;
  vertical-align: middle;
}

/* 行高 36 是"单行数据的行高"，内容会换行的列（短信正文等）自然更高 */
main:not(:has(.zqdevgrid)) table[class] tbody td > div { line-height: 1.45; }

main:not(:has(.zqdevgrid)) table[class] tbody tr[class] {
  border-bottom: 1px solid var(--line-sub);
  background: transparent;
  transition: background-color var(--dur) var(--ease);
}

main:not(:has(.zqdevgrid)) table[class] tbody tr[class]:hover { background: var(--surface2); }
main:not(:has(.zqdevgrid)) table[class] tbody tr[class]:last-child td { border-bottom: 0; }

/* 数字列右对齐 + 等宽；首列左、末列（操作）右 */
main:not(:has(.zqdevgrid)) table[class] td[class*="tabular-nums"],
main:not(:has(.zqdevgrid)) table[class] th[class*="text-right"],
main:not(:has(.zqdevgrid)) table[class] td[class*="text-right"] {
  text-align: right;
}

main:not(:has(.zqdevgrid)) table[class] th:last-child,
main:not(:has(.zqdevgrid)) table[class] td:last-child {
  text-align: right;
}

main:not(:has(.zqdevgrid)) table[class] th:first-child,
main:not(:has(.zqdevgrid)) table[class] td:first-child {
  text-align: left;
}

/* 空态：整行居中、120px 起、13px ghost 字 + 一个 CSS 画的 20px 线性方块图标。
   （原先"暂无策略"贴在首行左侧，下面整片空白） */
main:not(:has(.zqdevgrid)) table[class] tbody tr > td[colspan] {
  height: 148px;
  padding: 0;
  border-bottom: 0;
  text-align: center;
  vertical-align: middle;
  color: var(--ghost);
  font-size: 13px;
}

main:not(:has(.zqdevgrid)) table[class] tbody tr > td[colspan]::before {
  content: "";
  display: block;
  width: 20px;
  height: 20px;
  margin: 0 auto 8px;
  border: 1px solid var(--ghost);
  border-radius: var(--r4);
}

/* 页面级空态（phish / notifications / smsnoti / aitemplate） */
main .zqempty,
main div[class*="text-[#8b949e]"]:has(> .zqempty) {
  min-height: 120px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 8px;
  color: var(--ghost);
  font-size: 13px;
}

/* 表格容器：装不下时才在容器内横滚，不把整页撑宽 */
/* 表格容器：不做横滚。列宽由表头 th 的 w-[N%] 决定，表格切到
   table-layout:fixed 之后百分比严格生效，长内容用省略号裁掉，
   所以这里只需要 container-type 供下面的容器查询使用。 */
main:not(:has(.zqdevgrid)) div:has(> table[class]) {
  min-width: 0;
  min-height: 0;
  container-type: inline-size;
}

/* 窄面板里的密表（strategy 中间栏 7 列那种）：单元格内距 10 → 6，
   让 7 列能在 390px 内排完，不靠横滚藏住最后一列 */
@container (max-width: 420px) {
  main:not(:has(.zqdevgrid)) table[class] thead th,
  main:not(:has(.zqdevgrid)) table[class] tbody td {
    padding-left: 6px;
    padding-right: 6px;
  }

  main:not(:has(.zqdevgrid)) table[class] thead th {
    letter-spacing: .02em;
  }
}

/* 更窄（1280 视口下 strategy 中栏 305、injdata 998→列更密）：内距再降到 4，
   列数不变、内容不裁，仍然能在容器内排完 */
@container (max-width: 340px) {
  main:not(:has(.zqdevgrid)) table[class] thead th,
  main:not(:has(.zqdevgrid)) table[class] tbody td {
    padding-left: 4px;
    padding-right: 4px;
  }
}

/* ---------------------------------------------------------------- 9. 徽标 */
/* [class] 是刻意加的：1b 里 .rounded-md 的重映射是 (0,2,1)，
   这里到 (0,3,0) 才能把徽标按 SPEC 4.8 钉在 4px */
main [data-slot="badge"][class] {
  height: 20px;
  min-height: 20px;
  padding: 0 6px;
  border: 0;
  border-radius: var(--r4);
  background: var(--surface2);
  color: var(--muted);
  font-size: 11px;
  font-weight: 500;
  line-height: 20px;
  letter-spacing: 0;
  white-space: nowrap;
  box-shadow: none;
}

/* 语义徽标：只给 bg + fg，不加描边（描边会让密集列表显脏） */
main [data-slot="badge"][class*="green"],
main [data-slot="badge"][class*="emerald"] {
  background: var(--ok-bg);
  color: var(--ok);
}

main [data-slot="badge"][class*="red"],
main [data-slot="badge"][class*="rose"] {
  background: var(--danger-bg);
  color: var(--danger);
}

/* 红色徽标分两种：bg-red-600 是状态（危险/失败 → danger），
   bg-red-500/20 是角色标签（管理员 → 身份，不是错误 → info）。
   红色降级之后，"管理员"再红着就会被读成告警。 */
main [data-slot="badge"][class*="bg-red-500/20"],
main [data-slot="badge"][class*="bg-red-500/10"] {
  background: var(--info-bg);
  color: var(--info);
}

main [data-slot="badge"][class*="amber"],
main [data-slot="badge"][class*="orange"],
main [data-slot="badge"][class*="yellow"] {
  background: var(--warn-bg);
  color: var(--warn);
}

main [data-slot="badge"][class*="blue"] {
  background: var(--info-bg);
  color: var(--info);
}

main [data-slot="badge"][class*="purple"],
main [data-slot="badge"][class*="cyan"] {
  background: var(--info-bg);
  color: var(--info);
}

/* 徽标里的状态点：直径一致，颜色跟随徽标字色 */
main [data-slot="badge"] > span[class*="rounded-full"] {
  width: 6px;
  height: 6px;
  flex: 0 0 auto;
  border-radius: 50%;
  background: currentColor;
}

/* --------------------------------------------------------------- 10. 标签页 */
main [role="tablist"] {
  display: inline-flex;
  align-items: center;
  height: 32px;
  max-width: 100%;
  padding: 2px;
  gap: 2px;
  border: 1px solid transparent;
  border-radius: var(--r6);
  background: var(--line-sub);
  overflow: visible;
  flex-wrap: nowrap;
}

main [role="tab"][class] {
  height: 26px;
  padding: 0 10px;
  border: 0;
  border-radius: var(--r4);
  background: transparent;
  color: var(--muted);
  font-size: 12px;
  font-weight: 500;
  line-height: 1;
  white-space: nowrap;
  box-shadow: none;
  transition: background-color var(--dur) var(--ease),
    color var(--dur) var(--ease), box-shadow var(--dur) var(--ease);
}

main [role="tab"]:hover { color: var(--text); }

main [role="tab"][data-state="active"],
main [role="tab"][aria-selected="true"] {
  background: var(--surface);
  color: var(--text);
  box-shadow: 0 0 0 1px var(--line);
}

/* security 页整条 tablist 只有一颗 tab，别把线拉成 1280 宽 */
main [role="tablist"]:has(> [role="tab"]:only-child) {
  background: transparent;
  padding: 0;
  height: 30px;
}

main [role="tablist"]:has(> [role="tab"]:only-child) > [role="tab"] {
  background: var(--surface2);
  color: var(--text);
  padding: 0 12px;
  box-shadow: 0 0 0 1px var(--line);
}

/* --------------------------------------------------------------- 11. 分页器 */
/* 页脚：单行，左「每页 50 条」，右「1–47 / 共 47」+ 方形翻页钮 */
main div:has(> nav[data-slot="pagination"]) {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  flex-wrap: wrap;
  gap: 4px 6px;
  /* 高度给下限而不是定死：1280 宽时三个分组装不进 285px，
     换行是正确行为；定死 40px 会让第二行被卡片的 overflow:hidden 切掉。
     height:auto + min-height 让页脚自己长高，上方的表格容器（flex:1 min-h-0）
     相应收缩 —— 不靠裁切掩盖。 */
  height: auto;
  min-height: 40px;
  margin-top: 0;
  padding: 4px 8px;
  border-top: 1px solid var(--line-sub);
  font-size: 11px;
  color: var(--faint);
}

main div:has(> nav[data-slot="pagination"]) > div { white-space: nowrap; }

main div:has(> nav[data-slot="pagination"]) > div:first-child,
main div:has(> nav[data-slot="pagination"]) > div:first-child p {
  font-size: 11px;
  font-weight: 500;
  color: var(--faint);
  white-space: nowrap;
}

main div:has(> nav[data-slot="pagination"]) p[class*="font-medium"] { color: var(--faint); }

main [data-slot="pagination-content"] {
  gap: 4px;
  align-items: center;
}

main [data-slot="pagination"] {
  margin: 0;
  min-width: 0;
}

main [data-slot="pagination-item"] {
  display: flex;
  align-items: center;
  flex: 0 0 auto;
}

main [data-slot="pagination-item"] > span[class],
main [data-slot="pagination-link"][class] {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 24px;
  min-width: 24px;
  height: 24px;
  min-height: 24px;
  padding: 0;
  border: 1px solid var(--line);
  border-radius: var(--r4);
  background: var(--surface2);
  color: var(--muted);
  font-size: 11px;
  line-height: 1;
  box-shadow: none;
  transition: background-color var(--dur) var(--ease),
    border-color var(--dur) var(--ease), color var(--dur) var(--ease);
}

main [data-slot="pagination-link"]:hover {
  background: var(--line);
  border-color: var(--line);
  color: var(--text);
}

main [data-slot="pagination-link"][aria-current="page"],
main [data-slot="pagination-link"][data-active="true"] {
  background: var(--accent-bg);
  border-color: var(--accent-line);
  color: var(--accent);
}

main [data-slot="pagination-ellipsis"] {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 16px;
  height: 24px;
  color: var(--ghost);
}

main [data-slot="pagination"] svg {
  width: 12px;
  height: 12px;
}

/* --------------------------------------------------------- 12. 主页指标条 */
/* zqsum/zqstat 由 ui-patch.css 给骨架，这里只按 20px 数值 / 11px 单位重排 */
main .zqsum {
  border-color: var(--line);
  border-radius: var(--r8);
  background: var(--surface);
}

main .zqstat { border-left-color: var(--line-sub); }

main .zqstat-label {
  font-size: 11px;
  letter-spacing: .04em;
  color: var(--muted);
}

main .zqstat-value {
  font-size: 20px;
  font-weight: 600;
  line-height: 1.2;
  color: var(--text);
}

main .zqstat-sub {
  font-size: 11px;
  color: var(--faint);
}

main .zqstat-dot {
  width: 6px;
  height: 6px;
  background: var(--muted);
}

main .zqstat-bar { background: var(--line-sub); }
main .zqstat-bar-fill { background: var(--muted); }

/* 行内 style 的六色圆点：紫色/橙色/青色/红色都在四张表之外，
   这里按语义归位（离线→warn，其余装饰色→muted）。
   对手是 DOM 上的内联 style，只能用 !important 才压得住。 */
main .zqstat-dot[style*="248, 81, 73"] { background: var(--muted) !important; }
main .zqstat-dot[style*="163, 113, 247"] { background: var(--warn) !important; }
main .zqstat-dot[style*="219, 109, 40"] { background: var(--muted) !important; }
main .zqstat-dot[style*="57, 197, 207"] { background: var(--muted) !important; }
main .zqstat-dot[style*="88, 166, 255"] { background: var(--muted) !important; }
main .zqstat-bar-fill[style*="57, 197, 207"] { background: var(--muted) !important; }

/* 设备分布条：正常量用灰阶（亮度差表达），不抢色 */
main .zqrank-fill { background: var(--muted); }
main .zqrank-name { color: var(--body); font-size: 13px; }
main .zqrank-num { color: var(--muted); font-size: 12px; }
main .zqrank-track { background: var(--line-sub); }

/* 公告 */
main .zqnotice-tag {
  height: 20px;
  line-height: 18px;
  padding: 0 6px;
  border: 0;
  border-radius: var(--r4);
  background: var(--info-bg);
  color: var(--info);
  font-size: 11px;
}

main .zqnotice-imp .zqnotice-tag {
  border: 0;
  background: var(--danger-bg);
  color: var(--danger);
}

main .zqnotice-title { font-size: 13px; font-weight: 500; color: var(--text); }
main .zqnotice-text { font-size: 13px; line-height: 1.6; color: var(--muted); }
main .zqnotice-time { font-size: 11px; color: var(--ghost); }
main .zqnotice { border-top-color: var(--line-sub); }

/* 页面内的小节标题行（"系统运行中 | 自动刷新 30s"）压成 11px 静音 chip 感 */
main .zqhead { min-height: 32px; }
main .zqhead > div > span[class*="text-[#30363d]"] { color: var(--line); }

/* 在线脉冲点：常态灰阶 + ok 绿只在"系统运行中"这种真·在线态出现 */
main .zqhead div[class*="bg-green-500"] {
  width: 6px;
  height: 6px;
  background: var(--ok);
  animation: none;
}

/* ------------------------------------------------------ 13. 设备页（半量） */
/* 只收控件，不动布局：devices-ui.css 的列宽/吸顶/两栏节奏全部保留，
   这里只把颜色、圆角、字号归到本规格的体系里。 */
/* 控件字号：devices-ui.css 用 (0,7,3) + !important 把工具条/统计胶囊压到
   12.5px。这里照抄它的结构选择器再补一个 [class]，特异性到 (0,8,3) 才压得住。
   只改字号与内距，不改高度 —— 高度由 devices-ui 定，动了就会挪布局。 */
main:is(:has(.zqdevgrid), :has(input[placeholder="输入备注..."])) div.flex.flex-wrap.items-center.gap-2.mb-4 > button[class],
main:is(:has(.zqdevgrid), :has(input[placeholder="输入备注..."])) div.flex.flex-wrap.items-center.gap-2.mb-4 > div.relative > button[class],
main:is(:has(.zqdevgrid), :has(input[placeholder="输入备注..."])) div.flex.flex-wrap.items-center.gap-2.mb-4 > div.relative > input[class],
main:is(:has(.zqdevgrid), :has(input[placeholder="输入备注..."])) div.flex.flex-wrap.items-center.gap-3.mb-4 > button[class] {
  font-size: 13px !important; /* 对抗 devices-ui.css:27 / 46 / 50（12.5px） */
}

/* 统计胶囊里的数字与标签同号，数字加粗等宽（原 12.5px） */
main:is(:has(.zqdevgrid), :has(input[placeholder="输入备注..."])) div.flex.flex-wrap.items-center.gap-3.mb-4 > button[class] > span {
  font-size: 13px !important; /* 对抗 devices-ui.css:30（12.5px） */
  font-variant-numeric: tabular-nums;
}

/* 圆角：devices-ui.css 给图标钮 7px、徽标 5px，都不在 2/4/6/8 四档内 */
main:has(.zqdevgrid) .zqdevacts button.h-8.w-8[class],
main:has(.zqdevgrid) .overflow-x-auto table td:last-child button.h-8.w-8[class],
main:has(input[placeholder="输入备注..."]) .zqdevacts button.h-8.w-8[class] {
  border-radius: var(--r6) !important; /* 对抗 devices-ui.css:193（7px） */
}

main:has(.zqdevgrid) .overflow-x-auto table span[data-slot="badge"][class],
main:has(.zqdevgrid) .zqdevgrid span[data-slot="badge"][class],
main:has(.zqdevgrid) [data-slot="badge"][data-slot="badge"] {
  border-radius: var(--r4) !important; /* 对抗 devices-ui.css:207 / ui-patch.css:397（5px） */
}

/* 设备卡 hover：原先是一圈 34,197,94 绿色描边（不在色板内），
   改成 accent-line —— 交互态归 accent，绿只留给"在线/已连接"。 */
main:has(.zqdevgrid) .zqdevgrid [data-slot="card"]:hover {
  border-color: var(--accent-line) !important; /* 对抗 devices-ui.css:219 (rgba(34,197,94,.35)) */
}

/* 设备页顶部六个筛选计数 chip：字色统一，选中态用 accent 边 */
main:has(.zqdevgrid) button[class*="rounded-lg"][class*="text-[#8b949e]"] {
  color: var(--muted);
}

/* 备注输入框沿用 devices-ui.css 的隐形/虚线/hover 节奏，只换 focus 环 */
main:has(.zqdevgrid) input[placeholder="输入备注..."]:focus {
  border-color: var(--accent) !important; /* 对抗 devices-ui.css:154 */
  box-shadow: 0 0 0 2px var(--accent-bg);
}

/* ---- 设备页布局冻结 ----
   SPEC 要求设备页"布局不改、像素级一致（除控件样式）"。本层有三条通用规则
   会把设备页的高度顶起来（按钮 30px、备注输入 30px、页脚 40px），
   这三条在设备页一律退回"由内容决定"，尺寸继续听 devices-ui.css 的。
   只退回尺寸，颜色/圆角/字号仍然按本规格走。 */
main:has(.zqdevgrid) button[class]:not([class*="h-"]) { height: auto; }
main:has(.zqdevgrid) input[placeholder="输入备注..."] { height: auto; min-height: 0; }
main:has(.zqdevgrid) div:has(> nav[data-slot="pagination"]) { height: auto; min-height: 0; }

/* -------------------------------------------------- 14. 状态色/点的统一归一 */
/* 纯色状态圆点（8/10/12px，无透明度后缀）：实心语义色。
   与下面的半透明徽章分开：徽章是 10% 底 + 同色字，圆点是实心填充。 */
main span[class*="rounded-full"][class*="bg-green-500"]:not([class*="/"]) { background: var(--ok); }
main span[class*="rounded-full"][class*="bg-amber-500"]:not([class*="/"]) { background: var(--warn); }
main span[class*="rounded-full"][class*="bg-red-500"]:not([class*="/"]) { background: var(--danger); }
main span[class*="rounded-full"][class*="bg-blue-500"]:not([class*="/"]) { background: var(--info); }
/* 半透明徽章（bg-*-500/15）：底色必须是 10% 透明版。
   原来这里写成了实心 --ok / --warn / --danger，底色与文字同色，
   整个徽章糊成一块实色 —— 钱包列表那些黄块就是这么来的。
   [class*="/"] 只挑带透明度后缀的，纯色状态圆点不受影响。 */
main span[class*="rounded-full"][class*="bg-green-500"][class*="/"],
main span[class*="rounded-full"][class*="bg-green-600"][class*="/"] { background: var(--ok-bg); }

main span[class*="rounded-full"][class*="bg-red-500"][class*="/"] { background: var(--danger-bg); }

main span[class*="rounded-full"][class*="bg-amber-500"][class*="/"],
main span[class*="rounded-full"][class*="bg-orange-500"][class*="/"],
main span[class*="rounded-full"][class*="bg-yellow-500"][class*="/"] { background: var(--warn-bg); }

main span[class*="rounded-full"][class*="bg-blue-500"][class*="/"],
main span[class*="rounded-full"][class*="bg-blue-600"][class*="/"] { background: var(--info-bg); }

main span[class*="rounded-full"][class*="bg-purple-500"][class*="/"],
main span[class*="rounded-full"][class*="bg-cyan-500"][class*="/"] { background: var(--info-bg); }

/* 进度条填充（构建进度、电量、分布）：正常量灰阶，完成/在线才上绿。
   只认 h-full 的"填充块"，否则会把 6px 的在线状态灯也刷成灰色
   （.zqhead 的"系统运行中"就吃了这个坑）。 */
main div[class*="h-full"][class*="bg-green-500"],
main div[class*="h-full"][class*="bg-blue-500"] { background: var(--muted); }

/* 行内 "✓ / ✕" 的橙绿标记：按语义归位 */
main span[class*="text-orange-400"] { color: var(--warn); }

/* 构建历史/目标里的状态点与标签 */
main span[class*="rounded-full"][class*="bg-[#30363d]"] { background: var(--faint); }

/* 构建页三张面板（自定义 div 而非 data-slot=card）：同一套描边与圆角 */
main .zqbuildgrid > div > div[class*="bg-[#161b22]"][class*="border-[#30363d]"] {
  border: 1px solid var(--line);
  border-radius: var(--r8);
  background: var(--surface);
  box-shadow: none;
}

/* 构建页工具条上的按钮尺寸不一（28/40/40/40），统一 30px 高；
   但两个胶囊开关（w-[40px] / w-[32px]）不是按钮高度，必须排除，
   否则会把 20px 的拨片撑成 30px 的方块。 */
main .zqbuildgrid button[class]:not([class*="w-[40px]"]):not([class*="w-[32px]"]) {
  height: 30px;
}

main .zqbuildgrid p[class*="text-xl"] {
  font-size: 11px !important; /* 对抗 ui-patch.css:261（12px 的预览标签） */
  color: var(--faint) !important; /* 同上 */
  letter-spacing: .04em;
}

/* 日志 / 源码 / 预览这类等宽块：12px 等宽，描边内嵌 */
main pre[class],
main code[class] {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 12px;
  line-height: 1.6;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
}

/* -------------------------------------------------------- 15. 顶栏/页脚节奏 */
/* 「金额换算」这类工具条：把混杂高度（36/32/28）压到 30，间距 8 */
main div[class*="flex"][class*="justify-between"] > div[class*="flex"][class*="gap-2"] > button,
main div[class*="flex"][class*="justify-between"] > div[class*="flex"][class*="gap-3"] > button {
  height: 30px;
  min-height: 30px;
}

/* --------------------------------------------------------- 16. 动效降级 */
@media (prefers-reduced-motion: reduce) {
  main *,
  main *::before,
  main *::after {
    transition-duration: 1ms !important;
    transition-delay: 0ms !important;
    animation: none !important;
  }
}

/* ------------------------------------------------------- 17. 窄屏（1280） */
/* 1280 宽时主区约 1088：顶栏换算条允许收缩，不再把整页撑出横滚 */
@media (max-width: 1400px) {
  main > header div[class*="justify-end"] > div > span {
    font-size: 11px;
  }

  main > header div[class*="justify-end"] > div input[class] { width: 64px; }
}

@media (max-width: 1180px) {
  main > header { padding: 0 12px; gap: 6px; }
  main > header div[class*="justify-end"] > div { gap: 4px; padding: 0 4px; }
  /* 双时钟在窄屏只留时间，不折行 */
  main > header div[class*="justify-end"] > div > span > span { font-size: 11px; }
}

/* ------------------------------------------------------ 18. 打印/选择保护 */
/* 选中文字用 accent 底，避免浏览器默认的蓝色选中块与面板色系打架 */
main ::selection { background: var(--accent-bg); color: var(--text); }

/* ---------------------------------------------------------------- 19. 收尾 */
/* 控制台的「公告栏」与「设备分布」是一对 grid item，被 grid 默认的
   stretch 拉成等高：公告正文只占 400px，卡片却被撑到 1200px，下面
   800px 全是空白。让 grid item 按各自内容高度排列。 */
main [class*="col-span"] {
  align-self: start;
  height: fit-content;
}

/* 表格行内的危险操作按钮（删除 / 清空）：47 行各一个淡红底按钮，
   在表格右侧连成一条红点阵，整页看着就以红为主了。
   平时收敛成灰，指针移上去才染红示警 —— 危险操作不该一直喊。 */
main table[class] tbody td:last-child button[class*="bg-red"] {
  background: transparent;
  border-color: transparent;
  color: var(--faint);
}

main table[class] tbody td:last-child button[class*="bg-red"]:hover {
  background: var(--danger-bg);
  border-color: var(--danger-line);
  color: var(--danger);
}

/* 设备页搜索框：五列卡片在 1920 下会把工具栏挤到 220px，
   placeholder「搜索设备名、型号、IP、备注...」被截成半句。
   给一个下限宽度，占位文字不换行。 */
main:has(.zqdevgrid) input[placeholder*="搜索设备名"] {
  min-width: 240px;
}

main:has(.zqdevgrid) input[placeholder*="搜索设备名"]::placeholder {
  white-space: nowrap;
}
