
    /* ── Fixed-design proportional scaling ──
       以 2560×1289 为设计稿尺寸，body 作为整体逻辑画布，transform: scale 拉伸填满视口。
       ◆ 必须放在 body 而不是 .app：运行时挂到 document.body 的 fixed 覆盖层
         （右键菜单/过滤下拉面板/框选层/确认弹窗/虚拟光标）必须与 .app 内内容处于
         同一逻辑坐标系。若只缩 .app，这些 body 级元素是物理坐标，锚点会与内容错位
         （下拉菜单不跟随单元格）。放 body 后所有 ÷scale 换算与 zoom 时代等价。
       ◆ 行列像素点清晰：transform 走 GPU 合成，无 zoom 的子像素栅格化损失。
       ◆ --ld-scale-x / --ld-scale-y 由 lingdu.html 的 LDZoom 写入；transform-origin left top。 */
    :root {
      --ld-design-w: 2560px;
      --ld-design-h: 1289px;
      --ld-scale-x: 1;
      --ld-scale-y: 1;
      /* 浏览器模式可视视口高（2026-08-13 平板"底部被切"根因修复）：
         平板浏览器顶部 UI（地址栏/标签栏）以浮层方式盖住可视区顶部时，innerHeight 不扣减 UI，
         100vh 会按整窗高度解析 → 页面填满整窗、底部被浏览器 UI 盖住、看不到系统设置/输入框。
         100dvh（动态视口高）由浏览器实时扣减顶部 UI（地址栏显示=小、隐藏=大），
         旧浏览器不支持 dvh 时退回 100vh（双声明，后者无效则丢弃）。 */
      --ld-viewport-h: 100vh;
      --ld-viewport-h: 100dvh;
    }
    /* 全屏模式开关（2026-08-13 用户拍板：缩放弹窗内两种视口模式切换）：
       html.ld-vh-mode = 强制全屏（--ld-viewport-h 固定 100vh，不感知浏览器顶部 UI，
       始终填满整窗高；浏览器 UI 浮层盖住时底部被挡，靠滚动露出）；
       默认 dvh = 自动感知（浏览器 UI 在时让出高度、隐藏时满屏，推荐）。 */
    html.ld-vh-mode { --ld-viewport-h: 100vh; }
    html, body {
      width: 100%;
      height: 100%;
      margin: 0;
      padding: 0;
      overflow: hidden;
      background: var(--bg-deep);
    }
    /* 触屏：全局禁用双击缩放（double-tap-zoom），避免浏览器把项目内的双击误判为
       放大缩放手势（干扰双击卡片本地打开、双击标签重命名等）。
       manipulation = 保留滚动与双指捏合缩放，仅禁用双击缩放与 300ms 点击延迟；
       各拖动/缩放把手等已有更具体的 touch-action 不受影响。 */
    html {
      touch-action: manipulation;
    }
    body {
      width: var(--ld-design-w);
      height: var(--ld-design-h);
      min-height: var(--ld-design-h);
      transform: scale(var(--ld-scale-x), var(--ld-scale-y));
      transform-origin: left top;
      will-change: transform;
    }

    /* ── 首帧防闪（2026-08-12 用户反馈"刷新视觉闪烁"）──
       刷新加载早期 outerHeight 未就绪 → html zoom 先按错基准渲染，load 后校准跳变。
       lingdu.html 顶部脚本在加载期给 html 加 .ld-zoom-pending 隐藏 body，
       等 zoom 用精确 bzLoad 校准完成后再移除 —— 用户看到的第一帧即最终档位大小。 */
    html.ld-zoom-pending body {
      visibility: hidden;
    }

    /* ── 浏览器模式（自主缩放关闭，html.ld-browser-mode）──
       全权交给浏览器：撤掉 transform 拉伸，布局宽度自适应视口；
       高度回到页面内——body/.app/main/sidebar 均等于视口高（100vh），
       页面本身不滚动，内容超高时在 main（及 sidebar）内部滚动。
       该模式下 LDZoom 置 sx=sy=1，所有 ÷scale 定位换算自动退化为 ÷1，无需改 JS。 */
    html.ld-browser-mode,
    html.ld-browser-mode body {
      overflow-x: hidden;   /* 始终禁止左右滚动 */
      overflow-y: hidden;   /* 页面不滚动，滚动交给 .main 内部 */
      width: 100%;
      height: 100%;
    }
    html.ld-browser-mode body {
      width: 100%;
      height: 100%;
      min-height: 100%;
      transform: none;
      will-change: auto;
    }
    html.ld-browser-mode .app {
      width: 100%;
      min-width: 0;         /* 覆盖 min-width: 2560px，宽度自适应视口 */
      height: var(--ld-viewport-h);
      min-height: var(--ld-viewport-h);
      max-width: none;
      max-height: none;
    }
    html.ld-browser-mode .main {
      height: var(--ld-viewport-h);
      min-height: var(--ld-viewport-h);    /* 覆盖 height/min-height: 1289px，高度回到页面内 */
      overflow-y: auto;
      overflow-x: hidden;
    }
    html.ld-browser-mode .sidebar {
      height: var(--ld-viewport-h) !important;
      max-height: var(--ld-viewport-h) !important;
      min-height: var(--ld-viewport-h) !important;
    }
    /* ── CSS 旋转强制横屏（2026-08-14 orientation.lock 失败回退方案）──
       手机系统旋转锁定（Auto-rotate OFF）会拒绝 orientation.lock()，
       此时 JS 加 html.ld-css-rotate 类，并将 --ld-rot-vw/vh/tx 写成 innerH/innerW/innerW 像素值：
         --ld-rot-vw = innerHeight（物理竖屏的高，旋转后当宽 → 长边为宽 ✓）
         --ld-rot-vh = innerWidth （物理竖屏的宽，旋转后当高 → 短边为高 ✓）
         --ld-rot-tx = innerWidth （rotate(90deg) 后 body 左上跑到视口右侧外，需平移回来）
       body transform 顺序：先 scale（拉伸）→ 再 rotate → 再 translate（拉回视口内）；
       transform-origin 保持 left top。
       同时 .main 内部滚动方向交换。 */
    html.ld-css-rotate,
    html.ld-css-rotate body {
      width: 100%;
      height: 100%;
      overflow: hidden;
    }
    html.ld-css-rotate body {
      /* 旋转轴 left top：rotate(90deg) 后 body 左上位于 [原宽, 0] 物理坐标，
         translateX(--ld-rot-tx) 向右移一个原宽（innerW）拉回视口内铺满。 */
      transform-origin: left top;
      transform: scale(var(--ld-scale-x), var(--ld-scale-y)) rotate(90deg) translateX(var(--ld-rot-tx, 0px));
      will-change: transform;
    }
    html.ld-css-rotate .main {
      /* 旋转后原纵向滚动变横向，交换 overflow（配合 LDZoom.calc() 内宽高互换）*/
      height: var(--ld-design-h);
      overflow-x: auto;
      overflow-y: hidden;
      will-change: transform;
    }
    html.ld-css-rotate .sidebar {
      height: var(--ld-design-h);
      will-change: transform;
    }
    html.ld-css-rotate.ld-browser-mode body {
      /* 浏览器模式（无 scale）：仅 rotate + translate */
      transform: rotate(90deg) translateX(var(--ld-rot-tx, 0px));
    }
    /* ── 大字模式自动档位缩放（CSS zoom，2026-08-11）──
       1080 档 80%：html 级 zoom 把整页等比缩小。实测（Chrome）zoom 在根元素上
       只放大布局视口宽度（body 100% 天然铺满，宽度无需补偿）；高度方向 100vh
       仍按物理视口计算、视觉被等比缩小 → 底部留白。因此只按 1/zoom 补偿高度：
       body min-height 与 .app/.main/.sidebar 的 height 均 ×(1/zoom)，
       视觉高度恢复铺满，宽度不补偿（补偿会超出右缘）。
       档位生效时 lingdu.html 的 LDZoom 给 html 加 .ld-zoom-gear 并直设
       root.style.zoom（inline 优先，此规则作后备）。 */
    html.ld-browser-mode.ld-zoom-gear {
      zoom: var(--ld-zoom, 1);
    }
    html.ld-browser-mode.ld-zoom-gear body {
      min-height: calc(var(--ld-viewport-h) / var(--ld-zoom, 1));
    }
    html.ld-browser-mode.ld-zoom-gear .app,
    html.ld-browser-mode.ld-zoom-gear .main {
      height: calc(var(--ld-viewport-h) / var(--ld-zoom, 1));
      min-height: calc(var(--ld-viewport-h) / var(--ld-zoom, 1));
    }
    html.ld-browser-mode.ld-zoom-gear .sidebar {
      height: calc(var(--ld-viewport-h) / var(--ld-zoom, 1)) !important;
      max-height: calc(var(--ld-viewport-h) / var(--ld-zoom, 1)) !important;
      min-height: calc(var(--ld-viewport-h) / var(--ld-zoom, 1)) !important;
    }
    /* 档位下底部兜底（2026-08-12 用户反馈：2880×1664 等高分屏档位应用后，
       内容视觉高度超过物理视口底 → 侧边栏"系统设置"、页面底部输入框被 body overflow:hidden 裁掉。
       补偿正常情况下视觉恰好铺满 → 无超高 → 无滚动条无副作用；
       补偿偏差/内容超高时允许纵向滚动，保证底部元素始终可达。 */
    html.ld-browser-mode.ld-zoom-gear,
    html.ld-browser-mode.ld-zoom-gear body {
      overflow-y: auto;
    }
    html.ld-browser-mode.ld-zoom-gear .sidebar {
      overflow-y: auto;
    }
    /* ── 大字模式档位选择弹窗：fixed 容器需高度补偿（html zoom 高度方向布局视口不放大），
       宽度 100% 即放大后的布局视口宽、视觉铺满；卡片自身由 JS 反向 zoom 补偿为正常大小。
       2026-08-12 用户拍板：不要蒙版、底层仍可交互 —— 容器 pointer-events:none 不拦截
       页面任何点击/悬停，仅卡片自身恢复可交互（.ld-zoom-picker pointer-events:auto） */
    .ld-zoom-picker-overlay {
      position: fixed;
      left: 0;
      top: 0;
      width: 100%;
      height: calc(var(--ld-viewport-h) / var(--ld-zoom, 1));
      z-index: 99999;
      display: flex;
      align-items: center;
      justify-content: center;
      pointer-events: none;
    }
    .ld-zoom-picker {
      /* 窗体尺寸与文字大小对齐"主题亮度调节"弹窗（.font-settings-dialog/.brightness-dialog：
         380px 宽、padding 24px、圆角 16px、标题 20px，2026-08-12 用户拍板）
         2026-08-13 用户拍板：弹窗整体高度减小 100px → padding 24→12px，各区块
         margin/padding 同步收紧（标题 14→4、提示 16→4、自定义 14/12→6/6、
         全屏 12/12→6/6、档位按钮垂直内边距 8→5、关闭按钮 31→26） */
      /* 2026-09-17 用户："缩放比例 这个弹窗的 颜色 透明度遗漏了" —— 本窗当时只顾着对齐尺寸，
         底色/圆角/投影没跟上 #147 定下的"全站弹窗体统一外观"（底色 var(--panel) 半透明、圆角 12px、
         一律不带外圈发光影子），这里补齐。 */
      background: var(--panel);
      color: var(--text, #1a2b4a);
      border-radius: 12px;
      padding: 21px;
      width: 380px;
      min-width: 380px;
      border: 1px solid var(--line);
      box-shadow: none;
      text-align: center;
      pointer-events: auto;
    }
    /* ── 档位模式下浮层跟随档位缩放（2026-08-14 用户拍板，与预览弹窗一致）──
       AI 助手面板 / 语音设置弹窗 / AI API 设置弹窗 / 发布消息弹窗不再做 zoom: calc(1/--ld-gear)
       反向补偿 → 弹窗视觉 = 布局 × 档位，与主界面一致；JS 坐标换算（_ldFloatPosDivX/Y、
       _annDivX/Y）改为"布局 = 视觉 ÷ 档位"（返回 gear），max-height/max-width 视觉换算用
       --ld-gear 替换 --ld-float-div（见下）。 */
    /* 自定义无级比例条（50%–200%）：标签 + 滑块 + 当前值 */
    .ld-zoom-picker-custom {
      display: flex;
      align-items: center;
      gap: 10px;
      margin-top: 8px;
      padding-top: 8px;
      border-top: 1px solid var(--line);
    }
    .ld-zoom-picker-cus-label {
      font-size: 13px;   /* 对齐弹窗整体文字（15px）；2026-08-13 弹窗减高 15→13 */
      color: var(--muted, #6b7a90);
      white-space: nowrap;
    }
    .ld-zoom-picker-custom input[type="range"] {
      flex: 1;
      min-width: 0;
      accent-color: var(--primary, #2563eb);
    }
    /* 数值区 = 数字输入框 + 固定 "%"（2026-08-12 用户拍板：可手动直接输入数字） */
    .ld-zoom-picker-cus-val {
      font-size: 13px;   /* 对齐弹窗整体文字（15px）；2026-08-13 弹窗减高 15→13 */
      font-weight: 600;
      min-width: 58px;
      text-align: right;
      white-space: nowrap;
      display: inline-flex;
      align-items: center;
      justify-content: flex-end;
      gap: 2px;
    }
    .ld-zoom-picker-cus-val input {
      width: 44px;
      box-sizing: border-box;
      border: 1px solid var(--line);
      border-radius: 6px;
      padding: 2px 6px;
      font-size: 13px;   /* 对齐弹窗整体文字（15px）；2026-08-13 弹窗减高 15→13 */
      font-weight: 600;
      color: inherit;
      background: transparent;
      text-align: center;
    }
    .ld-zoom-picker-cus-val input:focus {
      outline: none;
      border-color: var(--primary, #2563eb);
    }
    .ld-zoom-picker-head {
      display: flex;
      align-items: center;
      justify-content: space-between;
      margin-bottom: 7px;
    }
    .ld-zoom-picker-title {
      font-size: 19px;   /* 对齐亮度弹窗 h3（.font-settings-dialog .section-head h3）；2026-08-13 减高 20→18 → +50px 恢复 18→19 */
      font-weight: 600;
    }
    .ld-zoom-picker-close {
      width: 28px;      /* 原 24px，基数加大 30%（2026-08-12 用户拍板）→ 减高 31→26 → +50px 恢复 26→28 */
      height: 28px;
      border: none;
      border-radius: 6px;
      background: transparent;
      color: var(--text, #1a2b4a);
      font-size: 20px;  /* 同步 23→18 → 18→20 */
      line-height: 1;
      cursor: pointer;
      display: flex;
      align-items: center;
      justify-content: center;
    }
    .ld-zoom-picker-close:hover { background: var(--panel-soft); }
    .ld-zoom-picker-hint {
      font-size: 16px;   /* "当前缩放比例"提示：15→18px（2026-08-12 用户拍板）→ 2026-08-13 减高 18→15 → +50px 恢复 15→16 */
      color: var(--muted, #6b7a90);
      margin-bottom: 6px;
    }
    .ld-zoom-picker-row {
      display: flex;
      gap: 12px;
      justify-content: center;
    }
    .ld-zoom-picker-btn {
      padding: 6px 22px;
      border-radius: 8px;
      /* 2026-09-17：档位按钮原来整块填 --primary（窗体内层唯一的实色块），
         按"弹窗体一体背景 + 自身外框线"（同 #149/#151）改成透明底 + 一圈边框，悬停才亮。 */
      border: 1px solid var(--line);
      background: transparent;
      color: var(--text);
      font-size: 19px;   /* 对齐亮度弹窗按钮字号（.font-settings-dialog .btn）；2026-08-13 减高 20→18 → +50px 恢复 18→19 */
      cursor: pointer;
      transition: color .15s ease, border-color .15s ease;
    }
    .ld-zoom-picker-btn:hover { color: var(--primary); border-color: var(--primary); }
    .app {
      position: relative;   /* 缩放由 body 统一负责，.app 自身不再 transform（避免双重缩放） */
      z-index: 1;
      width: var(--ld-design-w);
      height: var(--ld-design-h);
      min-width: var(--ld-design-w);
      min-height: var(--ld-design-h);
      max-width: none;
      max-height: none;
      --sidebar-width: 190px;
      --sidebar-full-w: 190px;   /* 侧栏"全显示"宽度，供非固定态浮层取用（.high-res 下另定为 240px） */
      --sidebar-gap: 0px;
      display: grid;
      grid-template-columns: var(--sidebar-width) minmax(0, 1fr);
      column-gap: var(--sidebar-gap);
      transition: grid-template-columns .125s ease, column-gap .125s ease;
      filter: brightness(var(--brightness, 1));
      overflow: hidden;
    }

    .app.sidebar-icon { --sidebar-width: 88px; }
    .app.sidebar-hidden { --sidebar-width: 0px; --sidebar-gap: 0px; }
    html[data-ss="icon"] .app { --sidebar-width: 88px; }
    html[data-ss="hidden"] .app { --sidebar-width: 0px; --sidebar-gap: 0px; }
    html[data-ss="hidden"] .app .sidebar { width: 0; padding-left: 0; padding-right: 0; opacity: 0; pointer-events: none; transform: translateX(-12px); }
    /* 图标模式下文字真隐藏（与 .app.sidebar-icon 规则等价，L565 起）：html[data-ss="icon"]
       在页面加载早期（setSidebarState 加类前）即生效，若不隐藏文字，侧边栏已是 88px 宽而
       文字完整渲染 → 溢出被裁/宽度不合适时漏字。两条规则必须保持一致 */
    html[data-ss="icon"] .brand-text,
    html[data-ss="icon"] .nav-label,
    html[data-ss="icon"] .nav-title,
    html[data-ss="icon"] .side-card,
    html[data-ss="icon"] .sidebar-tool-title,
    html[data-ss="icon"] .sidebar-tool-text {
      opacity: 0;
      width: 0;
      height: 0;
      margin: 0;
      padding: 0;
      overflow: hidden;
      pointer-events: none;
    }
    html[data-ss] .app { transition: none !important; }
    html[data-ss] .sidebar { transition: none !important; }
    html[data-ss] .brand-text,
    html[data-ss] .nav-label,
    html[data-ss] .nav-title,
    html[data-ss] .side-card,
    html[data-ss] .sidebar-tool-title,
    html[data-ss] .sidebar-tool-text { transition: none !important; }

    .sidebar {
      width: var(--sidebar-width);
      min-width: 0;
      background: var(--sidebar-bg);
      color: var(--sidebar-text);
      border-right: 1px solid var(--sidebar-border);
      box-shadow: -2px 0 48px rgba(0,0,0,.084);
      padding: 22px 12px 22px 0;
      position: sticky;
      top: 0;
      height: var(--ld-design-h);
      min-height: var(--ld-design-h);
      overflow: hidden;
      display: flex;
      flex-direction: column;
      transition: width .125s ease, padding .125s ease, opacity .2s ease, transform .125s ease;
    }

    .sidebar-main {
      flex: 1 1 auto;
      min-height: 0;
      overflow-y: auto;
      overflow-x: hidden;
      padding-right: 2px;
    }

    /* 全局隐藏滚动条但保留滚动能力 */
    * {
      scrollbar-width: none;
      -ms-overflow-style: none;
    }
    *::-webkit-scrollbar { display: none; }

    .sidebar-spacer {
      flex: 0 0 auto;
      min-height: 6px;
    }

    .app.sidebar-hidden .sidebar {
      width: 0;
      padding-left: 0;
      padding-right: 0;
      opacity: 0;
      pointer-events: none;
      transform: translateX(-12px);
    }

    /* ── 非固定态（临时展开）浮层化：2026-09-10 用户需求 ──
       受本机开关「浮层导航」控制（桌面右键菜单「开启/关闭浮层导航」，默认开启）；
       关闭时不加 .sidebar-float，即回到原「占位式」非固定态（临时展开把内容整体右推）。
       固定态（full/icon，经点 logo / 循环条 / Ctrl+Win 持久化）逻辑不变，仍按网格列占位；
       开启时，非固定态（hidden/icon 下点击左缘热区、循环条、Ctrl+Win 的临时展开）改为浮层：
       --sidebar-width 保持"进入前的固定态列宽"（0px=全折叠 / 88px=仅图标），
       侧栏自身取"全显示宽度"溢出该列、浮在内容之上 —— 不挤压也不位移页面（Win7 开始菜单效果）。
       侧栏仍留在网格里（position:relative 仅提升层级），故 .main 列宽不受影响。
       选择器前缀 html 压过 .high-res .app（L2185，特异性 0,2,0）对 --sidebar-width 的覆盖 */
    html .app.sidebar-float {
      --sidebar-width: var(--sidebar-float-w, 0px);
      --sidebar-gap: 0px;
    }
    .app.sidebar-float .sidebar {
      /* !important：需压过 @media(max-width:860px) 浏览器模式列布局（L7650 起，特异性 0,3,1）
         与移动端抽屉规则，保证任何缩放档位下临时浮层都以全宽浮出 */
      position: relative !important;
      justify-self: start;
      z-index: 70 !important;
      width: var(--sidebar-full-w, 190px) !important;
      min-width: var(--sidebar-full-w, 190px) !important;
      border-radius: 0 14px 14px 0;
      box-shadow: 10px 0 38px rgba(0, 0, 0, .30);
      animation: ld-sidebar-float-in .16s ease-out;
    }
    @keyframes ld-sidebar-float-in {
      from { opacity: 0; transform: translateX(-14px); }
      to   { opacity: 1; transform: translateX(0); }
    }

    .sidebar-cycle-rail {
      position: fixed;
      left: 0;
      top: 80%;
      transform: translateY(-50%);
      width: 13px;
      height: 96px;
      z-index: 80;
      border: 1px solid var(--sidebar-border);
      border-left: 0;
      border-radius: 0 14px 14px 0;
      background: linear-gradient(180deg, var(--panel-soft), var(--panel));
      color: var(--primary);
      display: inline-flex;
      align-items: center;
      justify-content: center;
      cursor: pointer;
      box-shadow: 8px 0 24px rgba(0,0,0,.14), 0 0 18px var(--glow-primary);
      backdrop-filter: blur(12px);
      transition: width .2s ease, background .2s ease, color .2s ease, box-shadow .2s ease;
    }

    .sidebar-cycle-rail:hover {
      width: 14px;
      color: #fff;
      background: linear-gradient(180deg, var(--primary), var(--accent-2));
      box-shadow: 10px 0 26px rgba(0,0,0,.18), 0 0 24px var(--glow-primary);
    }

    .sidebar-cycle-rail span {
      display: inline-block;
      font-size: 12px;
      line-height: 1;
      transform: rotate(0deg);
      transition: transform .2s ease;
      user-select: none;
    }

    .app.sidebar-hidden .sidebar-cycle-rail span {
      transform: rotate(180deg);
    }

    /* 独立全透明热区：满高 20px，仅侧边栏隐藏时可点击，显示后隐藏不挡页面 */
    .sidebar-hot-zone {
      position: fixed;
      left: 0;
      top: 0;
      width: 20px;   /* 2026-09-01 用户：15px → 20px */
      height: 100vh;
      z-index: 75;
      background: transparent;
      cursor: pointer;
      pointer-events: none;
      transition: opacity .2s ease;
    }
    .app.sidebar-hidden .sidebar-hot-zone {
      pointer-events: auto;
    }

    /* 左下 60×60 热区（2026-09-11 用户）：侧栏「全折叠」时，悬停=呼出悬浮系统设置、
       点击=等同 Alt+Win 切换；侧栏可见（全显示/仅图标）时关 pointer-events，点击/悬停都不生效。
       z-index 90：压过左缘热区(75)与切换拉手(80)，左下角归本热区 */
    .sidebar-settings-hotzone {
      position: fixed;
      left: 0;
      bottom: 0;
      width: 60px;
      height: 60px;
      z-index: 90;
      background: transparent;
      pointer-events: none;
    }

    .app.sidebar-hidden .sidebar-settings-hotzone {
      pointer-events: auto;
      cursor: pointer;
    }

    .brand {
      display: flex;
      gap: 4px;
      align-items: center;
      justify-content: center;
      padding: 1px 0 15px;
      border-bottom: 1px solid var(--sidebar-border);
      margin-top: -10px;
      margin-left: 0;
    }
    .brand img, .brand svg { margin-left: 0; }

    .logo {
      width: 73px;
      height: 73px;
      display: block;
      position: relative;
      overflow: visible;
      flex: 0 0 73px;
      background: none;
      box-shadow: none;
    }

    .logo::before,
    .logo::after {
      display: none;
    }

    .logo svg {
      position: absolute;
      inset: 0;
      width: 100%;
      height: 100%;
      z-index: 1;
      overflow: visible;
      filter: none;
    }

    .logo-orbit,
    .logo-arc,
    .logo-bar,
    .logo-rib,
    .logo-node-ring {
      fill: none;
      stroke-linecap: round;
      stroke-linejoin: round;
    }

    .logo-orbit {
      stroke: rgba(255,255,255,.92);
      stroke-width: 4.2;
      stroke-dasharray: 54 14;
      transform-origin: 24px 24px;
      transform: rotate(-28deg);
    }

    .logo-arc {
      stroke: rgba(255,255,255,.52);
      stroke-width: 3;
    }

    .logo-bar {
      stroke: url(#logoBeamGradient);
      stroke-width: 7;
    }

    .logo-bar.logo-bar-soft {
      stroke: rgba(255,255,255,.44);
      stroke-width: 4.2;
    }

    .logo-rib {
      stroke: rgba(4, 20, 28, .54);
      stroke-width: 1.8;
    }

    .logo-node {
      fill: rgba(255,255,255,.94);
    }

    .logo-node-ring {
      stroke: rgba(255,255,255,.46);
      stroke-width: 2.3;
    }

    .logo-spark {
      fill: rgba(255,255,255,.88);
      opacity: .92;
    }

    .brand h1 {
      margin: 0;
      line-height: 1.05;
      display: flex;
      flex-direction: column;
      gap: 12px;
    }
    .brand-line {
      display: block;
      white-space: nowrap;
      user-select: none !important;
      -webkit-user-select: none !important;
      -moz-user-select: none !important;
      -ms-user-select: none !important;
      -webkit-tap-highlight-color: transparent;
      -webkit-touch-callout: none;
    }
    .brand-text,
    .brand-text h1 {
      user-select: none !important;
      -webkit-user-select: none !important;
      -moz-user-select: none !important;
      -ms-user-select: none !important;
      -webkit-tap-highlight-color: transparent;
      -webkit-touch-callout: none;
    }
    .brand-line-main {
      font-size: 21px !important;
      font-weight: 900;
      letter-spacing: .04em;
      color: var(--sidebar-text);
      text-shadow: 0 3px 12px rgba(0,0,0,.18);
    }
    .brand-line-sub {
      display: inline-flex;
      align-items: center;
      gap: 5px;
      font-size: 12px !important;
      font-weight: 800;
      color: var(--sidebar-muted);
      letter-spacing: .08em;
    }
    .brand-line-sub em {
      color: #061922;
      background: linear-gradient(135deg, var(--primary), var(--accent-2));
      border-radius: 999px;
      padding: 2px 7px 2px 8px;
      font-size: 12px;
      font-style: normal;
      letter-spacing: .04em;
      box-shadow: 0 6px 14px var(--glow-primary);
      cursor: pointer;
      transition: transform .15s ease;
      line-height: 1;
      display: inline-flex;
      align-items: center;
    }
    .brand-line-sub em:active { transform: scale(.88); }
    .brand-text, .nav-label, .nav-title, .side-card, .sidebar-tool-title, .sidebar-tool-text { transition: opacity .15s ease, width .2s ease, margin .2s ease; }

    .app.sidebar-icon .sidebar { padding: 17px 9px; }
    .app.sidebar-icon .brand {
      justify-content: center;
      gap: 0;
      padding-left: 0;
      padding-right: 0;
    }
    .app.sidebar-icon .brand-text,
    .app.sidebar-icon .nav-label,
    .app.sidebar-icon .nav-title,
    .app.sidebar-icon .side-card,
    .app.sidebar-icon .sidebar-tool-title,
    .app.sidebar-icon .sidebar-tool-text {
      opacity: 0;
      width: 0;
      height: 0;
      margin: 0;
      padding: 0;
      overflow: hidden;
      pointer-events: none;
    }

    .app.sidebar-icon .sidebar-footer {
      padding: 0;
      border: 0;
      background: transparent;
      gap: 10px;
      align-items: center;
      margin-top: 0;
    }

    .app.sidebar-icon .sidebar-theme-select {
      width: 44px;
      min-width: 44px;
      height: 44px;
      padding: 0;
      color: transparent;
      font-size: 0;
      border-radius: 15px;
      background: var(--sidebar-icon-bg);
      background-image: none;
    }

    .app.sidebar-icon .sidebar-logout-btn {
      width: 44px;
      height: 44px;
      padding: 0;
      border-radius: 15px;
    }

    .app.sidebar-icon .sidebar-main {
      overflow: visible;
      padding-right: 0;
    }

    .app.sidebar-icon .sidebar-spacer { min-height: 144px; }
    .app.sidebar-icon .nav { margin-top: 18px; }
    .app.sidebar-icon .nav button {
      justify-content: center;
      gap: 0;
      padding: 13px 0;
    }
    .app.sidebar-icon .nav .icon {
      width: 34px;
      height: 34px;
      font-size: 16px;
    }

    .nav-title {
      margin: 4px 8px 21px;
      padding-left: 5px;
      color: var(--sidebar-muted);
      font-size: 9px !important;
      letter-spacing: .08em;
      display: flex;
      flex-direction: column;
      gap: 2px;
      min-height: 55px;
      justify-content: center;
    }
    .nav-title .nt-user {
      font-size: 10px !important;
      font-weight: 700;
      color: var(--sidebar-text);
      letter-spacing: .02em;
    }
    .nav-title .nt-user:empty::before {
      content: '\200B';
    }
    .nav-title .nt-greeting {
      font-size: 8px !important;
      color: var(--sidebar-muted);
      letter-spacing: .04em;
    }
    .nav-title .nt-greeting:empty::before {
      content: '\200B';
    }
    .nav-title .nt-datetime {
      font-size: 11px !important;
      color: var(--sidebar-muted);
      letter-spacing: .02em;
      white-space: pre;
      transform: translateY(-5px);
    }
    .nav-title .nt-datetime:empty::before {
      content: '\200B';
    }

    .nav button {
      width: calc(100% - 2px); /* 2026-08-31 用户要求标签宽度-2px：与容器左右各留1px */
      border: 0;
      color: var(--sidebar-text);
      background: transparent;
      display: flex;
      align-items: center;
      gap: 11px;
      padding: 8px 11px;
      margin: 2px 1px; /* 2026-08-31 用户要求标签宽度-2px：左右各+1px外边距 */
      border-radius: 11px;
      cursor: pointer;
      font-size: 17px !important;
      text-align: left;
      white-space: nowrap;
      min-height: 42px;
      transition: .15s;
    }

    .nav-label { display: inline-block; overflow: hidden; }
    .nav-label.editing,
    .pw-nav-label.editing { display: none; }
    .nav-edit-input {
      display: none;
      background: transparent;
      border: 1px solid var(--primary);
      border-radius: 4px;
      color: inherit;
      font-size: inherit;
      padding: 0 4px;
      width: 100%;
      outline: none;
      box-sizing: border-box;
    }
    .nav-edit-input.show { display: block; }

    .nav button:focus-visible { outline: none; }

    /* 共性问题：按 ESC/Tab 聚焦按钮时浏览器默认加黑边（右下角 AI 助手按钮等）。
       去掉所有按钮的键盘聚焦默认 outline；项目自定义的类高亮（如 .selected/.ifb-drop-target）不受影响。 */
    button:focus-visible { outline: none; }

    .nav button:hover,
    .nav button.active {
      background: var(--sidebar-hover);
      color: #fff;
    }
    .nav button.active {
      font-size: 21px !important;
    }
    .nav button.active .icon {
      width: 33px;
      height: 33px;
      font-size: 20px !important;
    }

    /* 导航拖拽排序 */
    .drag-btn { cursor: grab; }
    .drag-btn:active { cursor: grabbing; }
    .drag-btn.dragging { opacity: .45; }
    .drag-btn.drag-over {
      border-top: 2px solid var(--primary);
      border-radius: 11px 11px 0 0;
    }

    .nav .icon {
      width: 33px;
      height: 33px;
      border-radius: 8px;
      background: var(--sidebar-icon-bg);
      display: grid;
      place-items: center;
      font-size: 17px;
      flex-shrink: 0;
    }

    .nav-placeholder {
      width: 100%;
      min-height: 38px;
      margin: 3px 0;
      border: 2px dashed transparent;
      border-radius: 11px;
      background: transparent;
      transition: border-color .2s, background .2s;
      pointer-events: auto;
    }
    .nav-placeholder.drag-over {
      border-color: var(--primary);
      background: color-mix(in srgb, var(--primary) 10%, transparent);
    }

    .app.sidebar-icon .nav-placeholder,
    .app.sidebar-hidden .nav-placeholder { display: none; }

    .side-card {
      margin-top: 16px;
      padding: 11px;
      border-radius: 13px;
      background: var(--sidebar-card-bg);
      border: 1px solid var(--sidebar-border);
    }

    .side-card b { color: var(--sidebar-text); }
    .side-card p { margin: 8px 0 14px; color: var(--sidebar-muted); font-size: 10px; line-height: 1.6; }

    .sidebar-footer {
      flex: 0 0 auto;
      margin-top: 0;
      margin-bottom: 0;
      padding: 11px 26px 17px;
      border-radius: 13px;
      background: var(--sidebar-card-bg);
      border: 1px solid var(--sidebar-border);
      display: grid;
      gap: 8px;
      transition: opacity .18s ease, width .2s ease, margin .2s ease, padding .2s ease, background .2s ease, border-color .2s ease, all .2s ease;
    }

    .sidebar-tool-title {
      color: var(--sidebar-muted);
      font-size: 11px;
      letter-spacing: .08em;
      white-space: nowrap;
      cursor: pointer;
      user-select: none;
      display: flex;
      align-items: center;
      gap: 6px;
    }
    /* ★★ 2026-10-10（用户）："左导航栏左下角那个**消息栏**（按钮 + 卡片）不要了；**系统设置照旧**；
       以前折叠起来显示的是消息栏，**现在折叠以后就显示「系统设置」这 4 个字**。"
       ⚠ 原来折叠态是**整块 display:none** —— 而左下角那块地方**以前全靠消息栏卡片撑着**
         （这正是上一次"撤掉消息栏 ⇒ 底部变空、连系统设置也点不出来"的原因）
       ⇒ 折叠态改为**只留标题那一行**（即「系统设置」四个字）：其余项隐藏。
         ` .sidebar-bottom ` 上那对 hover 展开 / 移出折叠（`lingdu-core.js`）绑的是容器 ⇒ 照旧生效；
         点这行标题本身也仍可展开（模板里它的 onclick = `toggle('collapsed')`，一字未动）。 */
    .sidebar-footer.collapsed {
      padding-top: 11px;
      padding-bottom: 11px;   /* 只剩一行 ⇒ 上下对称（原来的 17px 是给多行时用的） */
    }
    .sidebar-footer.collapsed > *:not(.sidebar-tool-title) {
      display: none;
    }
    /* ★ 2026-10-14（用户）：折叠态只留「系统设置」四个字 ——
       ① 去掉标题左边那个图标按钮（`.sidebar-tool-title::before` 的 🔧）；
       ② 文字居中；③ 字号 +3px（**仅折叠态**，展开态一律不动）。 */
    .sidebar-footer.collapsed .sidebar-tool-title {
      justify-content: center;
      font-size: 14px;   /* 基准 11px + 3px */
    }
    .sidebar-footer.collapsed .sidebar-tool-title::before {
      content: none;
    }

    .sidebar-theme-select {
      width: 100%;
      height: 27px;
      border: 1px solid var(--sidebar-border);
      border-radius: 10px;
      background: color-mix(in srgb, var(--sidebar-card-bg) 72%, var(--bg-deep) 28%);
      color: var(--sidebar-text);
      padding: 0 12px;
      outline: none;
      cursor: pointer;
      font-size: 11px;
      font-weight: 700;
      text-align: center;
      box-shadow: inset 0 1px 0 rgba(255,255,255,.08), 0 8px 18px rgba(0,0,0,.08);
      -webkit-text-fill-color: var(--sidebar-text);
    }

    .sidebar-theme-select:focus {
      border-color: var(--primary);
      box-shadow: 0 0 0 3px var(--primary-soft);
    }

    .sidebar-theme-select option {
      background: var(--panel);
      color: var(--text);
    }

    .project-card-head {
      display: flex;
      align-items: flex-start;
      justify-content: space-between;
      gap: 10px;
    }

    .project-card-head b {
      line-height: 1.4;
      min-width: 0;
    }

    .project-status {
      flex: 0 0 auto;
      padding: 4px 7px;
      border-radius: 999px;
      background: var(--sidebar-hover);
      color: var(--sidebar-text);
      border: 1px solid var(--sidebar-border);
      font-size: 8px;
      font-weight: 800;
      white-space: nowrap;
    }

    .project-stage-list {
      display: grid;
      grid-template-columns: 1fr 1fr;
      gap: 7px;
      margin: 12px 0 14px;
    }

    .project-stage-list button {
      border: 1px solid var(--sidebar-border);
      border-radius: 11px;
      background: rgba(255,255,255,.06);
      color: var(--sidebar-muted);
      padding: 7px 6px;
      font-size: 8px;
      font-weight: 800;
      cursor: pointer;
    }

    .project-stage-list button.active {
      color: var(--sidebar-text);
      background: var(--sidebar-hover);
      box-shadow: inset 0 1px 0 rgba(255,255,255,.08);
    }


    /* ════════ 结算定审页（参照项目工程布局）════════ */
    .stl-card-wrap {
      position: relative;
      overflow: hidden;
      border-radius: 24px;
      border: 1px solid var(--line);
      background: var(--panel);
      flex: 1;
      min-height: 0;
      display: flex;
      flex-direction: column;
    }

    .stl-page-grid {
      display: flex;
      flex-direction: column;
      flex: 1;
      padding: 0 15px 0;
      min-height: 0;
      position: relative;
    }

    .stl-rows-scroll {
      flex: 1;
      overflow-y: auto;
      min-height: 0;
      position: relative;
      padding: 0 0 20px;
    }

    .stl-sticky-header {
      position: sticky;
      top: 0;
      z-index: 10;
      padding: 8px 0 4px;
      margin-bottom: 7px;
    }
    /* 结算定审(#inventory)二级导航高度位置对齐预算翻样(.mat-tabs)：
       去掉 .stl-sticky-header 顶部 8px 内边距，使标签栏顶端与预算翻样一致。 */
    #inventory .stl-sticky-header {
      padding: 0 0 4px;
    }

    .stl-group-tabs {
      display: flex;
      gap: 8px;
      padding: 10px 0 14px;
      flex-wrap: wrap;
      align-items: center;
    }
    /* 结算定审(#inventory)：去底层容器框 + 二级导航对齐预算翻样(.mat-tabs)。
       .stl-card-wrap 被 #inventory 与 #recycle_bin 共用，只能用 #inventory 作用域限定。 */
    #inventory .stl-card-wrap {
      border: none;
      border-radius: 0;
      background: transparent;
      overflow: visible;
    }
    #inventory .stl-group-tabs {
      padding: 0;
      margin-bottom: 16px;
    }
    /* 结算定审(#inventory)：二级导航第一个标签左起始位置对齐预算翻样(.mat-tabs)。
       .stl-page-grid 有 0 15px 左右内边距，去掉左侧 15px 使首个标签与预算翻样对齐（2026-08-31 用户要求） */
    #inventory .stl-page-grid {
      padding-left: 0;
    }
    /* ══ 二级导航按钮的**纵向几何**（物理像素口径）—— 2026-10-04 用户实测定案，见《开发要求》
       「文字在按钮/胶囊里"上下飘" ⇒ 小按钮纵向几何一律按物理像素给」硬规则 ══
       `N 物理像素 = calc(Npx / var(--ld-zoom, 1))`（与"1 物理像素边框"同一口径）。
       ⚠ **高度必须落在"偶数额物理像素"上**：盒子有对称的内边距+边框 ⇒ 盒子中心 = 高/2（38/2 = 19 整数）
         ⇒ 文字（`align-items:center`）的理想中心落在整数物理像素上 ⇒ 不再随窗口大小跳 1px。
       取值 = 改造前 `CSS px × 当时 zoom(0.91875)` 四舍五入：41→38、8→7、6→6、1→1 ⇒ **观感不变**。 */
    :root {
      /* ⚠⚠ 2026-10-12 修正（用户："料单审核 4 级页左上角那 4 个二级按钮（返回 + 三个子档），
         在手机/平板上**特别高**"）—— 本轮**踩了《开发要求》里那条坑**：
         `calc(Npx / var(--ld-zoom,1))` 的物理含义 = **恒定物理尺寸** ⇒ 只适合**线条/边框**；
         用在**尺寸（高度/内边距）**上，手机/低档位 `--ld-zoom` 很小 ⇒ 除以它 ⇒ 按钮被放得**很高**
         （如 --ld-zoom=0.5 时 38/0.5 = **76px**）。
         ⇒ 下面 3 个**尺寸**量一律回 **CSS px**（随档位缩放）= 2026-10-04 改造前的原值 41/8/6，
           观感不变（41 × 0.91875 ≈ 37.7 ≈ 原钉出来的 38）。
         ⚠ `--nav-tab-bd`（边框）**保留**物理像素口径：线宽就该恒为 1 物理像素 —— 这里用对了。 */
      --nav-tab-h:      41px;   /* 原 calc(38px / var(--ld-zoom,1)) —— 尺寸不能钉物理像素（手机会很高） */
      --nav-tab-pad:    8px;    /* 原 calc(7px  / var(--ld-zoom,1)) */
      --nav-tab-pad-on: 6px;    /* 原 calc(6px  / var(--ld-zoom,1)) */
      --nav-tab-bd:     calc(1px  / var(--ld-zoom, 1));   /* 1 物理像素边框：线条口径，正确，保留 */
    }
    /* 二级导航（结算定审顶部标签按钮，标准同项目工程 .project-group-tab） */
    .stl-group-tab {
      display: inline-flex;
      align-items: center;
      gap: 6px;
      padding: var(--nav-tab-pad) 16px;
      border-radius: 12px;
      border: var(--nav-tab-bd) solid var(--line);
      background: var(--panel);
      color: var(--text);
      font-size: 19px;
      font-weight: 600;
      height: var(--nav-tab-h);   /* 固定高度（物理像素）：基础态/选中态一致；⚠ 见上面 :root 那段 */
      line-height: 1;             /* 行高=字号，配合 align-items:center 精确垂直居中 */
      cursor: pointer;
      transition: background .2s, color .2s, border-color .2s, box-shadow .2s;
      user-select: none;
    }
    .stl-group-tab:hover {
      background: var(--primary-soft);
      border-color: var(--primary);
    }
    .stl-group-tab.active {
      background: color-mix(in srgb, var(--primary) 18%, transparent);
      color: var(--primary);
      border-color: var(--primary);
      box-shadow: 0 4px 12px color-mix(in srgb, var(--primary) 30%, transparent);
      font-size: 21px;                              /* 选中态文字+2px（基准 19→21） */
      padding: var(--nav-tab-pad-on) var(--tabpad, 8px);   /* 左右 padding 按字数补偿，按钮不加宽 */
    }
    .stl-group-tab .tab-count {
      font-size: 11px;
      opacity: .7;
      font-weight: 400;
    }
    .stl-group-tab.active .tab-count {
      opacity: .85;
    }

    /* ════ 工作汇报页顶部按钮：大小/高度/位置与预算翻样顶部 .mat-tab 完全一致 ════ */
    #cat-report .stl-group-tabs {
      display: flex;
      gap: 8px;
      flex-wrap: wrap;
      margin-bottom: 16px;
      padding: 0;
    }
    #cat-report .stl-group-tab {
      gap: 6px;
      padding: 8px 16px;
      border-radius: 12px;
    }
    /* 工作汇报二级导航选中态：同样「文字+2px 但按钮不加宽」（覆盖 #cat-report 的 padding 优先级） */
    #cat-report .stl-group-tab.active {
      font-size: 21px;
      padding: 6px var(--tabpad, 8px);
    }

    /* ════ 钢筋接头量整页（预算翻样内）：顶部按钮与预算翻样 .mat-tab 完全一致（2026-08-31）═══ */
    #cbdJointPage .stl-group-tabs {
      display: flex;
      gap: 8px;
      flex-wrap: wrap;
      margin-bottom: 16px;
      padding: 0;
      /* 接头量 4 表的「导航行」——本行同 `#constructionBudget .mat-tabs` 一样要当视图级挂件的定位基准：
         .cb-top-summary（右上角计算式，margin-left:auto 右对齐）与 .cb-hscroll（水平滚动条，absolute + top:100%）
         都 append 到本行；少了 position:relative，绝对定位的滚动条会改以更外层容器为基准而跑位。2026-09-15 */
      position: relative;
    }
    #cbdJointPage .stl-group-tab {
      gap: 6px;
      padding: 8px 16px;
      border-radius: 12px;
    }
    /* 接头量二级导航选中态：同样「文字+2px 但按钮不加宽」 */
    #cbdJointPage .stl-group-tab.active {
      font-size: 21px;
      padding: 6px var(--tabpad, 8px);
    }
    /* 进入钢筋接头量整页时隐藏预算翻样主界面（mat-tabs + 各 pane + 建设中占位） */
    #constructionBudget.joint-open .mat-tabs,
    #constructionBudget.joint-open > .cbd-pane,
    #constructionBudget.joint-open > #cbd-pending {
      display: none;
    }
    /* 接头量分类占位（参照工作汇报 .ppt-empty） */
    #cbdJointPage .joint-empty {
      padding: 46px 20px;
      text-align: center;
      color: var(--muted);
      font-size: 14px;
      background: var(--panel);
      border: 1px dashed var(--line);
      border-radius: 12px;
      line-height: 1.9;
    }
    #cbdJointPage .joint-empty b {
      display: block;
      font-size: 17px;
      color: var(--text);
      margin-bottom: 2px;
    }

    /* ════ 材料计划整页（钢筋物资内）：顶部按钮与钢筋接头量整页完全一致（2026-09-01，对标 Bug #2）═══ */
    #matPlanPage .stl-group-tabs {
      display: flex;
      gap: 8px;
      flex-wrap: wrap;
      margin-bottom: 16px;
      padding: 0;
    }
    #matPlanPage .stl-group-tab {
      gap: 6px;
      padding: 8px 16px;
      border-radius: 12px;
    }
    /* 材料计划二级导航选中态：同样「文字+2px 但按钮不加宽」 */
    #matPlanPage .stl-group-tab.active {
      font-size: 21px;
      padding: 6px var(--tabpad, 8px);
    }
    /* 进入材料计划整页时隐藏钢筋物资主界面（mat-tabs + 各 mat-pane + 建设中占位） */
    #trace.joint-open .mat-tabs,
    #trace.joint-open > .mat-pane,
    #trace.joint-open > #mat-pending {
      display: none;
    }
    /* 材料计划分类占位（参照钢筋接头量 .joint-empty） */
    #matPlanPage .joint-empty {
      padding: 46px 20px;
      text-align: center;
      color: var(--muted);
      font-size: 14px;
      background: var(--panel);
      border: 1px dashed var(--line);
      border-radius: 12px;
      line-height: 1.9;
    }
    #matPlanPage .joint-empty b {
      display: block;
      font-size: 17px;
      color: var(--text);
      margin-bottom: 2px;
    }

    .stl-search-box {
      display: flex;
      align-items: center;
      gap: 8px;
      margin-left: auto;
    }
    .stl-search-input {
      padding: 8px 14px;
      border-radius: 10px;
      border: 1px solid var(--line);
      background: var(--panel);
      color: var(--text);
      font-size: 14px;
      width: 200px;
      height: 41px; /* 2026-09-03 与二级导航按钮同高 41px */
      outline: none;
    }
    .stl-search-input:focus {
      border-color: var(--primary);
    }

    .stl-group-row {
      display: grid;
      grid-template-columns: repeat(auto-fit, 280px);
      gap: 15px;
      min-height: 60px;
      padding: 9px 6px 20px;
      overflow-y: visible;
      justify-content: center;
    }
    .stl-group-row.stl-hidden {
      display: none;
    }
    .stl-group-empty {
      grid-column: 1 / -1;
      text-align: center;
      color: var(--muted);
      font-size: 13px;
      padding: 40px 0;
    }

    /* ════════ 项目回收站（2026-08-24，见 测试和日志/双向同步架构.md 第八节）════════ */
    /* 2026-09-03 用户：顶栏操作按钮并入结算定审同款 .stl-group-tab 一行；计数并入搜索行左侧小字 */
    /* 2026-09-03 用户：回收站操作按钮改用结算定审同款 .stl-group-tab 样式并入顶行；
       危险操作(彻底删除/清空)用 .rb-danger 红色变体 */
    /* 2026-09-03 用户：顶部"彻底删除/清空回收站"按钮配色改为与行内操作列"彻底删除"(.btn.danger)
       完全一致——浅红底 var(--btn-danger-bg) + 危险字色 var(--btn-danger-text)（随主题切换），
       不再用写死的实心红底白字 */
    .stl-group-tab.rb-danger {
      color: var(--btn-danger-text);
      background: var(--btn-danger-bg);
      border-color: var(--btn-danger-bg);
    }
    .stl-group-tab.rb-danger:hover {
      color: var(--btn-danger-text);
      background: var(--btn-danger-bg);
      border-color: var(--btn-danger-bg);
      filter: brightness(1.08);
    }
    /* 危险变体禁选时文字不放大：与基础态一致（同 .stl-group-tab.active 防抖原理） */
    .stl-group-tab.rb-danger.active,
    .stl-group-tab.rb-danger:active {
      font-size: 19px;
      padding: 8px 16px;
      color: var(--btn-danger-text);
      background: var(--btn-danger-bg);
      border-color: var(--btn-danger-bg);
      box-shadow: none;
    }
    .stl-group-tab[disabled],
    .stl-group-tab:disabled {
      opacity: .45;
      cursor: not-allowed;
      pointer-events: none;
    }
    /* 回收站搜索行计数（并入 .stl-search-box 左侧小字） */
    #recycle_bin .stl-search-box .rb-count {
      margin-right: 0;
      font-size: 13px;
      color: var(--muted);
      white-space: nowrap;
    }
    /* 2026-09-03 用户：回收站右上角搜索框加宽 50px（200 → 250px，仅回收站，不影响其它页面同款输入框） */
    #recycle_bin .stl-search-box .stl-search-input {
      width: 250px;
    }
    /* ════════ 回收站去容器（同结算定审 2026-08-31 逻辑，2026-09-03 用户要求）════════
       去掉 .stl-card-wrap 白卡容器(圆角/背景)，左右 15px → 0。
       2026-09-03 用户：边线只圈表格区(上边线在"名称/类型"表头行、左右边线同高处起始)，
       不框住顶部的操作按钮行。 */
    #recycle_bin .stl-card-wrap {
      border: none;
      border-radius: 0;
      background: transparent;
      overflow: visible;
    }
    #recycle_bin .stl-page-grid {
      padding: 0;
    }
    #recycle_bin .stl-sticky-header {
      padding: 0 0 4px;
    }
    #recycle_bin .stl-group-tabs {
      padding: 0;
      margin-bottom: 16px;
    }
    /* 表格区四周边线：上边线 = 表头"名称/类型"行顶部，左右边线同一高度起始；底部封口 */
    #recycle_bin .stl-rows-scroll {
      border: 1px solid var(--line);
    }
    .rb-table {
      width: 100%;
      border-collapse: collapse;
      font-size: 14px;
    }
    .rb-table th {
      text-align: left;
      padding: 10px 12px;
      font-size: 13px;
      color: var(--muted);
      font-weight: 600;
      white-space: nowrap;
    }
    .rb-table td {
      padding: 10px 12px;
      border-bottom: 1px solid var(--line);
      vertical-align: middle;
      word-break: break-all;
    }
    .rb-table tbody tr {
      cursor: pointer;   /* 2026-09-03 用户：整行点击可勾选，悬停提示可点 */
    }
    .rb-table tbody tr:nth-child(even) {
      background: color-mix(in srgb, var(--primary-soft, #eef4ff) 35%, transparent);
    }
    .rb-table tbody tr:hover {
      background: color-mix(in srgb, var(--primary-soft, #eef4ff) 60%, transparent);
    }
    .rb-table .rb-name {
      /* 2026-09-03 用户：名称列按内容动态加宽（上限约半屏），超长名称在列内折行完整展示，
         不再被原 320px 上限压窄而与第 2 列(删除类型)文字重叠 */
      min-width: 200px;
      max-width: 46%;
      white-space: normal;
      overflow-wrap: anywhere;
    }
    .rb-table .rb-origin {
      display: block;
      font-size: 12px;
      color: var(--muted);
      margin-top: 2px;
      word-break: break-all;
    }
    /* 2026-09-06 用户：勾选框列固定宽度，避免被 100% 宽度的表布局拉伸，
       使勾选框与名称列间距为 20px（勾选框单元格右 padding 8 + 名称列左 padding 12） */
    .rb-table th:first-child,
    .rb-table td:first-child {
      width: 40px;
      padding: 10px 8px 10px 12px;
    }
    .rb-table .rb-empty {
      text-align: center;
      color: var(--muted);
      padding: 40px 0;
      font-size: 14px;
    }
    .rb-table .rb-btn {
      padding: 4px 12px;
      font-size: 13px;
      line-height: 1.4;
    }
    .rb-table .rb-btn + .rb-btn {
      margin-left: 6px;
    }
    /* 已删除项目行（合并进回收站表格）的"项目删除"类型标签 */
    .rb-table .rb-type-proj {
      display: inline-block;
      padding: 1px 8px;
      border-radius: 10px;
      font-size: 12px;
      color: #fff;
      background: color-mix(in srgb, var(--muted) 80%, #000);
    }
    /* 回收站表头固定：滚动时表头不随内容滚动（2026-08-25） */
    /* 2026-09-03 用户修正：表头底线不能用 border-bottom——border-collapse 下
       表格线归整表绘制、不随 sticky 表头移动(滚动后停在第一条记录顶部/消失)。
       改在表头 th 上用背景渐变画 2px 底线，随 sticky 背景一起固定，
       滚动时始终贴在表头底部。 */
    .rb-table thead th {
      position: sticky;
      top: 0;
      z-index: 3;
      background-color: var(--bg);
      background-image: linear-gradient(var(--line), var(--line));
      background-size: 100% 2px;
      background-repeat: no-repeat;
      background-position: 0 100%;
    }
    /* 2026-09-03 用户：回收站页面文字（顶部按钮行除外）统一 16px */
    #recycle_bin .rb-table {
      font-size: 16px;
    }
    #recycle_bin .rb-table th,
    #recycle_bin .rb-table td,
    #recycle_bin .rb-table .rb-origin,
    #recycle_bin .rb-table .rb-empty,
    #recycle_bin .rb-table .rb-btn,
    #recycle_bin .rb-table .tag,
    #recycle_bin .rb-table .rb-type-proj {
      font-size: 16px;
    }
    /* 2026-09-03 用户：大小/状态独立列已移除——大小跟在文件名称后(.rb-size)；项目行缺失红标(.rb-inline-tag) */
    #recycle_bin .rb-size {
      margin-left: 8px;
      color: var(--muted);
      font-weight: 400;
    }
    #recycle_bin .rb-inline-tag {
      margin-left: 6px;
      padding: 0 8px;
      line-height: 1.5;
    }
    /* 2026-09-03 用户：删除时间两行（年月日/时分秒）；表头全选框与勾选框同步放大 35%（16→22px） */
    #recycle_bin .rb-del span {
      display: block;
      white-space: nowrap;
    }
    #recycle_bin .rb-del .rb-del-time {
      color: var(--muted);
      margin-top: 2px;
    }
    /* M1 版本时间线：同路径合并组头行 + 展开箭头 */
    #recycle_bin .rb-group-row {
      cursor: pointer;
      background: color-mix(in srgb, var(--primary-soft, #eef4ff) 25%, transparent);
    }
    #recycle_bin .rb-group-row td {
      border-bottom: 1px solid var(--line);
    }
    /* 需求②：展开箭头与行内勾选框等大（勾选框 22px） */
    #recycle_bin .rb-arrow {
      display: inline-flex;
      align-items: center;
      justify-content: center;
      width: 22px;
      height: 22px;
      font-size: 20px;
      line-height: 1;
      color: var(--primary);
      user-select: none;
      transform: translateY(1px);
    }
    #recycle_bin .rb-ver-row td {
      background: color-mix(in srgb, var(--bg) 60%, transparent);
    }
    /* 需求④：表头「全展开/全折叠时间线」按钮 */
    #recycle_bin .rb-toggle-all {
      margin-left: 10px;
      padding: 2px 10px;
      font-size: 13px;
      line-height: 1.5;
      color: var(--primary);
      background: var(--panel);
      border: 1px solid var(--line);
      border-radius: 8px;
      cursor: pointer;
      vertical-align: middle;
    }
    #recycle_bin .rb-toggle-all:hover {
      border-color: var(--primary);
      background: var(--primary-soft);
    }
    /* 2026-09-03 用户：表头全选框多次累进放大（16→22→25→27.5px），行内勾选框保持 22px */
    #recycle_bin #rbSelectAll {
      width: 27.5px;
      height: 27.5px;
      cursor: pointer;
      accent-color: var(--primary);
      transform: translateY(2px);   /* 2026-09-03 用户：全选框位置下移 2px */
    }
    /* 回收站自定义垂直滚动条：原生滚动条隐藏，右侧自绘滚动条（滚动时显示、停止后隐藏，同施工预算） */
    #rbScrollView {
      scrollbar-width: none;
    }
    #rbScrollView::-webkit-scrollbar {
      width: 0;
      height: 0;
      display: none;
    }
    .rb-vscroll {
      position: fixed;
      right: 6px;
      width: 11px;
      border-radius: 6px;
      background: transparent;
      z-index: 8;
      opacity: 0;
      transition: opacity .18s ease;
      cursor: pointer;
    }
    .rb-vscroll.rb-show {
      opacity: 1;
    }
    .rb-vscroll-thumb {
      position: absolute;
      left: 0;
      width: 12px;
      border-radius: 6px;
      background: color-mix(in srgb, var(--text) 45%, transparent);
      cursor: grab;
    }
    body.rb-vscroll-dragging,
    body.rb-vscroll-dragging .rb-vscroll-thumb {
      cursor: grabbing;
      user-select: none;
      -webkit-user-select: none;
    }
    .rb-check {
      width: 24px;   /* 2026-09-03 用户：行内勾选框 22 → 24px */
      height: 24px;
      cursor: pointer;
      accent-color: var(--primary);
    }

    /* ════════ 权限设置去容器（同回收站/结算定审 2026-08-31 逻辑，2026-09-03 用户要求）════════
       去掉 PERM_PANEL_HTML 最外层 .map-center 白卡容器(圆角/边框/背景 + 光斑装饰伪元素)，
       权限面板内部卡片直接平铺在页面背景上。布局(flex/column)保留。 */
    #permissions #permContainer .map-center {
      border: none;
      border-radius: 0;
      background: transparent;
      overflow: visible;
    }
    #permissions #permContainer .map-center::before,
    #permissions #permContainer .map-center::after {
      display: none;
    }

    .project-card-wrap {
      position: relative;
      overflow: hidden;
      border-radius: 24px;
      border: 1px solid var(--line);
      background: var(--panel);
      flex: 1;
      min-height: 0;
      display: flex;
      flex-direction: column;
    }
    .project-card-wrap::before {
      content: '';
      position: absolute;
      top: 100px; left: 0; right: 0; bottom: -300px;
      background:
        radial-gradient(ellipse 70% 35% at 25% 35%, var(--bg-spot-b), transparent 78%),
        radial-gradient(ellipse 55% 30% at 42% 28%, var(--bg-spot-a), transparent 76%),
        radial-gradient(ellipse 60% 38% at 58% 32%, var(--bg-spot-b), transparent 78%),
        radial-gradient(ellipse 80% 32% at 78% 38%, var(--bg-spot-a), transparent 78%),
        radial-gradient(ellipse 50% 28% at 35% 50%, var(--bg-spot-b), transparent 74%),
        radial-gradient(ellipse 65% 30% at 65% 55%, var(--bg-spot-a), transparent 76%);
      opacity: .50;
      pointer-events: none;
      z-index: 0;
    }
    .project-card-wrap::after {
      content: '';
      position: absolute;
      top: 100px; left: 0; right: 0; bottom: -300px;
      background:
        radial-gradient(ellipse 45% 22% at 15% 42%, var(--bg-spot-b), transparent 74%),
        radial-gradient(ellipse 50% 25% at 50% 22%, var(--bg-spot-a), transparent 76%),
        radial-gradient(ellipse 55% 28% at 85% 30%, var(--bg-spot-b), transparent 74%);
      opacity: .30;
      pointer-events: none;
      z-index: 0;
    }
    .project-card-wrap > * { position: relative; z-index: 1; min-height: 0; }

    .project-page-grid {
         display: flex;
         flex-direction: column;
         flex: 1;
         padding: 0 15px 0;
         min-height: 0;
         position: relative;
       }

    .project-rows-scroll {
      flex: 1;
      overflow-y: auto;
      min-height: 0;
      position: relative;
      padding: 0 0 20px;
    }

    /* 冻结头部：tab 按钮 + 描述滚动�?*/
    .project-sticky-header {
      position: sticky;
      /* -18px 负偏移使标签顶部贴合容器顶部，与工作日报标签对齐（实测两处 top 均为 16px）。
         顶部裁边由项目工程容器 overflow:visible 解决（见贴边作用域），不在此加正 padding。 */
      top: -18px;
      z-index: 10;
      padding: 8px 0 4px;
      margin-top: -18px;
      margin-bottom: 7px;
    }

    /* 描述滚动�?*/
    .project-desc-bar {
      display: flex;
      align-items: center;
      gap: 10px;
      padding: 6px 14px;
      min-height: 32px;
      border-radius: 10px;
      background: var(--primary-soft);
      font-size: 13px;
      color: var(--text);
      margin-top: 6px;
    }
    .project-desc-bar .desc-label {
      flex-shrink: 0;
      font-weight: 700;
      color: var(--primary);
      font-size: 12px;
    }
    .project-desc-bar .desc-text {
      flex: 1;
      overflow: hidden;
      white-space: nowrap;
      text-overflow: ellipsis;
    }
    .project-desc-bar .desc-nav {
      flex-shrink: 0;
      font-size: 11px;
      color: var(--muted);
    }
    .drag-mode-btn {
      flex-shrink: 0;
      font-size: clamp(11px, 0.55vw, 14px) !important;
      padding: 1px 10px;
      height: var(--ifb-ctl-h, 24px);
      border-radius: clamp(8px, 0.47vw, 12px);
      border: 1px solid var(--primary);
      background: var(--primary-soft);
      color: var(--primary);
      cursor: pointer;
      transition: all .2s;
      line-height: 1;
    }
    .drag-mode-btn:hover {
      border-color: var(--primary);
      background: var(--primary-soft);
      color: var(--primary);
    }

    .project-group-row {
      /* 2026-09-02 同行等分：flex 换行 + space-evenly，一行放满 N 个后
         卡片间距按该行等分（不再写死列距）；行间距=列间距、末行占位靠左由 JS 补充 */
      display: flex;
      flex-wrap: wrap;
      justify-content: space-evenly;
      gap: 15px;
      min-height: 60px;
      padding: 9px 6px 20px;
      overflow-y: visible;
    }
    .project-group-row.drag-over {
      background: color-mix(in srgb, var(--primary, #36f) 6%, transparent);
      border-radius: 12px;
    }

    /* 地图分组行独立布局，不参与卡片网格 */
    .project-group-row[data-group="map"] {
      display: block;
      width: 100%;
      padding: 0;
      border: none;
      background: transparent;
      min-height: 0;
      flex: 1;
      overflow: hidden;
      height: 100%;
    }
    .project-group-row[data-group="map"] > * {
      width: 100%;
      margin: 0;
      height: 100%;
      min-height: 0;
    }

    .project-overview-card {
      width: 322.4px;
      height: 257.92px;
      flex-shrink: 0;
      padding: 12px;
      border-radius: 14px;
      background: var(--card-gradient);
      border: 1px solid var(--line);
      box-shadow: none;
      position: relative;
      overflow: hidden;
      display: flex;
      flex-direction: column;
      cursor: grab;
      transition: transform .2s, border-color .2s;
    }
    .project-overview-card:active { cursor: grabbing; }
    .project-overview-card.dragging {
      transform: scale(.95);
      border-color: var(--primary);
    }
    .project-overview-card.selected {
      border-color: var(--primary);
      background: color-mix(in srgb, var(--primary) 10%, transparent);
      outline: 2px solid var(--primary);
      outline-offset: -1px;
      box-shadow: 0 0 10px var(--primary);
    }
    .project-overview-card.selected:hover {
      transform: none;
    }
    .project-overview-card:hover {
      transform: translateY(-2px) scale(1.03); /* 2026-09-02 悬停轻微放大 1.03（同缩略图卡片） */
      box-shadow: none;
    }
    .project-overview-card.dragging:hover { transform: scale(.95); }
    /* 2026-09-02 框选(.proj-selection-box 拖拽)期间禁止卡片悬停放大，命中高亮 .proj-box-hl 不受影响 */
    body:has(.proj-selection-box) .project-overview-card:hover { transform: none !important; }

    /* 占位符：保持网格结构，允许自由放置卡�?*/
    .project-grid-placeholder {
      width: 322.4px;
      height: 257.92px;
      flex-shrink: 0;
      border-radius: 14px;
      border: 2px dashed transparent;
      transition: border-color .2s, background .2s;
      position: relative;
    }
    .project-grid-placeholder.drag-over {
      border-color: var(--primary, #36f);
      background: color-mix(in srgb, var(--primary, #36f) 8%, transparent);
    }
    .project-group-row.content-mode .project-grid-placeholder {
      min-height: 46px;
      height: 46px;
      width: 100%;
    }

    .project-overview-head {
      position: relative;
      z-index: 1;
      display: flex;
      justify-content: space-between;
      align-items: flex-start;
      gap: 12px;
      margin-bottom: 14px;
    }

    .project-overview-head h3 {
      margin: 0;
      color: var(--text);
      font-size: 15px;
      line-height: 1.3;
    }

    .project-overview-card p, .card-desc {
      position: relative;
      z-index: 1;
      margin: 0 -4px 6px;
      color: var(--muted);
      line-height: 1.5;
      font-size: 12px;
      cursor: text;
      padding: 5px 3px 3px 3px;
      border-radius: 6px;
      border: 1px solid transparent;
      transition: border-color .2s, background .2s;
      flex: 1;
    }
    .project-overview-card p:hover, .card-desc:hover {
      border-color: var(--line);
      background: var(--panel-soft);
    }
    .project-overview-card p:focus, .card-desc[contenteditable="true"] {
      outline: none;
      border-color: var(--primary);
      background: var(--panel-soft);
      color: var(--text);
    }

    /* 工程师标�?*/
    .project-engineer-tags {
      display: flex;
      flex-wrap: wrap;
      gap: 3px;
      margin-top: auto;
      padding-top: 6px;
      border-top: 1px solid var(--line);
      position: relative;
      z-index: 1;
    }
    .engineer-tag {
      display: inline-block;
      font-size: 10px;
      padding: 1px 7px;
      border-radius: 10px;
      background: var(--panel-soft);
      color: var(--muted);
      cursor: default;
      line-height: 1.6;
    }
    .engineer-tag.creator {
      border: 1px solid var(--primary);
      color: var(--primary);
      font-weight: 600;
    }

    /* 关闭关联人面板后，被操作卡片的高亮提示动画 */
    .eng-card-flash {
      animation: engCardFlash 1.5s ease-out;
      border-radius: 10px;
    }
    @keyframes engCardFlash {
      0%   { box-shadow: 0 0 0 3px var(--primary); }
      100% { box-shadow: 0 0 0 0 rgba(0,120,255,0); }
    }

    /* 项目关联人管理页面：内联两列布局 */
    .eng-page { display:flex; flex-direction:column; height:100%; overflow:hidden; }
    .eng-page-header { padding:16px 0; flex-shrink:0; }
    .eng-page-title { font-size:clamp(16px,0.83vw,20px); font-weight:600; }
    .eng-page-body { display:flex; gap:16px; flex:1; overflow:hidden; }
    .eng-left-col { flex:0 0 40%; display:flex; flex-direction:column; border:1px solid var(--line); border-radius:12px; background:var(--bg); overflow:hidden; }
    .eng-right-col { flex:1; display:flex; flex-direction:column; border:1px solid var(--line); border-radius:12px; background:var(--bg); overflow:hidden; }
    .eng-col-title { padding:12px 16px; font-size:16px; font-weight:600; color:var(--text); border-bottom:1px solid var(--line); flex-shrink:0; }
    .eng-list-wrap { display:flex; flex-direction:column; flex:1; overflow:hidden; padding:8px; }
    .eng-page-row { display:flex; align-items:center; gap:6px; padding:7px 8px; border-radius:8px; cursor:pointer; font-size:16px; }
    .eng-page-row:hover { background:var(--panel-soft); }
    .eng-page-row.selected { background:var(--primary-soft); border:1px solid var(--primary); }
    .eng-page-row input[type="checkbox"] { accent-color:var(--primary); cursor:pointer; }
    .eng-perm-wrap { padding:12px 16px; flex:1; overflow-y:auto; }
    .eng-perm-hint { color:var(--muted); font-size:16px; text-align:center; padding:40px 0; }
    .eng-perm-for { font-size:17px; margin-bottom:16px; padding-bottom:12px; border-bottom:1px solid var(--line); }
    .eng-perm-item { display:flex; align-items:center; gap:10px; padding:8px 10px; border-radius:6px; cursor:pointer; }
    .eng-perm-item:hover { background:var(--panel-soft); }
    .eng-perm-item input[type="checkbox"] { accent-color:var(--primary); width:16px; height:16px; cursor:pointer; }
    .eng-perm-item label { font-size:16px; cursor:pointer; color:var(--text); }
    .engineer-search-input { width:100%; padding:8px 12px; border-radius:8px; border:1px solid var(--line); background:var(--panel); color:var(--text); font-size:16px; outline:none; box-sizing:border-box; }
    .engineer-search-input:focus { border-color:var(--primary); box-shadow:0 0 0 3px var(--primary-soft); }

    /* ── 三列关联人页面 ── */
    .eng-page-3col .eng-page-body { display:flex; gap:12px; flex:1; overflow:hidden; min-height:0; }
    .eng-page-3col .eng-col { display:flex; flex-direction:column; border:1px solid var(--line); border-radius:8px; background:var(--bg); overflow:hidden; }
    .eng-page-3col .eng-col-avail { flex:0 0 40%; }
    .eng-page-3col .eng-col-perm { flex:1; min-width:0; }
    .eng-page-3col .eng-col-title { padding:8px 12px; font-size:18px; font-weight:600; color:var(--text); border-bottom:1px solid var(--line); flex-shrink:0; }
    .eng-page-3col .eng-list-wrap { display:flex; flex-direction:column; flex:1; overflow-y:auto; padding:6px; min-height:40px; }
    .eng-page-3col .eng-current-wrap { display:flex; flex-direction:column; flex:1; overflow-y:auto; padding:6px; }
    .eng-page-3col .eng-pending-wrap { flex-shrink:0; }
    .eng-current-row:hover { background:var(--primary-soft); }

    /* ── 内联面板（项目工程覆盖层）── */
    .eng-inline-panel {
      flex:1; min-width:0;
      background:var(--bg);
      display:flex; flex-direction:column; overflow:hidden;
      border-radius:0 12px 12px 0;
    }
    /* 关联人面板「返回项目工程」按钮（2026-09-06）：参照二级导航按钮统一标准（.project-group-tab）
       —— 高 41px、圆角 12、边框+panel 底、17px 600；位置由右上悬浮箭头组避让逻辑设置，
       transition 只含背景/边框/文字，不含 top/right，避免打开时位移动画“飘出” */
    .eng-inline-panel > .eng-back-btn {
      position:absolute;
      display:inline-flex;
      align-items:center;
      gap:6px;
      height:41px;
      box-sizing:border-box;
      padding:0 16px;
      border-radius:12px;
      border:1px solid var(--line);
      background:var(--panel);
      color:var(--text);
      font-size:17px;
      font-weight:600;
      line-height:1;
      cursor:pointer;
      user-select:none;
      z-index:10;
      transition: background .2s, border-color .2s, color .2s, box-shadow .2s;
    }
    .eng-inline-panel > .eng-back-btn:hover {
      background: var(--primary-soft);
      border-color: var(--primary);
      color: var(--primary);
    }
    .eng-inline-panel > .eng-back-btn:active { transform: scale(.97); }
    .eng-inline-close {
      position:absolute; top:8px; right:12px;
      width:38px; height:38px; line-height:38px; text-align:center;
      font-size:20px; cursor:pointer; border-radius:8px;
      color:var(--text); background:var(--panel-soft); z-index:10;
      user-select:none;
    }
    .eng-inline-close:hover { background:var(--primary); color:#fff; }
    .eng-inline-content { flex:1; display:flex; flex-direction:column; overflow:hidden; padding:41px 0 0 12px; }
    /* 2026-08-31 用户要求：第2列(关联人员)底部、第3列(权限设置)底部+右边 空隙归0（原 padding 下13/右12） */

    /* ── 关联人面板打开时：左侧第一列 400px 分组项目卡片列 ── */
    .project-card-wrap.eng-panel-open { flex-direction: row; }
    .eng-card-strip {
      width:400px; flex-shrink:0; min-width:0;
      /* 2026-08-31 第一列(切换选择项目)：补齐上/左/下边线（原仅右侧分隔线） */
      border:1px solid var(--line);
      background:transparent;
      display:flex; flex-direction:column; overflow:hidden;
    }
    .eng-card-strip-head {
      padding:10px 12px 6px; font-size:21px; font-weight:600; color:var(--text); flex-shrink:0;
    }
    .eng-card-strip-tabs {
      display:grid; grid-template-columns:repeat(4, 1fr); gap:6px;
      padding:6px 12px 8px; flex-shrink:0;
    }
    .eng-strip-tab {
      border:1px solid var(--line); background:var(--panel-soft); color:var(--muted);
      font-size:14px; padding:4px 2px; border-radius:6px; cursor:pointer; white-space:nowrap;
      text-align:center;
    }
    .eng-strip-tab:hover { border-color:var(--primary); color:var(--primary); }
    .eng-strip-tab.active { background:color-mix(in srgb, var(--primary) 18%, transparent); border-color:var(--primary); color:var(--primary); }
    .eng-card-strip-scroll { flex:1; overflow-y:auto; padding:4px 10px 14px; min-height:0; }
    .eng-strip-card {
      padding:9px 10px; margin-bottom:8px; border-radius:10px;
      border:1px solid var(--line); background:transparent;
      cursor:pointer; transition:transform .2s, border-color .2s;
    }
    .eng-strip-card:hover {
      transform: translateY(-2px);
      box-shadow: none;
    }
    .eng-strip-card.active {
      border-color: var(--primary);
      outline: 2px solid var(--primary);
      outline-offset: -1px;
    }
    .eng-strip-card.active:hover {
      transform: none;
    }
    .eng-strip-card-name { font-size:16px; font-weight:600; color:var(--text); line-height:1.3; word-break:break-all; }
    .eng-strip-card-meta { margin-top:4px; font-size:16px; color:var(--muted); word-break:break-all; }
    .eng-strip-empty { padding:20px 10px; text-align:center; font-size:16px; color:var(--muted); }

    /* ── 顶部项目名称栏 ── */
    .eng-page-topbar {
      flex-shrink:0; padding:6px 8px; font-size:23px; font-weight:600;
      border-bottom:1px solid var(--line); margin-bottom:8px;
    }

    /* ── 手动添加弹窗 ── */
    /* 手动添加项目关联人员弹窗（2026-10-08 按《开发要求》「弹窗标准」改造，样板＝语音助手设置）：
       root(#engAddModal) 只做**定位壳** —— pointer-events:none、不再铺满全屏吃事件（标准①：不挡交互）；
       面板本体 .eng-add-modal 交给 window.LdgFloatPanel.adopt() 管（标准②③④：拖动 / 位置记忆 / 出边兜住）。
       外观按标准⑥：底色 var(--panel)（半透明，与 .smbg-menu 同款）、圆角 12、无外圈影子。 */
    .eng-add-modal-overlay {
      position:fixed; z-index:10000; pointer-events:none;
    }
    .eng-add-modal {
      background:var(--panel); border-radius:12px; padding:0; width:480px; height:550px; max-width:90vw;
      border:1px solid var(--line); pointer-events:auto; overflow:hidden;
    }
    .eng-add-modal .section-head {
      cursor:grab; user-select:none; display:flex; align-items:center;
      justify-content:space-between; padding:16px 22px; border-bottom:1px solid var(--line);
    }
    .eng-add-modal .section-head:active { cursor:grabbing; }
    .eng-add-modal .section-head h3 { margin:0; font-size:18px; font-weight:600; }
    .eng-add-modal-body { padding:28px 24px; display:flex; flex-direction:column; gap:11px; }
    .eng-add-modal-row {
      display:flex; align-items:center; gap:12px; padding:2px 0;
    }
    .eng-add-modal-row label {
      flex:0 0 90px; font-size:17px; color:var(--text); text-align:left;
    }
    .eng-add-modal-row input,.eng-add-modal-row select {
      flex:1; padding:10px 14px; border-radius:8px; border:1px solid var(--line);
      background:var(--bg); color:var(--text); font-size:17px; outline:none;
    }
    .eng-add-modal-row input:focus,.eng-add-modal-row select:focus { border-color:var(--primary); }
    /* ⚠ 「所属单位」两个框 2026-10-08 起改用**原生 select**（与同行「项目角色」同一种控件），
       不再需要自绘箭头/包裹层 —— 样式与展开后的下拉菜单都交给浏览器原生表现，保证两处"一模一样"。 */
    .eng-add-modal-footer {
      display:flex; justify-content:flex-end; gap:10px; padding:14px 22px; border-top:1px solid var(--line);
    }
    .eng-add-btn {
      white-space:nowrap; height:28px; line-height:28px; text-align:center;
      border-radius:4px; font-size:16px;
      background:var(--primary); color:#fff; border:none; cursor:pointer; padding:0 10px;
    }
    .eng-add-btn:hover { opacity:.85; }
    .eng-add-confirm { padding:8px 24px; border-radius:8px; background:var(--primary); color:#fff; border:none; font-size:16px; cursor:pointer; }
    .eng-add-cancel { padding:8px 24px; border-radius:8px; background:var(--panel); color:var(--text); border:1px solid var(--line); font-size:16px; cursor:pointer; }
    .eng-add-confirm:hover,.eng-add-cancel:hover { opacity:.85; }


     /* 分组空白右键菜单 */
     .group-context-menu { position: fixed; z-index: 10001; background: transparent; border: none; border-radius: 10px; padding: 0; box-shadow: none; }
     .group-context-menu .btn { border: none !important; background: var(--panel-soft); color: var(--text); border-radius: 10px; padding: 10px 20px; font-size: 16px; }  /* 右键菜单字号全站统一 16px（原 14） */
     .group-context-menu .btn:hover { background: var(--primary); color: #fff; }
     .project-card-context-menu { position: fixed; z-index: 10002; background: transparent; border: none; border-radius: 10px; padding: 0; box-shadow: none; width: 170px; display: flex; flex-direction: column; gap: 6px; }
     .project-card-context-menu .btn { border: none !important; background: var(--panel-soft); color: var(--text); border-radius: 10px; padding: 10px 20px; font-size: 16px; width: 100%; text-align: left; }  /* 右键菜单字号全站统一 16px（原 14） */
     /* 2026-09-01 删除按钮颜色与其他项一致（保留 danger 类供 JS 选择，仅此处覆盖颜色） */
     .project-card-context-menu .btn.danger { background: var(--panel-soft); color: var(--text); }
     .project-card-context-menu .btn:hover { background: var(--primary); color: #fff; }
     /* 2026-09-14 远程演示：项目工程右键菜单项的**悬停高亮**也要跟随（同 `.fb-ctx-item` / `.smbg-item` 那两条）。
        `:hover` 按接收端**本机指针位置**算，对方鼠标并不在菜单上 → 永远不成立，
        所以必须让 `.ldp-hover` 与上面的 `:hover` 规则**一一等效**，否则就会出现
        "菜单弹出来了、但鼠标上下移动高亮条不走"（用户实测：项目工程右键菜单高亮不跟随）。 */
     .project-card-context-menu .btn.ldp-hover,
     .group-context-menu .btn.ldp-hover { background: var(--primary); color: #fff; }

    /* 账号芯片 */
    .account-chip { border-radius: 20px !important; transition: all .2s; }
    .account-chip.active { background: var(--primary) !important; color: #fff !important; border-color: var(--primary) !important; }

    /* 已注册账号行 */
    .approved-row:hover { background: var(--panel-soft); }
    .approved-row.selected { background: var(--primary-soft); border-left: 3px solid var(--primary); }

    /* 角色选择下拉框选项适配主题 */
    .approved-row select option {
      background: var(--panel);
      color: var(--text);
    }

    /* 字体设置弹窗 */
    .modal-overlay { position: fixed; inset: 0; background: transparent; z-index: 10000; display: flex; align-items: center; justify-content: center; pointer-events: none; }
    .modal-overlay.active { background: var(--overlay); pointer-events: auto; }
    /* 2026-09-07 用户：通用确认弹窗（删除图标/清空回收站等 ldgConfirm）不要暗色蒙板；
       透明遮罩仅用于居中 + 点击弹窗外关闭，不再压暗背景 */
    .modal-overlay#ldgConfirmModal.active { background: transparent; }
    .font-settings-dialog .section-head { cursor: grab; user-select: none; }
    .font-settings-dialog .section-head h3 { font-size: 20px; }
    .font-settings-dialog .section-head:active { cursor: grabbing; }
    /* 2026-09-16 用户："壁纸设置的透明度逻辑非常好，用这个作为所有弹窗体的样式，圆角大小都按他统一"
       → 底色统一用 `--panel`（半透明，与 `.smbg-menu` 同款）、圆角统一 12px（原 16px）。 */
    .font-settings-dialog { background: var(--panel); border-radius: 12px; padding: 24px; width: 500px; height: 600px; overflow-y: auto; border: 1px solid var(--line); pointer-events: auto; }
    .font-settings-dialog.ai-api-dialog { width: 510px; height: auto; max-height: calc(90vh / var(--ld-gear, 1)); }
    .engineer-assign-dialog { background: var(--panel); border-radius: 12px; padding: 24px; border: 1px solid var(--line); pointer-events: auto; }
    .engineer-assign-dialog .section-head { cursor: grab; user-select: none; }
    .engineer-assign-dialog .section-head:active { cursor: grabbing; }
    .font-settings-dialog .btn { padding: 1px 10px; font-size:20px; min-width: 140px; }
    .engineer-assign-dialog .section-head .btn.ghost,
    .eng-add-modal .section-head .btn.ghost { padding: 1px 10px; font-size: 17px; min-width: 140px; }

    .brightness-dialog { width: 380px !important; height: auto !important; min-height: 0 !important; }

    .auto-sort-dialog {
      background: var(--bg);
      border-radius: 16px;
      padding: 24px;
      width: 420px;
      border: 1px solid var(--line);
      pointer-events: auto;
    }
    .auto-sort-options {
      display: flex;
      flex-direction: column;
      gap: 8px;
    }
    .auto-sort-option {
      display: flex;
      align-items: center;
      gap: 12px;
      padding: 14px 16px;
      border-radius: 12px;
      border: 1px solid var(--line);
      background: var(--panel-soft);
      color: var(--text);
      font-size: 14px;
      cursor: pointer;
      text-align: left;
      width: 100%;
      transition: background .15s, border-color .15s;
    }
    .auto-sort-option:hover {
      background: var(--primary-soft);
      border-color: var(--primary);
    }
    .auto-sort-icon {
      font-size: 22px;
      flex-shrink: 0;
    }
    .auto-sort-label {
      font-weight: 600;
      font-size: 15px;
    }
    .auto-sort-desc {
      font-size: 12px;
      color: var(--muted);
      margin-left: auto;
    }

    .project-overview-stage {
      display: grid;
      grid-template-columns: repeat(2, minmax(0, 1fr));
      gap: 6px;
      margin-bottom: 10px;
      position: relative;
      z-index: 1;
    }

    .project-overview-stage button {
      border: 1px solid var(--line);
      border-radius: 10px;
      padding: 5px 4px;
      color: var(--muted);
    }

/* ── 语音助手设置弹窗 ──
   max-height 用 --ld-gear（档位）换算：弹窗跟随档位缩放（无反向补偿，2026-08-14），
   视觉高度上限 = 布局 × 档位 = 90% 视口 → 布局 max-height = 90vh ÷ 档位
   （2026-08-12 用户反馈：浏览器300%时弹框视觉高度只有 ~243px） */
.ai-voice-dialog { width: 500px !important; height: auto !important; max-height: calc(90vh / var(--ld-gear, 1)); }
.ai-voice-settings-body { padding: 0 14px 14px; display: flex; flex-direction: column; gap: 8px; }
.ai-voice-row { background: var(--panel-soft); border-radius: 12px; padding: 11px 16px; border: 1px solid var(--line); }
.ai-voice-row-header { display: flex; align-items: center; justify-content: space-between; margin-bottom: 4px; }
.ai-voice-row-header label { font-size: 14px; font-weight: 600; color: var(--text); }
.ai-voice-row-header .ai-voice-value { font-size: 14px; font-weight: 700; color: var(--primary); min-width: 40px; text-align: right; }
.ai-voice-row-desc { font-size: 12px; color: var(--muted); line-height: 1.5; margin-bottom: 8px; }
.ai-voice-row input[type="range"] { width: 100%; -webkit-appearance: none; appearance: none; height: 5px; border-radius: 3px;
  background: linear-gradient(to right, var(--primary) 0%, var(--primary) 50%, var(--accent-3) 50%, var(--accent-3) 100%);
  outline: none; cursor: pointer; margin-top: 4px; }
.ai-voice-row input[type="range"]::-webkit-slider-thumb { -webkit-appearance: none; width: 16px; height: 16px; border-radius: 50%;
  background: var(--primary); cursor: pointer; border: 2px solid var(--bg); box-shadow: 0 1px 3px rgba(0,0,0,.2); }
.ai-voice-row select { width: 100%; padding: 8px 12px; border-radius: 10px; border: 1px solid var(--line);
  background: var(--panel); color: var(--text); font-size: 13px; outline: none; cursor: pointer; margin-top: 4px; }
.ai-voice-row select option { background: var(--panel); color: var(--text); }
.ai-voice-actions { display: flex; gap: 8px; margin-top: 4px; }
.ai-voice-actions .btn { flex: 1; text-align: center; }

/* ── 语音助手设置弹窗（无遮挡可拖动版）── */
.ai-voice-dialog-root { position: fixed; z-index: 30000; left: 50%; top: 50%; transform: translate(-50%,-50%); pointer-events: none; }
.ai-voice-dialog-root .font-settings-dialog { pointer-events: auto; }
.ai-voice-dialog-root .section-head:active { cursor: grabbing !important; }

    .project-overview-stage button.active {
      color: var(--text);
      background: var(--primary-soft);
      border-color: var(--primary);
    }

    .project-overview-card .btn {
      position: relative;
      z-index: 1;
    }

    /* 高分辨率（屏幕实际分辨率 >=2400px，非视口宽度）*/
    .high-res .app { --sidebar-width: 240px; --sidebar-full-w: 240px; }
    .high-res .app.sidebar-icon { --sidebar-width: 88px; }
    .high-res .app.sidebar-hidden { --sidebar-width: 0px; --sidebar-gap: 0px; }
    .high-res .logo { width: 97px; height: 97px; flex: 0 0 97px; }
    .high-res .brand-line-main { font-size: 24px !important; }
    .high-res .brand-line-sub { font-size: 13px !important; }
    .high-res .nav-title { font-size: 12px !important; }
    .high-res .nav-title .nt-user { font-size: 14px !important; }
    .high-res .nav-title .nt-greeting { font-size: 11px !important; }
    .high-res .nav-title .nt-datetime { font-size: 14px !important; }
    .high-res .nav button { font-size: 22px !important; }
    .high-res .nav button.active { font-size: 27px !important; }
    .high-res .sidebar { padding: 22px 18px 22px 0; }
    .high-res .brand { gap: 5px; justify-content: center; padding: 1px 0 20px; }
    .high-res .brand-line-sub { gap: 7px; }
    .high-res .nav-title { margin: 4px 10px 28px; }
    .high-res .nav button { gap: 14px; padding: 11px 14px; border-radius: 14px; min-height: 54px; }
    .high-res .nav .icon { border-radius: 10px; }
    .high-res .side-card { padding: 14px; border-radius: 18px; }

    /* 触屏设备（手机/平板）：长按任意元素禁止浏览器原生呼出菜单（下载/分享/打印/刷新/搜索/复制）。
       -webkit-touch-callout 针对 iOS Safari（长按图片/链接/输入框呼出菜单）；user-select:none 屏蔽
       Android/iOS 长按文字弹"复制/全选/搜索"选择菜单（2026-08-14 用户要求全部屏蔽）；
       输入框/文本域/contenteditable 保留文本选择（可正常编辑与复制）；图片/视频禁止拖拽触发系统行为。
       修复（2026-08-14）：对文件卡片、项目卡片、侧边栏、图引、悬浮助手等需要页面自定义右键菜单的元素，
       恢复 -webkit-touch-callout:default，确保 iOS Safari 能正常触发 contextmenu 事件，让自定义菜单弹出。 */
    /* 触屏点按高亮通病修复（2026-08-30）：全局禁用 tap-highlight，所有可点按元素不再闪背景 */
    * { -webkit-tap-highlight-color: transparent; }
    @media (pointer: coarse), (any-pointer: coarse) {
      * { -webkit-touch-callout: none; -webkit-user-select: none; user-select: none; -webkit-tap-highlight-color: transparent; }
      input, textarea, [contenteditable="true"], [contenteditable="plaintext-only"] {
        -webkit-user-select: text; user-select: text;
      }
      img, video, canvas, svg { -webkit-user-drag: none; user-drag: none; }
      .fb-item, .ifb-card-item, .project-card, .side-card, .ai-float-avatar, .sidebar,
      #photosRightPanel, .fb-list-header, .hist-stage {
        -webkit-touch-callout: default;
        -webkit-user-select: auto;
        user-select: auto;
      }
    }

    @media (max-width: 760px) {
      .project-page-grid { gap: 16px; }
    }

    .sidebar-logout-btn {
      width: 100%;
      height: 31px;
      border: 0;
      border-radius: 11px;
      background: linear-gradient(135deg, var(--primary), var(--accent-2));
      color: #fff;
      display: inline-flex;
      align-items: center;
      justify-content: center;
      gap: 8px;
      font-size: 11px;
      font-weight: 900;
      cursor: pointer;
      box-shadow: 0 12px 24px var(--glow-primary);
      transition: transform .2s ease, box-shadow .2s ease;
    }

    .sidebar-font-btn {
      width: 100%;
      height: 27px;
      border: 1px solid var(--sidebar-border);
      border-radius: 10px;
      background: color-mix(in srgb, var(--sidebar-card-bg) 72%, var(--bg-deep) 28%);
      color: var(--sidebar-text);
      display: inline-flex;
      align-items: center;
      justify-content: center;
      gap: 6px;
      font-size: 11px;
      font-weight: 700;
      cursor: pointer;
      box-shadow: inset 0 1px 0 rgba(255,255,255,.08), 0 8px 18px rgba(0,0,0,.08);
      transition: all .2s ease;
      outline: none;
    }

    .sidebar-font-btn:focus {
      border-color: var(--primary);
      box-shadow: 0 0 0 3px var(--primary-soft);
    }

    .sidebar-font-btn:hover {
      border-color: var(--primary);
      background: color-mix(in srgb, var(--sidebar-card-bg) 60%, var(--primary) 12%);
    }

    .sidebar-logout-btn:hover {
      transform: translateY(-1px);
      box-shadow: 0 16px 30px var(--glow-primary);
    }

    .sidebar-logout-btn .icon {
      width: 18px;
      height: 18px;
      border-radius: 7px;
      background: rgba(255,255,255,.16);
      display: grid;
      place-items: center;
      flex: 0 0 18px;
    }

    .main {
      padding: 22px;
      min-width: 0;
      display: flex;
      flex-direction: column;
    }

    .content {
      flex: 1;
      min-height: 0;
      display: flex;
      flex-direction: column;
    }

    .topbar {
      background: var(--topbar-bg);
      backdrop-filter: blur(16px);
      border: 1px solid var(--topbar-border);
      border-radius: var(--radius);
      padding: 16px 18px;
      display: flex;
      justify-content: space-between;
      align-items: center;
      gap: 16px;
      box-shadow: var(--shadow);
      position: sticky;
      top: 16px;
      z-index: 20;
    }

    .topbar h2 { margin: 0; font-size: 22px; }
    .breadcrumb { color: var(--muted); font-size: 13px; margin-top: 4px; }

    /* 内容页统一取消顶部标题栏，避免每页重复占位 */
    .main > .topbar {
      display: none;
    }

    .content {
      padding-top: 0;
    }

    .top-actions { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; justify-content: flex-end; }

    .user-badge {
      display: flex;
      align-items: center;
      gap: 6px;
      padding: 6px 14px;
      border-radius: 22px;
      background: var(--primary-soft);
      border: 1px solid var(--primary);
      color: var(--primary);
      font-size: 13px;
      font-weight: 600;
      cursor: pointer;
      white-space: nowrap;
      transition: .2s;
    }
    .user-badge:hover { background: var(--primary); color: #fff; }

    .sidebar-state-controls {
      display: inline-flex;
      align-items: center;
      gap: 4px;
      height: 40px;
      padding: 4px;
      border: 1px solid var(--line);
      border-radius: 12px;
      background: var(--panel-soft);
    }

    .sidebar-state-btn {
      height: 30px;
      border: 0;
      border-radius: 9px;
      padding: 0 10px;
      background: transparent;
      color: var(--muted);
      font-weight: 800;
      cursor: pointer;
      white-space: nowrap;
      transition: .2s;
    }

    .sidebar-state-btn:hover,
    .sidebar-state-btn.active {
      background: linear-gradient(135deg, var(--primary), var(--accent-2));
      color: #fff;
      box-shadow: 0 8px 20px var(--glow-primary);
    }


    .sidebar-state-controls { display: none !important; }

    .select, .input {
      height: 40px;
      border: 1px solid var(--line);
      border-radius: 12px;
      background: transparent;
      padding: 0 12px;
      color: var(--input-text);
      outline: none;
    }

    .select,
    .input,
    .sidebar-theme-select,
    .auth-theme-switch select,
    .auth-field input,
    .auth-field select {
      color: var(--input-text);
      -webkit-text-fill-color: currentColor;
      caret-color: var(--primary);
    }

    .select option,
    .sidebar-theme-select option,
    .auth-theme-switch select option,
    .auth-field select option {
      background: var(--panel);
      color: var(--text);
    }

    .input { min-width: 250px; }

    .btn {
      border: 0;
      height: 40px;
      padding: 0 15px;
      border-radius: 12px;
      background: linear-gradient(135deg, var(--primary), var(--accent-2));
      color: #fff;
      box-shadow: 0 10px 22px var(--glow-primary);
      font-weight: 700;
      cursor: pointer;
      transition: .2s;
      display: inline-flex;
      align-items: center;
      justify-content: center;
      gap: 6px;
    }

    .btn:hover { background: linear-gradient(135deg, var(--primary-dark), var(--primary)); transform: translateY(-1px); }
    .btn.secondary { background: var(--btn-secondary-bg); color: var(--btn-secondary-text); }
    .btn.ghost { background: var(--btn-ghost-bg); color: var(--text); border: 1px solid var(--line); }
    .btn.danger { background: var(--btn-danger-bg); color: var(--btn-danger-text); }
    .btn.success { background: var(--btn-success-bg); color: var(--btn-success-text); }

    .content { margin-top: 22px; font-size: 14px; }
    .main > .topbar + .content { margin-top: 0; }
    .view { display: none; animation: fade .15s ease; }
    .view.active { display: flex; flex-direction: column; flex: 1; min-width: 0; min-height: 0; }

    /* ★★ 2026-09-27 用户定稿：**9 个导航分组之间互相切换也都有这个位移 ⇒ 统一去掉**。
       原 `fade` 带 `transform: translateY(8px) → 0`：进一格时**整格先偏下 8px、0.15s 内升上来**。
       最开始只在「管理工作」那一格发现（"进页那一刻量到的附件区偏下 8px" —— 那格里有料单审核，
       外面有跨进程附件窗要贴合它的几何），随后用户要求**统一**：
         "我们一共是 9 个导航分组，每个导航分组之间相互切换的时候都有这个位移，**统一去掉**"。
       ⇒ 把 `fade` 改成**纯淡入**：只改 `opacity`，**不碰 `transform`**。
         · 观感基本不变（位移本来只有 8px），但**布局从第一帧就是终值**；
         · 凡是"进场期间会被量尺寸/位置"的容器（如料单审核的附件区）从此量出来永远准
           ⇒ 客户端与前端几何代码**一行都不用改**（这正是用户要的效果）；
         · `@keyframes fade` 全站**只有这一处定义**、也只被 `.view` 用 ⇒ 改这里 = 9 个分组一起生效。
       ⚠ **别再用 `transform` 做"进口动画"**：排查口诀 —— **"只有切页后第一次才偏" ⇒ 先怀疑进口动画**。 */
    @keyframes fade {
      from { opacity: 0; }
      to { opacity: 1; }
    }

    .grid { display: grid; gap: 16px; }
    .grid.cols-4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }
    .grid.cols-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
    .grid.cols-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }

    .card {
      position: relative;
      overflow: hidden;
      background: var(--card-gradient, var(--panel));
      border: 1px solid var(--line);
      border-radius: var(--radius);
      padding: 18px;
      box-shadow: var(--shadow);
      min-width: 0;
    }

    .card::before {
      content: "";
      position: absolute;
      inset: 0;
      border-radius: inherit;
      pointer-events: none;
      background: linear-gradient(135deg, var(--card-highlight), transparent 38%, transparent 72%, rgba(255,255,255,.04));
      opacity: .75;
    }

    .card > * { position: relative; z-index: 1; }


    .stat { position: relative; overflow: hidden; }
    .stat::after {
      content: "";
      position: absolute;
      right: -30px;
      top: -30px;
      width: 100px;
      height: 100px;
      border-radius: 999px;
      background: var(--primary-soft);
    }

    .stat .label { color: var(--muted); font-size: 13px; }
    .stat .value { font-size: 28px; font-weight: 900; margin: 9px 0 6px; position: relative; z-index: 1; }

    /* 物资指数顶部 5 张统计卡片：描述文字固定在顶部、数值在卡片中垂直水平居中、数值放大 30%（28→36px）、卡片高度增加 50px（仅作用于 #mat-overview-stats，不影响其它页面统计卡）
       box-shadow: none（2026-09-19 用户："物资指数也有 顺带也去掉"）—— 去掉 .card 的投影，
       与「料单审核 · 审核通过」那张卡以及预算翻样「量差&对比」的 5 张 KPI 卡保持同一口径。 */
    #mat-overview-stats .card.stat {
      min-height: 170px;
      display: flex;
      flex-direction: column;
      align-items: center;
      justify-content: center;
      text-align: center;
      box-shadow: none;
    }
    #mat-overview-stats .card.stat .label {
      position: absolute;
      top: 17px;
      left: 0;
      right: 0;
      font-size: 20px;
    }
    #mat-overview-stats .card.stat .value { margin-left: 0; margin-right: 0; font-size: 66px; transform: translateY(15px); }
    #mat-overview-stats .card.stat .value .value-dec { font-size: 36px; }
    .card h3 { font-size: 17px; }
    .section-head h4, .card h4 { font-size: 15px; }
    .trend { font-size: 13px; display: inline-flex; align-items: center; gap: 5px; }
    .up { color: var(--green); }
    .down { color: var(--red); }
    .warn { color: var(--orange); }

    .section-head {
      display: flex;
      justify-content: space-between;
      gap: 12px;
      align-items: center;
      margin-bottom: 14px;
    }

    /* 项目分组标题背景�?*/
    .project-group-head {
      display: flex;
      align-items: center;
      gap: 1px;
      padding: 8px 16px;
      border-radius: 14px;
      background: var(--primary-soft);
      border: 1px solid color-mix(in srgb, var(--primary) 20%, transparent);
      margin-bottom: 4px;
    }
    .project-group-head h3 {
      margin: 0;
      font-size: 16px;
      white-space: nowrap;
      flex-shrink: 0;
    }
    .project-group-head span {
      color: var(--muted);
      font-size: 13px;
      text-align: left;
      flex: 1;
    }
    .project-group-head .proj-count {
      font-size: 12px;
      color: var(--primary);
      font-weight: 700;
      white-space: nowrap;
    }

    /* 二级导航（项目工程顶部标签按钮，全站统一标准） */
    .project-group-tabs {
      display: flex;
      gap: 8px;
      padding: 10px 0 14px;
      flex-wrap: wrap;
      align-items: center;
    }

    /* 数据看板/盈亏分析/形象进度 二级导航上下位置对齐预算翻样(.mat-tabs)：
       .mat-tabs 为 margin-bottom:16px 且无上下 padding；原 .project-group-tabs 有
       10px/14px padding 导致标签栏整体靠下。用 view id 作用域覆盖，
       仅影响 dashboard/delivery/progress，不影响 projectWorks。 */
    #dashboard .project-group-tabs,
    #delivery .project-group-tabs,
    #progress .project-group-tabs {
      padding: 0;
      margin-bottom: 16px;
    }
    .project-group-tab {
      display: inline-flex;
      align-items: center;
      gap: 6px;
      padding: 8px 16px;
      border-radius: 12px;
      border: 1px solid var(--line);
      background: var(--panel);
      color: var(--text);
      font-size: 19px;
      font-weight: 600;
      height: 41px;          /* 固定高度：基础态/选中态一致(41px)，杜绝切换重排抖动；与旧基础态41px保持一致 */
      line-height: 1;        /* 行高=字号，配合 align-items:center 精确垂直居中，文字不再偏下 */
      cursor: pointer;
      /* 只过渡颜色/阴影，不去动画字号与padding，避免放大时文字抖动/重排 */
      transition: background .2s, color .2s, border-color .2s, box-shadow .2s;
      user-select: none;
    }
    .project-group-tab:hover {
      background: var(--primary-soft);
      border-color: var(--primary);
    }
    .project-group-tab.active {
      background: color-mix(in srgb, var(--primary) 18%, transparent);
      color: var(--primary);
      border-color: var(--primary);
      box-shadow: 0 4px 12px color-mix(in srgb, var(--primary) 30%, transparent);
      /* 选中态文字加大2px(19→21)且按钮框不撑宽：左右padding由JS按中文数补偿(--tabpad)，
         高度锁定41px不变；上下padding由8px→6px为加大的文字腾出空间 */
      font-size: 21px;
      padding: 6px var(--tabpad, 8px);
    }
    .project-group-tab .tab-count {
      font-size: 11px;
      opacity: .7;
      font-weight: 400;
    }
    .project-group-tab.active .tab-count {
      opacity: .85;
    }

    /* 项目搜索�?+ 切换按钮容器 */
    .project-search-box {
      display: flex;
      align-items: center;
      gap: 8px;
      margin-left: auto;
    }
    .project-search-input {
      padding: 8px 14px;
      border-radius: 10px;
      border: 1px solid var(--line);
      background: var(--panel);
      color: var(--text);
      font-size: 14px;
      width: 200px;
      height: 41px; /* 2026-09-03 与二级导航按钮同高 41px */
      outline: none;
      transition: border-color .2s, box-shadow .2s;
    }
    .project-search-input:focus {
      border-color: var(--primary);
      box-shadow: 0 0 0 3px var(--primary-soft);
    }
    .project-search-input::placeholder {
      color: var(--muted);
    }
    .project-search-input.highlight-match {
      border-color: #f59e0b;
      box-shadow: 0 0 0 3px rgba(245,158,11,.25);
    }
    /* 视图切换按钮 */
    .view-toggle-btn {
      display: inline-flex;
      align-items: center;
      justify-content: center;
      width: 36px;
      height: 36px;
      border-radius: 10px;
      border: 1px solid var(--line);
      background: var(--panel);
      color: var(--text);
      cursor: pointer;
      font-size: 18px;
      transition: all .2s;
      user-select: none;
      flex-shrink: 0;
    }
    .view-toggle-btn:hover {
      background: var(--primary-soft);
      border-color: var(--primary);
    }
    .view-toggle-btn.active {
      background: color-mix(in srgb, var(--primary) 18%, transparent);
      color: var(--primary);
      border-color: var(--primary);
    }
    /* 项目工程描述条内的显示模式按钮与自动重排/拖拽模式按钮保持一致高度 */
    .project-desc-bar .view-toggle-btn {
      width: 26px;
      height: 24px;
      padding: 0;
      border-radius: clamp(5px, 0.31vw, 8px);
      border: none;
      background: transparent;
      color: var(--muted);
      font-size: clamp(11px, 0.63vw, 16px);
      line-height: 1;
      display: inline-flex;
      align-items: center;
      justify-content: center;
    }
    .project-desc-bar .view-toggle-btn:hover {
      background: var(--primary-soft);
      color: var(--primary);
    }
    .project-desc-bar .view-toggle-btn.active {
      background: color-mix(in srgb, var(--primary) 18%, transparent);
      color: var(--primary);
    }

    /* 全员设置弹窗：开启/关闭分段按钮 */
    .cache-toggle-group {
      display: inline-flex;
      border: 1px solid var(--line);
      border-radius: 8px;
      overflow: hidden;
      flex-shrink: 0;
    }
    .cache-toggle-btn {
      padding: 5px 14px;
      font-size: 12px;
      border: none;
      background: var(--panel);
      color: var(--muted);
      cursor: pointer;
      line-height: 1.4;
      transition: all .2s;
      user-select: none;
    }
    /* AI API 设置弹窗的 公用/私有 开关：使按钮文字上下垂直居中（2026-08-28） */
    #aiApiSettingsModal .cache-toggle-btn {
      display: inline-flex;
      align-items: center;
      justify-content: center;
    }
    /* 全员设置页（#syssettings，2026-09-27 由弹窗改独立页面）：开关按钮正文 16px。
       ⚠ 原来这两条挂在 `#cacheSettingsModal`（弹窗已删）⇒ 现改挂页面容器，效果不变。 */
    #sysSettingsContainer .cache-toggle-btn { font-size: 16px; padding: 6px 16px; position: relative; overflow: hidden; }
    /* 未选中的开关按钮加 1px 对角线（斜划掉），如点了"开启"则"关闭"上显示斜线 */
    #sysSettingsContainer .cache-toggle-btn:not(.active)::after {
      content: '';
      position: absolute;
      top: 0; right: 0; bottom: 0; left: 0;
      background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1 1' preserveAspectRatio='none'%3E%3Cline x1='0' y1='0' x2='1' y2='1' stroke='currentColor' stroke-width='1' vector-effect='non-scaling-stroke' /%3E%3C/svg%3E");
      background-repeat: no-repeat;
      background-size: 100% 100%;
      pointer-events: none;
    }
    .cache-toggle-btn + .cache-toggle-btn {
      border-left: 1px solid var(--line);
    }
    /* 开始远程演示/接收弹窗（photoProjectModal）压缩 100px 高：间距整体收窄，仅演示场景生效 */
    #photoProjectModal.present-compact .font-settings-dialog { padding: 10px 24px !important; }
    #photoProjectModal.present-compact .section-head { margin-bottom: 4px !important; }
    #photoProjectModal.present-compact p { margin-bottom: 4px !important; }
    #photoProjectModal.present-compact #photoProjectSelectRow { margin-bottom: 4px !important; }
    #photoProjectModal.present-compact #ldpAutoSwapRow { margin-bottom: 4px !important; }
    #photoProjectModal.present-compact #ldpBaselineRow { margin-bottom: 4px !important; }
    .cache-toggle-btn:hover {
      color: var(--primary);
      background: var(--primary-soft);
    }
    .cache-toggle-btn.active {
      background: color-mix(in srgb, var(--primary) 18%, transparent);
      color: var(--primary);
    }
    .cache-toggle-btn.active:hover {
      color: var(--primary);
      background: color-mix(in srgb, var(--primary) 18%, transparent);
    }

    /* 内容模式（列表） */
    .project-group-row.content-mode {
      display: flex;
      flex-direction: column;
      gap: 14px;
      padding: 12px 0 20px;
    }
    .project-group-row.content-mode .project-overview-card {
      width: 100%;
      min-height: 46px;
      height: 46px;
      flex-direction: row;
      align-items: center;
      gap: 6px;
      padding: 0 14px;
      border-radius: 8px;
      border: 1px solid var(--line);
      box-shadow: none;
      background: var(--panel);
      transition: background .15s, border-color .15s;
      cursor: pointer;
      overflow: visible;
      box-sizing: border-box;
    }
    .project-group-row.content-mode .project-overview-card::before {
      display: none;
    }
    .project-group-row.content-mode .project-overview-card:hover {
      transform: none;
      box-shadow: none;
      background: var(--primary-soft);
      border-color: var(--primary);
    }
    .project-group-row.content-mode .project-overview-card.selected {
      background: color-mix(in srgb, var(--primary) 8%, transparent);
      border-color: var(--primary);
      box-shadow: none;
      transform: none;
    }
    /* 内容模式复选框 - 全局隐藏，点击行切换 */
    .content-mode-checkbox {
      display: none !important;
    }
    .project-group-row.content-mode .project-overview-card.dragging {
      transform: none;
    }
    /* ★ 2026-09-28 用户第 1 条："**项目资料 项目工程 施工影像 内容标签 右边的文字也要 16px，
       整个行的文字要统一大小 16**" ⇒ 「项目工程」的内容（标签）模式这一行**整行统一 16px**：
         · 项目名 h3 15 → 16
         · 描述 `.card-desc` 13 → 16
         · 右侧元信息 `.content-mode-meta`（日期 / 大小…）12 → 16
       ⚠ 只作用于 **`.project-group-row.content-mode`**（项目工程的"内容模式"那一种行），
         卡片模式的 `.project-overview-card`（大卡）不受影响。 */
    .project-group-row.content-mode .project-overview-card .project-overview-head h3 {
      font-size: 16px;
      min-width: 100px;
      margin: 0;
      line-height: 1;
    }
    .project-group-row.content-mode .project-overview-card .project-overview-head {
      margin: 0;
      align-items: center;
    }
    .project-group-row.content-mode .project-overview-card .card-desc {
      flex: 1;
      font-size: 16px;
      margin: 0;
      line-height: 1;
      white-space: nowrap;
      overflow: hidden;
      text-overflow: ellipsis;
    }
    .project-group-row.content-mode .project-overview-card .content-mode-meta {
      display: flex;
      align-items: center;
      gap: 12px;
      flex-shrink: 0;
      font-size: 16px;
      color: var(--muted);
    }
    .project-group-row.content-mode .project-overview-card .content-mode-meta span {
      white-space: nowrap;
    }
    .project-group-row.content-mode .project-overview-card .card-engineer-badge {
      display: inline-flex;
      align-items: center;
      gap: 4px;
      padding: 2px 10px;
      border-radius: 20px;
      font-size: 12px;
      background: var(--panel);
      border: 1px solid var(--line);
      color: var(--text);
    }
    /* 卡片模式时隐藏列表专用元�?*/
    .project-group-row:not(.content-mode) .project-overview-card .content-mode-meta {
      display: none;
    }
    /* 内容模式复选框移到最右边 */
    .project-group-row.content-mode .project-overview-card .content-mode-checkbox {
      margin-left: auto;
      order: 1;
    }
    /* 内容模式时隐藏工程师徽章（已�?renderEngineerTags 显示�?*/
    .project-group-row.content-mode .project-overview-card .card-engineer-badge {
      display: none !important;
    }
    /* 内容模式下关联人标签去除多余间距，确保垂直居�?*/
    .project-group-row.content-mode .project-engineer-tags {
      margin-top: 0 !important;
      padding-top: 0 !important;
      border-top: none !important;
    }

    /* 批量操作�?*/
    .batch-action-bar {
      display: flex;
      align-items: center;
      gap: 12px;
      padding: 8px 14px;
      margin-top: 6px;
      border-radius: 10px;
      background: color-mix(in srgb, var(--primary) 6%, transparent);
      border: 1px solid var(--primary);
      font-size: 13px;
      animation: fadeIn .2s ease;
    }
    .batch-action-bar .btn {
      padding: 4px 16px;
      border-radius: 8px;
      font-size: 13px;
    }
    @keyframes fadeIn { from { opacity:0; transform:translateY(-4px); } to { opacity:1; transform:translateY(0); } }

    /* 框选矩�?*/
    .proj-selection-box {
      position: absolute;
      border: 1px solid var(--primary, #36f);
      background: color-mix(in srgb, var(--primary, #36f) 10%, transparent);
      z-index: 100;
      pointer-events: none;
    }
    /* 框选悬停高�?*/
    .project-overview-card.proj-box-hl {
      outline: 2px solid var(--primary, #36f);
      outline-offset: -1px;
    }
    .content-mode .project-overview-card.proj-box-hl {
      background: var(--bg-spot-b, #e8f0fe);
    }

    /* 拖拽目标卡片高亮 */
    .project-overview-card.proj-drop-target {
      outline: 3px solid var(--primary, #36f);
      outline-offset: -2px;
      background: color-mix(in srgb, var(--primary, #36f) 12%, transparent);
    }

    /* 跟随鼠标的确认提示（与管理工作的删除提示框样式统一）
       2026-10-09 用户："300*100 大小都改为 350*150" → 再定稿 350*130 */
    .mouse-confirm {
      position: fixed; z-index: 10002;
      width: 350px; min-height: 130px;
      display: flex; flex-direction: column; justify-content: space-between;
      background: var(--panel);
      border: 1px solid #ef4444;
      border-radius: 8px;
      box-shadow: 0 8px 24px rgba(0,0,0,.5);
      padding: 12px 14px;
      pointer-events: auto;
      animation: fadeIn .15s ease;
      box-sizing: border-box;
    }
    /* 2026-10-09 用户："300*100 这个对话框的文字微调下统一 16px" ⇒ 正文/按钮一律 16px（原来 14/13） */
    .mouse-confirm .mc-msg { font-size: 16px; color: var(--text); line-height: 1.5; word-break: break-all; }
    .mouse-confirm .mc-btns { display: flex; gap: 8px; justify-content: flex-end; }
    .mouse-confirm .mc-btn {
      padding: 4px 14px;
      border-radius: 5px;
      font-size: 16px;
      cursor: pointer; border: none;
      background: #ef4444; color: #fff; font-weight: 600;
      transition: background .1s;
    }
    .mouse-confirm .mc-btn:hover { background: #dc2626; }
    .mouse-confirm .mc-btn.danger { background: #ef4444; color: #fff; }
    .mouse-confirm .mc-btn.danger:hover { background: #dc2626; }
    .mouse-confirm .mc-btn:not(.danger) { background: var(--sidebar-hover); color: var(--text); font-weight: 400; }
    .mouse-confirm .mc-btn:not(.danger):hover { background: var(--sidebar-border); }
    .mouse-confirm .mc-btn.mc-focus { outline: 2px solid var(--primary, #36f); outline-offset: 2px; }
    /* 上传同名冲突弹窗：620×380，背景/边框/圆角与主题亮度调节弹窗（.font-settings-dialog）一致：
       背景 var(--bg)、边框 var(--line)、圆角 16px */
    .mouse-confirm.ld-conflict { width: 620px; height: 380px; padding: 20px 24px 24px; justify-content: flex-start; animation: ldConflictIn .15s ease; background: var(--bg); border: 1px solid var(--line); border-radius: 16px; }
    .mouse-confirm.ld-conflict .mc-title-row { display: flex; align-items: center; justify-content: space-between; margin-bottom: 10px; }
    .mouse-confirm.ld-conflict .mc-title { font-size: 20px; font-weight: 700; color: var(--text); margin-bottom: 0; }
    .mouse-confirm.ld-conflict .mc-line { font-size: 17px; color: var(--text); opacity: .72; line-height: 1.5; margin-bottom: 7px; word-break: break-all; }
    .mouse-confirm.ld-conflict .mc-title-row + .mc-line { margin-top: 10px; }   /* 第二行文字开始下移10px */
    /* ★★ 2026-10-09（用户）："三个大按钮**从底部开始排**，**底部距离和左右的距离要一样** ——
       不然上面的文字多它就下来一点、文字少它就上去一点，三个按钮位置不固定，很难受。"
       ⇒ 原来第一个按钮只吃 10px 上边距、整组跟在文字后头 ⇒ 位置随文字行数上下漂。
         现在改成**压到底部**：
           · `margin-top:auto` —— 对话框是固定高度 380 的 flex 列，这个 auto 把**第一个按钮连同后面两个**
             一起推到底（上面的文字多一行少一行都不再影响按钮位置）；
           · 最后一个按钮去掉 5px 下边距 + 容器下内边距 24px（见上面那条 `padding` 的第三值）
             ⇒ **底部留白 = 左右留白 = 24px**。
       ⚠ 这两个弹窗（「料单/图纸上传」与「替换/保留/跳过 文件」）**共用这一套类**，所以一起生效、外观继续一致。
       ⚠ 那两条规则要写在**下面 `.mc-row` 基础规则之后** —— 同特异度时后写的赢，而 `.mc-row` 的
         `margin: 5px 0` 是简写，写在它前面的话 `margin-top:auto` 会被它盖掉（原来那条 10px 就是这么失效的）。 */
    .mouse-confirm.ld-conflict .mc-row {
      display: block; width: 100%; text-align: center;
      padding: 12px 16px; margin: 5px 0;
      font-size: 18px; border: 3px solid transparent; border-radius: 6px;
      cursor: pointer; background: var(--sidebar-hover, #333); color: var(--text);
      transition: background .1s, border-color .1s;
      box-sizing: border-box;
    }
    .mouse-confirm.ld-conflict .mc-row:focus { outline: none; }   /* 去掉聚焦时浏览器默认边框，避免与选中高亮叠加 */
    .mouse-confirm.ld-conflict .mc-row:hover { background: var(--sidebar-border, #555); }
    .mouse-confirm.ld-conflict .mc-row.mc-selected { border-color: var(--primary, #36f); }
    /* ★ 2026-10-09（承上面那段说明）：三个大按钮**压到底部**、底部留白=左右留白=24px。
       ⚠ 必须写在这儿（`.mc-row` 基础规则之后），否则被它的 `margin: 5px 0` 简写盖掉。 */
    .mouse-confirm.ld-conflict .mc-line + .mc-row { margin-top: auto; }   /* 第一个按钮起把整组推到底部 */
    .mouse-confirm.ld-conflict .mc-row:last-child { margin-bottom: 0; }   /* 底部留白只由容器 padding 决定 */
    .mouse-confirm.ld-conflict .ld-apply-all { display: flex; align-items: center; gap: 8px; font-size: 17px; color: var(--text); cursor: pointer; user-select: none; }
    .mouse-confirm.ld-conflict .ld-apply-all input { cursor: pointer; width: 18px; height: 18px; }   /* 勾选框加大约30% */
    @keyframes ldConflictIn { from { opacity: 0; } to { opacity: 1; } }

    /* ── 桌面推送弹窗（.dp-dialog 复用的遮罩/面板基础样式） ── */
    .ann-overlay {
      position: fixed; inset: 0; z-index: 9999;
      background: rgba(0,0,0,0.65);
      display: flex; align-items: center; justify-content: center;
      backdrop-filter: blur(4px);
    }
    .ann-popup {
      background: var(--panel, #fff);
      border-radius: 20px;
      width: 90vw; max-width: 680px; max-height: 88vh;
      overflow-y: auto;
      box-shadow: 0 24px 80px rgba(0,0,0,0.35);
      padding: 36px 40px;
      position: relative;
      animation: annFadeIn .3s ease;
    }
    /* 桌面图标推送对话框：**不要页面蒙版**（2026-09-11 用户）—— 去掉深色遮罩与毛玻璃，
       只留"铺满视口、把对话框居中的容器"（仍挡住下层点击以保持模态；点对话框外不关闭）。 */
    .ann-overlay.dp-overlay { background: transparent; backdrop-filter: none; -webkit-backdrop-filter: none; }
    @keyframes annFadeIn { from { opacity:0; transform:translateY(20px); } to { opacity:1; transform:translateY(0); } }
    .ann-popup h2 { font-size: 26px; margin: 0 0 8px; color: var(--text,#222); }
    .ann-popup .ann-body { font-size: 17px; line-height: 1.75; color: var(--text,#333); margin: 16px 0; white-space: pre-wrap; }
    .ann-popup .ann-actions { display: flex; gap: 12px; justify-content: flex-end; margin-top: 20px; flex-wrap: wrap; }
    .ann-popup .ann-actions button {
      padding: 10px 28px; border-radius: 10px; border: 1px solid var(--line,#ccc);
      background: var(--panel,#f5f5f5); color: var(--text,#333); cursor: pointer; font-size: 14px;
      transition: all .15s;
    }
    .ann-popup .ann-actions .btn-primary { background: var(--primary,#36f); color: #fff; border-color: var(--primary,#36f); }
    .ann-popup .ann-actions .btn-danger { color: #e74c3c; border-color: #e74c3c; }
    .ann-popup .ann-actions button:hover { opacity: 0.85; }

    /* 桌面图标推送对话框（发送「推送给用户」/ 接收端）：统一字体层级 ——
       2026-09-10 用户：标题 22px / 中号 18px / 最小号 16px；无角标、内边距收窄 */
    .dp-dialog { font-size: 18px; padding: 24px 26px; }      /* 中号：正文 / 选项 / 分组标签 */
    .dp-dialog h2 { font-size: 22px; line-height: 1.35; }   /* 标题 */
    .dp-dialog .ann-body { font-size: 18px; }               /* 说明文字（覆盖通用 17px） */
    /* 按钮：必须写 .ann-actions button（0,2,1），否则被上面 `.ann-popup .ann-actions button`
       的 14px 压掉（2026-09-10 用户反馈按钮不是 16px）；三个按钮强制一行、文字左右内边距 20px */
    .dp-dialog .ann-actions { flex-wrap: nowrap; }
    .dp-dialog .ann-actions button {
      font-size: 16px; white-space: nowrap;
      padding-left: 20px; padding-right: 20px;
    }
    .dp-dialog input[type="text"] { font-size: 18px; }       /* 输入框：中号（input 不继承字号） */

    /* 推送端（发送）窗体：总高固定 450px，内容不撑高；「推送范围」行吸收剩余高度，
       列表区内部滚动；列表底到按钮间距 10px（2026-09-10 用户） */
    .dp-dialog.dp-send {
      height: 450px; box-sizing: border-box;
      display: flex; flex-direction: column;
    }
    .dp-dialog.dp-send > * { flex: 0 0 auto; }
    .dp-dialog.dp-send > .dp-scope-row { flex: 1 1 auto; min-height: 0; }
    .dp-dialog.dp-send > .ann-actions { margin-top: 10px; }
    /* 列表区：用户名单行排列、不足则滚动、隐藏滚动条（2026-09-10 用户） */
    .dp-dialog.dp-send .dp-scope-list { overflow-x: hidden; scrollbar-width: none; -ms-overflow-style: none; }
    .dp-dialog.dp-send .dp-scope-list::-webkit-scrollbar { width: 0; height: 0; }
    .dp-dialog.dp-send .dp-scope-list label { white-space: nowrap; }
    .dp-dialog.dp-send .dp-scope-list .dp-user-name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
    /* 列表内文字统一 16px（写死，避免被 .dp-dialog 的 18px 影响） */
    .dp-dialog.dp-send .dp-scope-list,
    .dp-dialog.dp-send .dp-scope-list label,
    .dp-dialog.dp-send .dp-scope-list .dp-user-name { font-size: 16px; }

    /* 锁屏覆盖层（2026-09-06）：Alt+L 回到桌面并锁屏；淡遮罩透出壁纸背景（无毛玻璃）
       左上角小锁 <-> 解锁对话框 切换；刷新后仍锁定（sessionStorage 持久化） */
    #ldLockScreen {
      position: fixed; inset: 0; z-index: 999999;
      display: none; background: rgba(0, 0, 0, 0.35);
    }
    .ld-lock-badge {
      position: fixed; top: 16px; left: 16px; z-index: 1000000;
      display: inline-flex; align-items: center; gap: 8px;
      padding: 8px 14px; background: rgba(0, 0, 0, 0.55); color: #fff;
      border: none; border-radius: 8px; cursor: pointer; line-height: 1;
      box-shadow: 0 4px 16px rgba(0, 0, 0, 0.3);
    }
    .ld-lock-badge-icon { font-size: 18px; }
    .ld-lock-badge-txt { font-size: 14px; }
    #ldLockDialog {
      position: fixed; inset: 0; z-index: 1000001;
      display: flex; align-items: center; justify-content: center;
    }
    .ld-lock-box {
      background: var(--panel, #fff);
      border: 1px solid var(--line, #ddd); border-radius: 16px;
      padding: 26px; text-align: center; width: 360px;
      box-shadow: 0 18px 60px rgba(0, 0, 0, 0.45);
    }
    .ld-lock-dlg-head {
      display: flex; align-items: center; justify-content: space-between;
      margin-top: -10px; margin-bottom: 35px;
    }
    .ld-lock-icon { font-size: 40px; line-height: 1; }
    .ld-lock-title { font-size: 28px; font-weight: 700; color: var(--text,#333); }
    .ld-lock-close {
      border: none; background: transparent; font-size: 32px; cursor: pointer;
      color: var(--muted,#888); padding: 4px 12px; line-height: 1;
      transform: translateX(15px);
    }
    .ld-lock-close:hover { color: #e74c3c; }
    .ld-lock-sub { font-size: 16px; color: var(--muted,#888); margin-top: 6px; }
    .ld-lock-input {
      width: 100%; padding: 12px 14px; margin-top: 20px;
      border: 1px solid var(--line,#ccc); border-radius: 10px;
      font-size: 16px; box-sizing: border-box; background: var(--panel,#fafafa);
      color: var(--text,#333); outline: none;
    }
    .ld-lock-input:focus { border-color: #3b82f6; }
    .ld-lock-err { color: #e74c3c; font-size: 14px; line-height: 20px; height: 20px; margin-top: 10px; visibility: hidden; }
    .ld-lock-err.show { visibility: visible; }
    .ld-lock-btns { margin-top: 18px; }
    .ld-lock-btn { width: 100%; padding: 11px; font-size: 20px; }

    /* 隐藏非活跃分�?*/
    .project-group-row.group-hidden {
      display: none !important;
    }

    /* 权限设置页面 */
    .perm-role-level { font-size: 12px; color: var(--muted); }
    .perm-list { display: flex; flex-direction: column; gap: 5px; }
    .perm-item {
      display: flex;
      align-items: center;
      justify-content: space-between;
      gap: 12px;
      padding: 5px 14px;
      border-radius: 12px;
      background: var(--panel-soft);
      border: 1px solid var(--line);
    }
    .perm-item label { font-size: 14px; color: var(--text); font-weight: 500; }
    .perm-item input[type="checkbox"] {
      width: 18px; height: 18px; accent-color: var(--primary); cursor: pointer;
    }
    .perm-item-desc { font-size: 12px; color: var(--muted); margin-top: 2px; }

    .section-head h3 { margin: 0; }
    .muted { color: var(--muted); }

    .table-wrap { overflow: auto; border-radius: 16px; border: 1px solid var(--line); }
    table { width: 100%; border-collapse: collapse; background: var(--table-bg); min-width: 860px; }
    th, td { padding: 14px 15px; text-align: left; border-bottom: 1px solid var(--line); font-size: 14px; white-space: nowrap; }
    th { background: var(--table-head-bg); color: var(--table-head-text); font-size: 13px; font-weight: 800; }
    tr:hover td { background: var(--row-hover); }
    tr:last-child td { border-bottom: 0; }

    .tag {
      display: inline-flex;
      align-items: center;
      height: 26px;
      padding: 0 9px;
      border-radius: 999px;
      font-size: 12px;
      font-weight: 700;
      background: var(--tag-bg);
      color: var(--tag-text);
    }
    .tag.blue { background: var(--tag-blue-bg); color: var(--tag-blue-text); }
    .tag.green { background: var(--tag-green-bg); color: var(--tag-green-text); }
    .tag.orange { background: var(--tag-orange-bg); color: var(--tag-orange-text); }
    .tag.red { background: var(--tag-red-bg); color: var(--tag-red-text); }
    .tag.purple { background: var(--tag-purple-bg); color: var(--tag-purple-text); }

    .progress {
      height: 9px;
      border-radius: 999px;
      background: var(--progress-bg);
      overflow: hidden;
    }
    .progress span { display: block; height: 100%; border-radius: 999px; background: linear-gradient(90deg, var(--primary), var(--accent-2)); }

    .mini-chart { display: flex; align-items: end; gap: 10px; height: 185px; padding-top: 8px; }
    .bar { flex: 1; border-radius: 14px 14px 6px 6px; background: linear-gradient(180deg, var(--chart-start), var(--chart-end)); position: relative; min-width: 28px; }
    .bar::after { content: attr(data-label); position: absolute; bottom: -28px; left: 50%; transform: translateX(-50%); font-size: 12px; color: var(--muted); }
    .bar::before { content: attr(data-value); position: absolute; top: -24px; left: 50%; transform: translateX(-50%); font-size: 12px; color: var(--chart-value); font-weight: 800; }

    .timeline { position: relative; padding-left: 20px; display: grid; gap: 14px; }
    .timeline::before { content:""; position:absolute; left:5px; top:7px; bottom:7px; width:2px; background: var(--line); }
    .timeline-item { position: relative; background: var(--timeline-bg); border: 1px solid var(--line); border-radius: 14px; padding: 12px 14px; }
    .timeline-item::before { content:""; position:absolute; left:-20px; top:16px; width:11px; height:11px; border-radius:999px; background: var(--primary); box-shadow: 0 0 0 4px var(--timeline-ring), 0 0 14px var(--glow-primary); }
    .timeline-item b { display: block; font-size: 14px; margin-bottom: 4px; }
    .timeline-item span { font-size: 13px; color: var(--muted); }

    .kanban { display: grid; grid-template-columns: repeat(4, minmax(220px, 1fr)); gap: 14px; overflow-x: auto; }
    .lane { background: var(--lane-bg); border: 1px dashed var(--lane-border); border-radius: 18px; padding: 14px; min-height: 280px; }
    .lane h4 { margin: 0 0 12px; display:flex; justify-content:space-between; align-items:center; }
    .task-card { background: var(--task-bg); border: 1px solid var(--line); border-radius: 15px; padding: 13px; margin-bottom: 10px; cursor: grab; box-shadow: var(--task-shadow); }
    .task-card:active { cursor: grabbing; }
    .task-card b { display: block; margin-bottom: 6px; }
    .task-card small { color: var(--muted); display: block; line-height: 1.6; }

    .form-grid { display: grid; grid-template-columns: repeat(2, minmax(0,1fr)); gap: 12px; }
    .field label { display:block; color: var(--muted); font-size: 12px; margin-bottom: 6px; font-weight: 700; }
    .field input, .field select, .field textarea {
      width: 100%;
      border: 1px solid var(--line);
      border-radius: 12px;
      padding: 11px 12px;
      outline: none;
      background: var(--input-bg);
      color: var(--input-text);
      font-family: inherit;
    }
    .field textarea { min-height: 90px; resize: vertical; }
    .field.full { grid-column: 1 / -1; }

    .alert-list { display: grid; gap: 10px; }
    .alert {
      display: flex;
      gap: 12px;
      padding: 13px;
      border-radius: 15px;
      border: 1px solid var(--line);
      background: var(--panel);
      align-items: flex-start;
    }
    .alert .dot { width: 10px; height: 10px; border-radius: 50%; margin-top: 5px; flex: 0 0 auto; }
    .dot.red { background: var(--red); }
    .dot.orange { background: var(--orange); }
    .dot.green { background: var(--green); }
    .alert b { display:block; margin-bottom:3px; }
    .alert span { color: var(--muted); font-size: 13px; }

    /* ── 零度领眸 ── */
    /* 2026-09-15 用户（领眸页改版）：原来此处有 `#warning .monitor-modes.stl-group-tabs{padding:0;margin:0}`
       给顶部两个二级标签（零度领眸 / 设备管理）清默认内边距 —— 这两个标签已删除（设备管理改名「监控设置」
       挪进左下系统设置卡片），容器也没了，故该规则一并删除。
       现行头排 = 左侧 .monitor-controls（4/6/8/16 画面按钮，原来在右侧）；行距页面顶部仍 = .main padding-top
       （18px 体系，Bug 记录：勿再加 margin/padding-top 破坏 18px）。 */
    .monitor-header { display:flex; align-items:center; justify-content:space-between; padding:0 4px 12px 4px; flex-shrink:0; }
    .monitor-controls { display:flex; gap:6px; }
    /* 2026-09-03：4/6/8/16 画面按钮与二级导航标签同高 41px、同字号 17px（用户要求；2026-09-15 起这排按钮
       本身就是本页的二级导航，位置在左侧） */
    .monitor-layout-btn {
      height:41px; padding:0 16px; border-radius:20px; border:1px solid var(--line);
      background:var(--panel); color:var(--text); cursor:pointer; font-size:17px; transition:all .2s;
      display:inline-flex; align-items:center; justify-content:center; gap:4px; line-height:1;
      white-space:nowrap;   /* 2026-09-11 用户：按钮文字不允许换行 */
    }
    .monitor-layout-btn:hover,
    .monitor-layout-btn.active { background:var(--primary-soft); border-color:var(--primary); color:var(--primary); }
    .monitor-layout-btn.active { box-shadow:0 2px 8px color-mix(in srgb, var(--primary) 20%, transparent); }
    .monitor-layout-btn .grid-icon { width:18.2px; height:18.2px; flex:0 0 auto; transform:translateY(-1px); }   /* 2026-09-03 用户：画面图标加大30%(14→18.2px)；图标相对文字上移1px（2026-09-04 由2px改为1px） */
    /* 2026-09-03 用户：8画面为4列图形，若也按 18.2px 宽渲染会让点显示小于6画面(3列)；
       单独放宽其图标显示宽度使点与6画面等大（缩放比同为 0.667），点间空隙随之与6画面一致 */
    .monitor-layout-btn .grid-icon.grid-icon-8 {
      width: 24.3px;
      height: 18.2px;
    }

    .monitor-container { flex:1; display:flex; gap:10px; min-height:0; }
    .monitor-sidebar {
      width:200px; flex-shrink:0; overflow-y:auto; display:flex; flex-direction:column; gap:3px;
      padding-right:4px;
      scrollbar-width:none;
    }
    .monitor-sidebar::-webkit-scrollbar { display:none; }
    .monitor-sidebar-active { border-color:var(--accent) !important; background:var(--hover) !important; }

    .monitor-grid { flex:1; display:grid; gap:6px; min-height:0; align-content:start; }
    .grid-2x2 { grid-template-columns:repeat(2,1fr); grid-template-rows:repeat(2,1fr); }
    .grid-3x2 { grid-template-columns:repeat(3,1fr); grid-template-rows:repeat(2,1fr); }
    .grid-4x2 { grid-template-columns:repeat(4,1fr); grid-template-rows:repeat(2,1fr); }
    .grid-4x4 { grid-template-columns:repeat(4,1fr); grid-template-rows:repeat(4,1fr); }

    .monitor-cell {
      background:var(--panel); border-radius:14px;
      border:2px solid var(--line); cursor:pointer; transition:all .15s;
      display:flex; flex-direction:column;
      min-height:0; overflow:hidden; position:relative;
    }
    .monitor-cell:hover { border-color:var(--accent); transform:translateY(-1px); box-shadow:0 4px 16px rgba(0,0,0,.08); }
    .monitor-cell.status-ok { border-color:var(--line); }
    .monitor-cell.status-warn { border-color:var(--orange); }
    .monitor-cell.status-danger { border-color:var(--red); animation:pulse-danger 2s infinite; }
    @keyframes pulse-danger { 0%,100%{border-color:var(--red)}50%{border-color:transparent} }

    /* 网格摄像头缩略图 */
    .cell-thumb {
      flex:1; min-height:40px; background:var(--bg) center/cover no-repeat;
    }
    .cell-info { padding:5px 8px; display:flex; flex-direction:column; gap:1px; }
    .cell-name { font-size:11px; font-weight:700; }
    .cell-loc { font-size:10px; color:var(--muted); }
    .cell-status {
      position:absolute; top:5px; right:5px; padding:1px 7px; border-radius:8px;
      font-size:10px; font-weight:700; color:#fff; z-index:1;
    }
    .cell-status.ok { background:var(--green); }
    .cell-status.warn { background:var(--orange); }
    .cell-status.danger { background:var(--red); }

    /* 侧边栏摄像头 */
    .sidebar-cam { flex-direction:row !important; gap:8px; padding:6px 8px; align-items:center; }
    .cell-thumb-sm { width:40px; height:30px; border-radius:6px; background:var(--bg) center/cover no-repeat; flex-shrink:0; }
    .cell-info-sm { flex:1; min-width:0; display:flex; flex-direction:column; gap:1px; }
    .cell-status-dot { width:6px; height:6px; border-radius:50%; flex-shrink:0; }
    .cell-status-dot.ok { background:var(--green); }
    .cell-status-dot.warn { background:var(--orange); }
    .cell-status-dot.danger { background:var(--red); }

    .monitor-detail {
      flex:1; min-height:0; background:var(--panel); border-radius:18px;
      display:flex; flex-direction:column; border:2px solid var(--accent);
      overflow:hidden;
    }
    .detail-topbar {
      height:36px; min-height:36px; display:flex; align-items:center; gap:12px;
      padding:0 20px; border-bottom:1px solid var(--line); flex-shrink:0;
    }
    .detail-topbar-title { font-size:18px; font-weight:700; flex:1; }
    .detail-status-sm {
      padding:3px 10px; border-radius:10px; font-size:12px; font-weight:600; color:#fff; width:52px; text-align:center;
    }
    .detail-status-sm.ok { background:var(--green); }
    .detail-status-sm.warn { background:var(--orange); }
    .detail-status-sm.danger { background:var(--red); }
    .detail-close-btn { height:22px; font-size:12px; padding:0 8px; line-height:1; border-radius:10px; width:52px; }
    .detail-main { flex:1; display:flex; min-height:0; }
    .detail-expanded {
      flex:1; display:flex; min-width:0; position:relative;
    }
    .detail-feed {
      flex:1; background:var(--bg) center/cover no-repeat;
      display:flex; align-items:flex-end;
    }
    .feed-overlay {
      width:100%; padding:12px 20px; background:linear-gradient(transparent,rgba(0,0,0,.7));
      display:flex; align-items:center; gap:16px;
    }
    .feed-label { font-size:18px; font-weight:700; color:#fff; }
    .feed-loc { font-size:13px; color:rgba(255,255,255,.7); }
    .feed-rec { margin-left:auto; color:var(--red); font-size:12px; font-weight:700; animation:pulse-rec 1.5s infinite; }
    @keyframes pulse-rec { 0%,100%{opacity:1}50%{opacity:.3} }

    .detail-alarms {
      width:300px; min-width:300px; border-left:1px solid var(--line);
      display:flex; flex-direction:column; overflow:hidden;
    }
    .alarms-title {
      font-size:15px; font-weight:700; padding:14px 18px;
      border-bottom:1px solid var(--line); flex-shrink:0;
    }
    .alarms-list { flex:1; overflow-y:auto; padding:8px 12px; }
    .alarms-empty { color:var(--muted); text-align:center; padding:40px 0; font-size:13px; }
    .alarm-item {
      display:flex; gap:10px; align-items:flex-start; padding:10px 8px;
      border-radius:10px; transition:background .15s;
    }
    .alarm-item:hover { background:var(--hover); }
    .alarm-dot { width:8px; height:8px; border-radius:50%; margin-top:6px; flex-shrink:0; }
    .alarm-dot.danger { background:var(--red); }
    .alarm-dot.warn { background:var(--orange); }
    .alarm-item b { display:block; font-size:13px; margin-bottom:2px; }
    .alarm-item span { font-size:12px; color:var(--muted); }

    /* ── 设备管理（内联在零度领眸中）── */
    .ds-list-container {
      flex:1; min-height:0; display:flex; flex-direction:column; gap:10px; overflow:hidden;
    }
    .ds-toolbar {
      padding:12px 16px; display:flex; gap:10px; align-items:center; border-bottom:1px solid var(--line); flex-shrink:0;
    }
    .ds-search {
      flex:1; padding:8px 14px; border-radius:20px; border:1px solid var(--line);
      background:var(--bg); font-size:13px; outline:none;
    }
    .ds-search:focus { border-color:var(--accent); }
    .ds-filter {
      padding:8px 12px; border-radius:20px; border:1px solid var(--line);
      background:var(--bg); font-size:13px; outline:none; cursor:pointer;
    }
    .ds-list { flex:1; overflow-y:auto; padding:8px 12px; }
    .ds-item {
      display:flex; align-items:center; gap:12px; padding:12px 14px;
      border-radius:12px; background:var(--bg); margin-bottom:6px; transition:background .15s;
    }
    .ds-item:hover { background:var(--hover); }
    .ds-item-num { font-size:13px; font-weight:700; color:var(--muted); width:40px; flex-shrink:0; }
    .ds-item-fields { flex:1; display:flex; flex-direction:column; gap:6px; }
    .ds-row { display:flex; gap:8px; }
    .ds-row input, .ds-row select {
      padding:6px 10px; border-radius:8px; border:1px solid var(--line);
      background:var(--panel); font-size:12px; outline:none; transition:border-color .15s;
    }
    .ds-row input:focus, .ds-row select:focus { border-color:var(--accent); }
    .ds-name { width:90px; }
    .ds-loc { flex:1; }
    .ds-type { width:100px; }
    .ds-url { flex:1; font-size:11px !important; }
    .ds-status { margin-left:auto; display:flex; align-items:center; gap:6px; }
    .ds-status-dot { width:8px; height:8px; border-radius:50%; }
    .ds-status-dot.ok { background:var(--green); }
    .ds-status-dot.warn { background:var(--orange); }
    .ds-status-dot.danger { background:var(--red); }

    /* Dynamic national map page */
    .map-page { display: flex; flex-direction: column; height: 100%; width: 100%; min-width: 0; min-height: 0; }

    .map-hero {
      flex: 1;
      min-height: 0;
      min-width: 0;
      padding: 0;
      background: var(--card);
      border: 1px solid var(--line);
      isolation: isolate;
      overflow: hidden;
    }

    .card.map-hero::before { content: none !important; display: none !important; }
    .map-hero::after { content: none !important; display: none !important; }

    .map-stage {
      position: relative;
      z-index: 1;
      height: 100%;
      width: 100%;
      min-width: 0;
      display: grid;
      grid-template-columns: 22fr 78fr;
      grid-template-rows: 1fr;
      gap: 18px;
      padding: 2px 0 0;
      overflow: hidden;
    }

    .map-top {
      grid-column: 1 / -1;
      display: flex;
      justify-content: space-between;
      align-items: center;
      gap: 16px;
      padding: 4px 6px 2px;
    }

    .map-title-kicker {
      color: var(--accent-2);
      font-size: 12px;
      font-weight: 900;
      letter-spacing: .18em;
      text-transform: uppercase;
    }

    .map-top h3 {
      margin: 7px 0 4px;
      font-size: 26px;
      letter-spacing: .04em;
    }

    .map-top p { margin: 0; color: var(--muted); font-size: 13px; }

    .map-kpi-row {
      display: grid;
      grid-template-columns: repeat(4, minmax(108px, 1fr));
      gap: 10px;
      min-width: min(650px, 58vw);
    }

    .map-kpi {
      min-height: 48px;
      padding: 8px 15px;
      border-radius: 16px;
      border: 1px solid var(--line);
      background: var(--card-gradient);
      box-shadow: inset 0 0 24px var(--card-highlight), 0 12px 28px rgba(0,0,0,.18);
      position: relative;
      overflow: hidden;
    }

    .map-kpi::before {
      content: "";
      position: absolute;
      inset: 0;
      background: linear-gradient(110deg, transparent 0 36%, rgba(255,255,255,.12) 47%, transparent 58% 100%);
      transform: translateX(-120%);
      animation: mapSweep 4.8s infinite;
    }

    .map-kpi b { display: flex; align-items: baseline; gap: 2px; margin-top: 0; font-size: 26px; color: var(--text); justify-content: center; }
    .map-kpi em { font-style: normal; font-size: 13px; color: var(--accent-2); margin-left: 3px; }

    .map-panel {
      border: 1px solid var(--line);
      border-radius: 20px;
      background: var(--panel);
      overflow: hidden;
    }

    .map-left { display: grid; grid-template-rows: 1fr 1fr; gap: 16px; min-width: 0; overflow: hidden; }
    .map-left .map-panel { display: flex; flex-direction: column; min-height: 0; }
    .map-left .map-panel-body { flex: 1; overflow-y: auto; min-height: 0; }

    .map-panel-head {
      display: flex;
      align-items: center;
      justify-content: space-between;
      gap: 10px;
      padding: 15px 16px;
      border-bottom: 1px solid var(--line);
    }

    .map-panel-head h4 { margin: 0; font-size: 15px; letter-spacing: .04em; }
    .map-panel-head span { color: var(--accent-2); font-size: 12px; }

    .map-panel-body { padding: 14px 16px 16px; }

    .map-rank-list,
    .map-alert-feed,
    .map-dispatch-list {
      display: grid;
      gap: 12px;
    }

    .map-rank-item,
    .map-alert-item,
    .map-dispatch-item {
      position: relative;
      padding: 12px 12px;
      border-radius: 16px;
      border: 1px solid var(--line);
      background: var(--panel-soft);
    }

    .map-rank-item b,
    .map-alert-item b,
    .map-dispatch-item b { display: block; font-size: 13px; margin-bottom: 6px; }
    .map-rank-item span,
    .map-alert-item span,
    .map-dispatch-item span { display: block; color: var(--muted); font-size: 12px; line-height: 1.45; }

    .map-progress {
      height: 7px;
      margin-top: 10px;
      border-radius: 999px;
      background: var(--progress-bg);
      overflow: hidden;
    }
    .map-progress i { display: block; height: 100%; border-radius: 999px; background: linear-gradient(90deg, var(--primary), var(--accent-2)); box-shadow: 0 0 14px var(--glow-primary); }

    .map-dot-mini {
      width: 8px;
      height: 8px;
      display: inline-block;
      border-radius: 999px;
      margin-right: 7px;
      background: var(--accent-2);
      box-shadow: 0 0 14px currentColor;
    }
    .map-dot-mini.orange { background: var(--huolicheng); }
    .map-dot-mini.green { background: var(--green); }
    .map-dot-mini.red { background: var(--red); }

    .map-center {
      position: relative;
      border-radius: 24px;
      border: 1px solid var(--line);
      background: var(--panel);
      overflow: hidden;
      display: flex;
      flex-direction: column;
      min-height: 0;
      min-width: 0;
    }
    .map-center::before,
    .map-center::after {
      content: "";
      position: absolute;
      top: 100px; left: 0; right: 0; bottom: -300px;
      border-radius: inherit;
      pointer-events: none;
      z-index: 0;
    }
    .map-center::before {
      background:
        radial-gradient(ellipse 70% 35% at 25% 35%, var(--bg-spot-b), transparent 78%),
        radial-gradient(ellipse 55% 30% at 42% 28%, var(--bg-spot-a), transparent 76%),
        radial-gradient(ellipse 60% 38% at 58% 32%, var(--bg-spot-b), transparent 78%),
        radial-gradient(ellipse 80% 32% at 78% 38%, var(--bg-spot-a), transparent 78%),
        radial-gradient(ellipse 50% 28% at 35% 50%, var(--bg-spot-b), transparent 74%),
        radial-gradient(ellipse 65% 30% at 65% 55%, var(--bg-spot-a), transparent 76%);
      opacity: .50;
    }
    .map-center::after {
      background:
        radial-gradient(ellipse 45% 22% at 15% 42%, var(--bg-spot-b), transparent 74%),
        radial-gradient(ellipse 50% 25% at 50% 22%, var(--bg-spot-a), transparent 76%),
        radial-gradient(ellipse 55% 28% at 85% 30%, var(--bg-spot-b), transparent 74%);
      opacity: .30;
    }

    @keyframes mapCloudFloat {
      0%, 100% { transform: translateY(110px) translateX(0); }
      25% { transform: translateY(75px) translateX(-50px); }
      50% { transform: translateY(110px) translateX(60px); }
      75% { transform: translateY(145px) translateX(-50px); }
    }
    @keyframes mapCloudDrift {
      0%, 100% { transform: translateY(110px) translateX(0) scale(1); }
      33% { transform: translateY(75px) translateX(-60px) scale(1.06); }
      66% { transform: translateY(145px) translateX(60px) scale(0.95); }
    }
    .map-center .map-echarts-wrap { flex: 1; min-height: 0; min-width: 0; overflow: hidden; position: relative; z-index: 1; }
    .map-center #echartsMap { width: 100% !important; height: 100% !important; }
    .map-center #echartsMap > div,
    .map-center #echartsMap canvas { width: 100% !important; height: 100% !important; max-width: 100% !important; max-height: 100% !important; }

    .map-breadcrumb {
      position: absolute;
      top: 12px;
      left: 16px;
      z-index: 5;
      display: flex;
      align-items: center;
      gap: 8px;
      font-size: 13px;
      color: var(--muted);
    }
    .map-breadcrumb-back {
      background: var(--primary-soft);
      border: 1px solid var(--primary);
      color: var(--primary);
      border-radius: 8px;
      padding: 4px 12px;
      cursor: pointer;
      font-size: 13px;
      font-weight: 700;
      transition: .2s;
      opacity: .6;
    }
    .map-breadcrumb-back:hover {
      opacity: 1;
      background: var(--primary-soft);
    }
    .map-breadcrumb-path {
      background: var(--panel-soft);
      border: 1px solid var(--line);
      border-radius: 999px;
      padding: 5px 16px;
      font-weight: 700;
      color: var(--text);
    }

    /* 区县级数据详情面�?*/
    .county-detail-panel {
      position: absolute;
      top: 0;
      left: 0;
      right: 0;
      bottom: 0;
      z-index: 10;
      background: linear-gradient(180deg, var(--panel), var(--bg-deep));
      border-radius: 24px;
      padding: 20px;
      overflow-y: auto;
      animation: countyPanelIn .3s ease;
    }
    @keyframes countyPanelIn {
      from { opacity: 0; transform: translateY(10px); }
      to { opacity: 1; transform: translateY(0); }
    }
    .county-detail-header {
      display: flex;
      align-items: center;
      gap: 12px;
      margin-bottom: 20px;
      padding-bottom: 16px;
      border-bottom: 1px solid var(--line);
    }
    .county-detail-close {
      width: 32px;
      height: 32px;
      border-radius: 8px;
      border: 1px solid var(--line);
      background: var(--panel-soft);
      color: var(--text);
      cursor: pointer;
      font-size: 18px;
      display: flex;
      align-items: center;
      justify-content: center;
      transition: .2s;
      line-height: 1;
    }
    .county-detail-close:hover {
      background: var(--primary-soft);
      border-color: var(--primary);
    }
    .county-detail-header h4 {
      font-size: 22px;
      color: var(--text);
      margin: 0;
    }
    .county-detail-header span {
      color: var(--muted);
      font-size: 13px;
    }
    .county-kpi-row {
      display: grid;
      grid-template-columns: repeat(4, 1fr);
      gap: 12px;
      margin-bottom: 20px;
    }
    .county-kpi {
      padding: 16px;
      border-radius: 16px;
      border: 1px solid var(--line);
      background: var(--panel-soft);
      text-align: center;
    }
    .county-kpi span {
      display: block;
      color: var(--muted);
      font-size: 12px;
      margin-bottom: 8px;
    }
    .county-kpi b {
      display: block;
      color: var(--text);
      font-size: 28px;
      font-weight: 800;
    }
    .county-kpi b span {
      font-size: 14px;
      font-weight: 400;
      color: var(--muted);
      margin-left: 2px;
    }
    .county-table {
      margin-bottom: 20px;
      border-radius: 16px;
      border: 1px solid var(--line);
      overflow: hidden;
      background: var(--panel-soft);
    }
    .county-table table {
      width: 100%;
      border-collapse: collapse;
    }
    .county-table th {
      padding: 12px 16px;
      text-align: left;
      font-size: 12px;
      color: var(--muted);
      background: var(--bg-deep);
      border-bottom: 1px solid var(--line);
      font-weight: 600;
    }
    .county-table td {
      padding: 12px 16px;
      font-size: 13px;
      color: var(--text);
      border-bottom: 1px solid var(--line);
    }
    .county-table tr:last-child td {
      border-bottom: none;
    }
    .county-table .status-badge {
      display: inline-block;
      padding: 2px 10px;
      border-radius: 999px;
      font-size: 11px;
      font-weight: 600;
    }
    .status-ok {
      background: rgba(34, 197, 94, .15);
      color: #4ade80;
      border: 1px solid rgba(34, 197, 94, .3);
    }
    .status-warn {
      background: rgba(251, 191, 36, .15);
      color: #fbbf24;
      border: 1px solid rgba(251, 191, 36, .3);
    }
    .status-danger {
      background: rgba(239, 68, 68, .15);
      color: #f87171;
      border: 1px solid rgba(239, 68, 68, .3);
    }
    .county-projects h5 {
      font-size: 14px;
      color: var(--text);
      margin: 0 0 12px 0;
    }
    .county-project-item {
      padding: 12px 16px;
      border-radius: 12px;
      border: 1px solid var(--line);
      background: var(--panel-soft);
      margin-bottom: 8px;
    }
    .county-project-item b {
      display: block;
      color: var(--text);
      font-size: 14px;
      margin-bottom: 4px;
    }
    .county-project-item span {
      color: var(--muted);
      font-size: 12px;
    }

    .map-bottom {
      grid-column: 1 / -1;
      display: grid;
      grid-template-columns: 1.2fr .8fr 1fr;
      gap: 16px;
    }

    .city-detail {
      display: grid;
      grid-template-columns: 1fr 1fr;
      gap: 12px;
    }
    .city-detail-card {
      border-radius: 16px;
      padding: 13px;
      background: var(--panel-soft);
      border: 1px solid var(--line);
    }
    .city-detail-card span { display:block; color: var(--muted); font-size:12px; }
    .city-detail-card b { display:block; margin-top:6px; font-size:20px; color: var(--text); }

    .map-ticker {
      overflow: hidden;
      white-space: nowrap;
      border-radius: 999px;
      border: 1px solid var(--line);
      background: var(--bg-deep);
      height: 42px;
      display: flex;
      align-items: center;
      margin-top: 12px;
    }
    .map-ticker-track {
      display: inline-flex;
      gap: 34px;
      padding-left: 100%;
      animation: tickerMove 24s linear infinite;
      color: var(--text);
      font-size: 13px;
    }
    .map-ticker-track em { color: var(--accent-2); font-style: normal; }

    @keyframes mapSweep { 0%, 42% { transform: translateX(-120%); } 68%, 100% { transform: translateX(120%); } }
    @keyframes mapRain { to { transform: translate3d(-90px, 90px, 0); } }
    @keyframes mapRotate { to { transform: rotate(360deg); } }
    @keyframes mapScan { 0%, 100% { transform: translateY(0); opacity: .25; } 50% { transform: translateY(430px); opacity: .88; } }
    @keyframes routeFlow { to { stroke-dashoffset: -68; } }
    @keyframes cityPulse { 0%,100% { r: 14; opacity: .56; } 50% { r: 28; opacity: .12; } }
    @keyframes tickerMove { to { transform: translateX(-100%); } }

    @media (max-width: 1380px) {
      .map-kpi-row { min-width: min(560px, 52vw); }
    }

    @media (max-width: 1180px) {
      .map-stage { grid-template-columns: 1fr; grid-template-rows: auto auto auto; }
      .map-top { flex-direction: column; align-items: flex-start; }
      .map-kpi-row { width: 100%; min-width: 0; }
      .map-left { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 16px; }
      .map-left .map-panel { min-width: 0; }
    }

    @media (max-width: 720px) {
      .map-stage { padding: 12px; }
      .map-kpi-row, .map-left { grid-template-columns: 1fr; }
      .map-center { min-height: 460px; }
      .map-top h3 { font-size: 22px; }
    }

    .toast {
      position: fixed;
      left: 50%;
      top: 20px;
      transform: translateX(-50%) translateY(-30px);
      background: var(--toast-bg);
      color: var(--toast-text);
      padding: 13px 28px;
      border-radius: 14px;
      box-shadow: var(--shadow);
      opacity: 0;
      pointer-events: none;
      transition: .25s;
      z-index: 80;
      white-space: nowrap;
    }
    .toast.show { transform: translateX(-50%) translateY(0); opacity: 1; }
    .toast-error { background: #dc3545 !important; color: #fff !important; }

    /* 游客身份提示条（2026-09-10 用户；2026-09-19 改间歇提醒）：浏览器顶部、透明红。
       显示节奏由 JS 控制（每次显示 1 分钟 → 隐藏 → 隔 15 分钟再显示，循环，见 lingdu-core.js ldgGuestNotice）。
       层级 55：压过内容/顶栏（20），但低于弹窗（60）、toast（80）与各处全屏浮层，不遮挡交互 */
    .ldg-guest-notice {
      position: fixed;
      left: 50%;
      top: 24px;
      transform: translateX(-50%);
      z-index: 55;
      background: rgba(211, 47, 47, .55);
      color: #fff;
      border: 1px solid rgba(255, 255, 255, .28);
      padding: 10px 22px;
      border-radius: 8px;
      font-size: 20px;
      line-height: 1.4;
      box-shadow: 0 2px 10px rgba(180, 35, 24, .28);
      pointer-events: none;
      white-space: nowrap;
    }

    /* 长文案提示条（2026-09-11 客户端/网页账号不一致）：沿用游客提示条样式，
       仅放开换行并限宽，避免 nowrap 在窄窗口溢出视口 */
    .ldg-guest-notice.ldg-notice-long {
      white-space: normal;
      max-width: min(92vw, 1080px);
      text-align: center;
    }

    .modal-mask {
      position: fixed;
      inset: 0;
      background: var(--overlay);
      display: none;
      place-items: center;
      padding: 18px;
      z-index: 60;
    }
    .modal-mask.show { display: grid; }
    .modal { width: min(760px, 100%); background: var(--modal-bg); border-radius: 22px; padding: 20px; border: 1px solid var(--line); }
    .modal-head { display: flex; justify-content: space-between; align-items:center; margin-bottom: 16px; }
    .modal-head h3 { margin: 0; }
    .close { border: 0; background: var(--close-bg); color: var(--text); width: 34px; height: 34px; border-radius: 12px; cursor: pointer; }

    .mobile-menu { display: none; }

    @media (max-width: 1180px) {
      .grid.cols-4 { grid-template-columns: repeat(2, minmax(0,1fr)); }
      .grid.cols-3 { grid-template-columns: repeat(2, minmax(0,1fr)); }
    }

    @media (max-width: 860px) {
      .app,
      .app.sidebar-icon,
      .app.sidebar-hidden { grid-template-columns: 1fr; --sidebar-gap: 0px; }
      .sidebar,
      .app.sidebar-icon .sidebar {
        display: none;
        position: fixed;
        z-index: 90;
        left: 0;
        width: min(290px, 86vw);
        padding: 24px 18px;
        opacity: 1;
        pointer-events: auto;
        transform: none;
      }
      .app.sidebar-hidden .sidebar {
        width: 0;
        padding-left: 0;
        padding-right: 0;
        opacity: 0;
        pointer-events: none;
      }
      .sidebar.open { display: block; }
      .app.sidebar-hidden .sidebar.open { display: none; }
      .app.sidebar-icon .brand-text,
      .app.sidebar-icon .nav-label,
      .app.sidebar-icon .nav-title,
      .app.sidebar-icon .side-card {
        opacity: 1;
        width: auto;
        height: auto;
        overflow: visible;
        pointer-events: auto;
      }
      .app.sidebar-icon .nav-title { margin: 22px 8px 8px; padding: 0 0 0 5px; }
      .app.sidebar-icon .side-card { margin-top: 19px; padding: 12px; }
      .app.sidebar-icon .sidebar-footer { margin-top: auto; padding: 12px; border: 1px solid var(--sidebar-border); background: var(--sidebar-card-bg); }
      .app.sidebar-icon .sidebar-tool-title, .app.sidebar-icon .sidebar-tool-text { opacity: 1; width: auto; height: auto; overflow: visible; pointer-events: auto; }
      .app.sidebar-icon .sidebar-theme-select, .app.sidebar-icon .sidebar-logout-btn { width: 100%; height: 42px; font-size: 11px; color: var(--sidebar-text); }
      .app.sidebar-icon .sidebar-logout-btn { color: #fff; }
      .app.sidebar-icon .brand { justify-content: flex-start; gap: 12px; padding: 6px 6px 19px; }
      .app.sidebar-icon .nav { margin-top: 0; }
      .app.sidebar-icon .nav button { justify-content: flex-start; gap: 12px; padding: 11px 11px; font-size: 11px; }
      .mobile-menu { display: inline-flex; }
      .topbar { align-items: flex-start; flex-direction: column; position: static; }
      .top-actions { justify-content: flex-start; width: 100%; }
      .sidebar-state-controls { width: 100%; justify-content: space-between; }
      .sidebar-state-btn { flex: 1; padding: 0 6px; }
      .input { min-width: 100%; }
      .grid.cols-4, .grid.cols-3, .grid.cols-2 { grid-template-columns: 1fr; }
      .form-grid { grid-template-columns: 1fr; }
      .main { padding: 14px; }
    }

    /* ── 档位模式（html.ld-zoom-gear）下媒体查询失效修正（2026-08-12 用户反馈：
       浏览器300% 时 3 列卡片堆叠为 1 列）──
       档位系统里 视觉 = 设计稿 × 档位，浏览器页面缩放已被 html zoom 抵消；
       但媒体查询按 innerWidth（浏览器缩放后缩小，如 300% → 640）触发，
       误把 1180/860 的"小屏塌缩"套到设计稿布局上（3 列 → 1fr）。
       档位模式下布局应始终是设计稿列数（html zoom 负责视觉缩放），
       故以更高优先级恢复，覆盖上述媒体查询。 */
    html.ld-zoom-gear .grid.cols-4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }
    html.ld-zoom-gear .grid.cols-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
    html.ld-zoom-gear .grid.cols-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
    html.ld-zoom-gear .form-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
    /* 智慧管理页 .ai-stage 两栏（历史 7fr / 对话 20fr）
       同样被 @media(max-width:1180) 塌缩为 1fr。
       2026-09-06 用户：对话放最右且最宽；2026-09-21 用户删掉原第2列（待办+记事本）后剩两栏，
       行高 1fr 撑满保证对话卡片填满底部。 */
    html.ld-zoom-gear .ai-stage {
      grid-template-columns: 7fr 20fr;
      grid-template-rows: 1fr;
      overflow-y: visible;
    }
    html.ld-zoom-gear .ai-left-col { max-height: none; }
    html.ld-zoom-gear .ai-center-col { min-height: 0; }
    /* 智慧大屏 .map-stage 两栏（22fr 78fr）/KPI 四列同样恢复设计稿布局 */
    html.ld-zoom-gear .map-stage {
      grid-template-columns: 22fr 78fr;
      grid-template-rows: 1fr;
      padding: 2px 0 0;
      overflow: hidden;
    }
    html.ld-zoom-gear .map-top { flex-direction: row; align-items: center; }
    html.ld-zoom-gear .map-kpi-row {
      grid-template-columns: repeat(4, minmax(108px, 1fr));
      width: auto;
      min-width: min(650px, 58vw);
    }
    html.ld-zoom-gear .map-left {
      grid-template-columns: none;
      grid-template-rows: 1fr 1fr;
    }

    /* 内容页高度由 body 画布的固定 2560×1289 + transform: scale 整体拉伸，
       不再用 100dvh 反推逻辑高（zoom 时代遗留，避免双重缩放） */
    *, *::before, *::after { margin: 0; padding: 0; box-sizing: border-box; }
    html, body {
      margin: 0;
      padding: 0;
    }

    .sidebar {
      height: var(--ld-design-h) !important;
      max-height: var(--ld-design-h) !important;
      min-height: var(--ld-design-h) !important;
      padding: 13px 11px;
      overflow-y: auto;
      overflow-x: hidden;
    }

    .main {
      height: var(--ld-design-h);
      min-height: var(--ld-design-h);
      min-width: 0;
      overflow-y: auto;
      overflow-x: hidden;
      padding: 18px 22px 14px;
      background: var(--bg);
    }

    .content {
      margin-top: 0;
      min-width: 0;
      height: 100%;
    }

    .brand {
      justify-content: center;
      padding: 4px 0 13px;
    }

    .logo {
      width: 42px;
      height: 42px;
      flex-basis: 42px;
      border-radius: 0;
      background: none;
      box-shadow: none;
    }

    .brand-line-main {
      font-size: 16px;
    }

    .brand-line-sub {
      font-size: 11px;
      gap: 6px;
    }

    .nav-title {
      margin: 12px 6px 13px;
    }

    .nav button {
      gap: 11px;
      padding: 8px 9px;
      border-radius: 12px;
      font-size: 17px;
    }

    .nav .icon {
      width: 33px;
      height: 33px;
      border-radius: 9px;
      flex-shrink: 0;
      font-size: 17px;
    }

    .side-card {
      margin-top: 12px;
      padding: 11px;
      border-radius: 16px;
    }

    .side-card p {
      margin: 6px 0 10px;
      line-height: 1.45;
      font-size: 9px;
    }

    .project-stage-list {
      margin: 7px 0 9px;
      gap: 6px;
    }

    .project-stage-list button {
      padding: 4px 3px;
    }

    .sidebar-main {
      padding-bottom: 0;
    }

    .sidebar-spacer {
      min-height: 67px;
      flex: 1 1 auto;
    }

    .sidebar-footer {
      flex: 0 0 auto;
      margin-top: 0;
      margin-bottom: 0;
      padding: 9px;
      gap: 7px;
      position: relative;
      z-index: 2;
      backdrop-filter: blur(12px);
    }

    .sidebar-theme-select {
      height: 26px;
      margin: 4px 0 6px;
    }

    .sidebar-logout-btn {
      height: 27px;
    }

    .card {
      padding-top: 18px;
      padding-bottom: 18px;
    }

    .high-res .logo { width: 56px; height: 56px; flex-basis: 56px; }
    .high-res .sidebar { padding: 18px 14px; }
    .high-res .brand { justify-content: center; padding: 6px 0 18px; }
    .high-res .nav-title { margin: 16px 8px 18px; }
    .high-res .nav button { font-size: 22px; gap: 14px; padding: 9px 12px; }
    .high-res .side-card { margin-top: 16px; padding: 14px; }
    .high-res .sidebar-tool-title { font-size: 14px; }
    .high-res .sidebar-theme-select { font-size: 14px; }
    .high-res .sidebar-tool-text { font-size: 14px; }
    /* ★ 2026-10-14：折叠态标题字号 +3px 的「高倍」档（基准 14px + 3px）——
       特异性需压过 `.high-res .sidebar-tool-title`(0,2,0) 与折叠态默认(0,3,0)。 */
    .high-res .sidebar-footer.collapsed .sidebar-tool-title { font-size: 17px; }


    /* V6 Sidebar Professional Layout */
    /* 高度必须用设计稿高度 var(--ld-design-h)，由 body 画布的 transform: scale 统一拉伸填满视口；
       不能再用 100dvh —— 100dvh 本身已是视口高度，再乘 scale 会二次缩放，
       在视口低于设计稿(1289)时视觉高度 < 视口，导致底部露白 */
    .app {
      min-height: var(--ld-design-h);
      height: var(--ld-design-h);
      overflow: hidden;
    }

    .main {
      height: var(--ld-design-h);
      overflow: auto;
    }

    .sidebar {
      height: var(--ld-design-h);
      min-height: var(--ld-design-h);
      overflow: hidden;
      display: flex;
      flex-direction: column;
      padding: 17px 12px 13px;
    }

    .brand {
      flex: 0 0 auto;
    }

    .sidebar-main {
      flex: 0 1 auto;
      overflow: visible;
      min-height: 0;
      padding-right: 0;
    }

    .sidebar-spacer {
      flex: 1 1 auto;
      min-height: 42px;
    }

    .sidebar-footer {
      flex: 0 0 auto;
      margin-top: 0;
      margin-bottom: 0;
      padding: 11px 26px;
      gap: 8px;
      border-radius: 13px;
      background: color-mix(in srgb, var(--sidebar-card-bg) 88%, var(--bg-deep) 12%);
      border: 1px solid var(--sidebar-border);
      box-shadow: 0 16px 32px rgba(0,0,0,.10), inset 0 1px 0 rgba(255,255,255,.06);
      backdrop-filter: blur(14px);
    }

    .sidebar-tool-title {
      display: flex;
      align-items: center;
      gap: 16px;
      color: var(--sidebar-text);
      font-weight: 900;
      letter-spacing: .04em;
    }

    .sidebar-tool-title::before {
      content: "🔧";
      width: 17px;
      height: 17px;
      border-radius: 6px;
      display: grid;
      place-items: center;
      background: var(--sidebar-icon-bg);
      color: var(--primary);
      box-shadow: 0 8px 18px var(--glow-primary);
    }

    .sidebar-theme-select {
      height: 28px;
      margin: 0;
      width: 100%;
      min-width: 0;
      color: var(--sidebar-text);
      background: color-mix(in srgb, var(--sidebar-card-bg) 70%, var(--bg-deep) 30%);
      border-color: var(--sidebar-border);
      -webkit-text-fill-color: var(--sidebar-text);
    }

    .sidebar-logout-btn {
      height: 30px;
      color: #fff;
      background: linear-gradient(135deg, var(--primary), var(--accent-2));
    }

    .nav button {
      position: relative;
      overflow: hidden;
    }

    .nav button::before {
      content: "";
      position: absolute;
      left: 0;
      top: 50%;
      width: 3px;
      height: 0;
      border-radius: 999px;
      transform: translateY(-50%);
      background: linear-gradient(180deg, var(--primary), var(--accent-2));
      box-shadow: 0 0 14px var(--glow-primary);
      transition: height .18s ease;
    }

    .nav button:hover::before,
    .nav button.active::before {
      height: 24px;
    }

    .nav button:hover,
    .nav button.active {
      background: color-mix(in srgb, var(--sidebar-hover) 72%, transparent);
      color: var(--sidebar-text);
    }

    .app.sidebar-icon .sidebar {
      padding: 17px 9px 13px;
    }

    .app.sidebar-icon .sidebar-spacer {
      min-height: 34px;
    }

    .app.sidebar-icon .sidebar-footer {
      padding: 0;
      background: transparent;
      border: 0;
      box-shadow: none;
      gap: 7px;
      align-items: center;
    }

    .app.sidebar-icon .sidebar-theme-select,
    .app.sidebar-icon .sidebar-logout-btn {
      width: 42px;
      height: 42px;
      border-radius: 12px;
    }

    .app.sidebar-icon .sidebar-theme-select {
      color: transparent;
      -webkit-text-fill-color: transparent;
      font-size: 0;
      padding: 0;
      background: var(--sidebar-icon-bg);
    }

    @media (max-height: 760px) {
      .sidebar {
        padding-top: 11px;
        padding-bottom: 11px;
      }
      .brand {
        padding-bottom: 11px;
      }
      .nav-title {
        margin-top: 7px;
      }
      .nav button {
        padding-top: 7px;
        padding-bottom: 7px;
      }
      .sidebar-spacer {
        min-height: 11px;
      }
      .sidebar-footer {
        padding: 9px;
        gap: 6px;
      }
    }


    /* Footer safety spacer: keep logout button fully visible above viewport edge */
    .sidebar {
      overflow-y: auto;
      padding-bottom: 9px;
    }

    .sidebar-footer {
      padding-bottom: 7px;
    }

    .sidebar-footer-blank {
      height: 23px;
      min-height: 23px;
      pointer-events: none;
    }

    .app.sidebar-icon .sidebar-footer-blank {
      height: 13px;
      min-height: 13px;
    }


    /* Final sidebar height fix: 固定设计稿高度，由 body transform: scale 统一拉伸（原 100dvh 会与缩放二次叠加） */
    .sidebar {
      height: var(--ld-design-h) !important;
      max-height: var(--ld-design-h) !important;
      min-height: var(--ld-design-h) !important;
      box-sizing: border-box !important;
      padding-bottom: 24px !important;
      overflow-y: auto !important;
      overflow-x: hidden !important;
    }

    .sidebar-footer {
      margin-bottom: 0 !important;
      padding-bottom: 11px !important;
    }

    .sidebar-footer-blank {
      display: none !important;
      height: 0 !important;
      min-height: 0 !important;
    }

    /* ========== 管理工作 布局 ========== */
    .pw-layout {
      display: flex;
      flex: 1;
      min-height: 0;
      overflow: hidden;
      position: relative;
      border-radius: 18px;
      border: 1px solid var(--line);
      background: var(--panel);
    }
    /* 管理工作(#projectWorks)去掉底层容器框：.pw-layout 去掉圆角/边框/背景/剪切，
       保留 flex 布局，不影响其他视图。 */
    #projectWorks .pw-layout {
      border: none;
      border-radius: 0;
      background: transparent;
      overflow: visible;
    }
    /* 管理工作：去掉底层云朵动态动画背景（2026-08-30 用户要求） */
    #projectWorks .pw-layout::before,
    #projectWorks .pw-layout::after { display: none; }
    .pw-layout::before {
      content: '';
      position: absolute;
      top: 75px; left: 0; right: 0; bottom: -225px;
      background:
        radial-gradient(ellipse 70% 35% at 25% 35%, var(--bg-spot-b), transparent 78%),
        radial-gradient(ellipse 55% 30% at 42% 28%, var(--bg-spot-a), transparent 76%),
        radial-gradient(ellipse 60% 38% at 58% 32%, var(--bg-spot-b), transparent 78%),
        radial-gradient(ellipse 80% 32% at 78% 38%, var(--bg-spot-a), transparent 78%),
        radial-gradient(ellipse 50% 28% at 35% 50%, var(--bg-spot-b), transparent 74%),
        radial-gradient(ellipse 65% 30% at 65% 55%, var(--bg-spot-a), transparent 76%);
      opacity: .50;
      pointer-events: none;
      z-index: 0;
    }
    .pw-layout::after {
      content: '';
      position: absolute;
      top: 75px; left: 0; right: 0; bottom: -225px;
      background:
        radial-gradient(ellipse 45% 22% at 15% 42%, var(--bg-spot-b), transparent 74%),
        radial-gradient(ellipse 50% 25% at 50% 22%, var(--bg-spot-a), transparent 76%),
        radial-gradient(ellipse 55% 28% at 85% 30%, var(--bg-spot-b), transparent 74%);
      opacity: .30;
      pointer-events: none;
      z-index: 0;
    }
    .pw-main {
      position: relative;
      z-index: 1;
    }


    /* 管理工作 导航标签（水平排列在头部；项目选择器作为内部第一个 flex 项，
       窄屏换行时第 2 行从容器最左边开始，不再被项目名称挤占 2026-08-31）
       不加 overflow-x：flex-wrap 负责换行，overflow 会把 overflow-y 强判为 auto 裁剪换行行 */
    .pw-nav {
      display: flex;
      flex-direction: row;
      flex-wrap: wrap;
      gap: 8px;
      padding: 0 0 4px; /* 2026-09-02 去顶部4px，按钮距顶对齐18px */
      /* 接管整行宽度并允许收缩换行 */
      flex: 1 1 auto;
      min-width: 0;
    }
    /* 二级导航（管理工作顶部标签按钮，标准同项目工程 .project-group-tab；去抖动：active 不缩边框） */
    .pw-nav-item {
      display: inline-flex;
      align-items: center;
      gap: 6px;
      padding: 8px 16px;
      border-radius: 12px;
      border: 1px solid var(--line);
      background: var(--panel);
      color: var(--text);
      font-size: 19px;
      font-weight: 600;
      height: 41px;          /* 固定高度：基础态/选中态一致(41px)，杜绝切换重排抖动；与旧基础态41px保持一致 */
      line-height: 1;        /* 行高=字号，配合 align-items:center 精确垂直居中，文字不再偏下 */
      cursor: pointer;
      /* 只过渡颜色/阴影，不去动画字号与padding，避免放大时文字抖动/重排 */
      transition: background .2s, color .2s, border-color .2s, box-shadow .2s;
      user-select: none;
    }
    .pw-nav-item:hover {
      background: var(--primary-soft);
      border-color: var(--primary);
    }
    .pw-nav-item.active {
      background: color-mix(in srgb, var(--primary) 18%, transparent);
      color: var(--primary);
      border-color: var(--primary);
      box-shadow: 0 4px 12px color-mix(in srgb, var(--primary) 30%, transparent);
      /* 选中态文字加大2px(19→21)且按钮框不撑宽：左右padding由JS按中文数补偿(--tabpad)，
         高度锁定41px不变；上下padding由8px→6px为加大的文字腾出空间 */
      font-size: 21px;
      padding: 6px var(--tabpad, 8px);
    }


    .pw-nav-label {
      /* 2026-09-02 去掉 overflow:hidden：flex 子项 blockify 后 overflow 生效，
         把中文字形顶部约1px裁掉（管理工作非选中态文字顶被切）。预算 .mat-tab 无此包裹层不受影响。 */
      text-overflow: ellipsis;
    }
    .pw-nav-divider {
      width: 1px;
      height: auto;
      align-self: stretch;
      background: var(--sidebar-border);
      margin: 2px 4px;
      opacity: .4;
    }

    /* 右侧主区�?*/
    .pw-main {
      flex: 1;
      min-width: 0;
      display: flex;
      flex-direction: column;
      overflow: hidden;
    }
    .pw-main-header {
      display: flex;
      align-items: center;
      gap: clamp(8px, 0.47vw, 12px);
      padding: 18px clamp(16px, 0.94vw, 24px); /* 2026-09-02 管理工作二级导航距顶对齐18px */
      border-bottom: 1px solid var(--border);
      /* 标签换行成多行时 header 自由增高，不被 .pw-main 压缩导致下方内容遮挡（2026-08-31） */
      flex-shrink: 0;
    }
    /* 项目选择器（现为 .pw-nav 内第一个 flex 项）：只占其内容宽度，可收缩但上限 34%。
       select 的 width:auto 是由最长 option 文本（如"— 请选择项目 —"）决定的，
       即使当前选中的项目名很短也会撑很宽；不加收敛会挤压右侧标签的换行空间 */
    .pw-project-selector {
      flex: 0 0 auto;
      min-width: 0;
      max-width: 34%;
      align-self: center;
    }
    .pw-project-selector select {
      padding: clamp(5px, 0.31vw, 8px) clamp(9px, 0.55vw, 14px);
      border-radius: clamp(7px, 0.39vw, 10px);
      border: 1px solid var(--border);
      background: transparent;
      color: var(--text);
      font-size: clamp(16px, 0.86vw, 22px);
      font-weight: 600;
      cursor: pointer;
      outline: none;
      text-align: left;
      -webkit-appearance: none;
      appearance: none;
      min-width: 0;
      max-width: 100%;
      width: auto;
      white-space: nowrap;
      overflow: hidden;
      text-overflow: ellipsis;
    }
    .pw-project-selector select:hover {
      border-color: var(--primary);
    }
    .pw-project-selector select:focus {
      border-color: var(--primary);
      box-shadow: 0 0 0 3px rgba(59,130,246,.14);
    }
    .pw-project-selector select option {
      background: var(--bg);
      color: var(--text);
    }

    /* ── 项目选择浮层（2026-09-08：管理工作/弹窗原生 select → 自定义触发器+搜索浮层，参照钢筋采购列头浮层）──
       2026-09-17：项目选择窗体拆成 4 个独立窗体后，四个窗体的"项目行"统一挂 `.ldp-proj-row`，
       于是这一套样式对四个窗体同时生效（原来只认 #photoProjectSelectRow 这一个 id）。 */
    .pw-project-selector .ld-ppick,
    #photoProjectSelectRow .ld-ppick,
    .ldp-proj-row .ld-ppick,
    /* 2026-09-19：预算翻样「量差&对比」顶部 5 个筛选下拉 —— 与"管理工作·选择项目"同源同款 */
    .cbd-cmp-fltwrap .ld-ppick {
      position: relative;
      display: inline-flex;
      align-items: center;
      min-width: 0;
      max-width: 100%;
    }
    #photoProjectSelectRow .ld-ppick,
    .ldp-proj-row .ld-ppick { display: flex; width: 100%; }
    /* 2026-09-19：预算翻样「量差&对比」筛选下拉也套这一套（与"管理工作·选择项目"触发器一模一样） */
    .pw-project-selector .ld-ppick-trg,
    .cbd-cmp-fltwrap .ld-ppick-trg {
      -webkit-appearance: none;
      appearance: none;
      height: 41px;            /* 标准二级导航按钮高（见 Bug 记录，2026-09-08） */
      border: 1px solid var(--line);
      background: var(--panel);   /* 触发器外框常显（2026-09-08 用户要求：平时就要看得出是下拉控件，不靠点击/悬停） */
      color: var(--text);
      font-weight: 600;
      font-family: inherit;
      cursor: pointer;
      outline: none;
      display: inline-flex;
      align-items: center;
      gap: 7px;
      min-width: 0;
      max-width: 100%;
      box-sizing: border-box;
      padding: 0 clamp(9px, 0.55vw, 14px);
      border-radius: 12px;
      font-size: 17px;         /* 标准二级导航按钮字号（见 Bug 记录，2026-09-08） */
      line-height: 1;
      box-shadow: 0 1px 2px rgba(0,0,0,.05);
    }
    .pw-project-selector .ld-ppick-trg:hover,
    .cbd-cmp-fltwrap .ld-ppick-trg:hover { border-color: var(--primary); }
    .pw-project-selector .ld-ppick-trg:focus,
    .cbd-cmp-fltwrap .ld-ppick-trg:focus { border-color: var(--primary); box-shadow: 0 0 0 3px rgba(59,130,246,.14); }
    .ldp-proj-row .ld-ppick-trg,
    #photoProjectSelectRow .ld-ppick-trg {
      -webkit-appearance: none;
      appearance: none;
      width: 100%;
      height: 41px;            /* 标准二级导航按钮高（见 Bug 记录，2026-09-08） */
      box-sizing: border-box;
      border: 1px solid var(--line);
      /* 2026-09-17 用户："弹窗中的输入框选择框 颜色也去掉" → 触发器也照"一体背景 + 自身外框线"，
         底色清空（原来填 var(--panel)，套在半透明窗体上会叠深）。 */
      background: transparent;
      color: var(--text);
      font-family: inherit;
      font-size: 17px;         /* 标准二级导航按钮字号（见 Bug 记录，2026-09-08） */
      font-weight: 600;
      cursor: pointer;
      outline: none;
      border-radius: 12px;
      padding: 0 12px;
      display: flex;
      align-items: center;
      justify-content: space-between;
      gap: 10px;
      line-height: 1;
    }
    .ldp-proj-row .ld-ppick-trg:focus,
    #photoProjectSelectRow .ld-ppick-trg:focus { border-color: var(--primary); }
    .ld-ppick-txt {
      overflow: hidden;
      text-overflow: ellipsis;
      white-space: nowrap;
      min-width: 0;
      flex: 1 1 auto;
    }
    /* 浮层面板：样式与钢筋采购表头列选项浮层一致（面板底不透明 + 顶部搜索 + 选项列表） */
    .ld-ppick-panel {
      position: fixed;
      z-index: 30000;
      display: none;
      flex-direction: column;
      min-width: 240px;
      max-width: 360px;
      height: 300px;              /* 下拉固定高 300px，超出内部滚动（2026-09-08 用户：默认300，取消 600 上限） */
      background: var(--bg);
      border: 1px solid var(--line);
      border-radius: 10px;
      box-shadow: 0 8px 28px rgba(0, 0, 0, .16);
      overflow: hidden;
      font-size: 16px;   /* 下拉面板文字（2026-09-08 用户：16px） */
      color: var(--text);
    }
    .ld-ppick-panel .ld-ppick-search {
      flex-shrink: 0;
      border: none;
      border-bottom: 1px solid var(--line);
      outline: none;
      background: var(--input-bg, var(--panel));
      color: var(--text);
      font-size: 16px;
      font-family: inherit;
      padding: 8px 10px;
      margin: 0;
      box-sizing: border-box;
    }
    .ld-ppick-panel .ld-ppick-search::placeholder { color: var(--muted); }
    .ld-ppick-panel .ld-ppick-list {
      flex: 1;
      min-height: 0;
      overflow-y: auto;
      padding: 4px 0;
      user-select: none;
      -webkit-user-select: none;
      /* 滚动但隐藏滚动条（2026-09-08 用户：不显示滚动条） */
      scrollbar-width: none;
      -ms-overflow-style: none;
    }
    .ld-ppick-panel .ld-ppick-list::-webkit-scrollbar { display: none; width: 0; height: 0; }
    .ld-ppick-opt {
      display: block;
      padding: 7px 12px;
      cursor: pointer;
      color: var(--text);
      white-space: nowrap;
      overflow: hidden;
      text-overflow: ellipsis;
      /* ★★ 2026-09-26 修「下拉标签行被挤压得很细 / 行高不对」（料单审核的「请选择单体」浮层暴露）：
         列表 `.ld-ppick-panel .ld-ppick-list` 是 **flex 竖列**（见下面 9311 那条 `display:flex;
         flex-direction:column`），面板又是**固定高 300px** ⇒ 行是 flex 子项。
         ⚠ 而本行自己有 `overflow: hidden` ⇒ 按规范，它的**自动最小尺寸退化为 0**（`min-height:auto`
         那条保护失效）⇒ 选项一多（≥ 面板高度装得下的行数），flex 就把**每一行按比例压扁**，
         而不是让列表滚动 —— 用户看到的就是"**标签行被挤压得很细、标签的高度也不对**"。
         （"选择项目"那枚只有三四个项目 ⇒ 从不触发；开始菜单那套 `.ld-sm-pick` 的行另有
          `min-height: 32px` 兜着 ⇒ 也从不触发。只有"行多 + 基础样式"这一种组合会暴露。）
         ⇒ 行一律**不许被压缩**（`flex: 0 0 auto`），超出高度交给列表自己的 `overflow-y: auto` 滚动
           （面板注释里写的"下拉固定高 300px，超出内部滚动"本来就是设计意图）。 */
      flex: 0 0 auto;
    }
    .ld-ppick-opt:hover { background: var(--primary-soft); }
    .ld-ppick-opt.sel { color: var(--primary); font-weight: 600; }
    .ld-ppick-empty { padding: 12px 10px; color: var(--muted); text-align: center; }
    /* 候选为空时的「去建立…」按钮条（2026-10-09，见 lingdu-files.js 的 data-ppick-empty-btn）：
       一条可点的标签条 —— 只留自身边框（不叠底色），悬停才用主题色填 */
    .ld-ppick-panel .ld-ppick-empty-btn {
      display: block;
      width: calc(100% - 20px);
      margin: 2px auto 6px;
      padding: 9px 10px;
      border: 1px solid var(--line);
      border-radius: 8px;
      background: transparent;
      color: var(--primary);
      font-family: inherit;
      font-size: 16px;
      cursor: pointer;
      text-align: center;
    }
    .ld-ppick-panel .ld-ppick-empty-btn:hover {
      border-color: var(--primary);
      background: var(--primary-soft);
    }
    .pw-main-header h3 {
      font-size: clamp(14px, 0.7vw, 18px);
      font-weight: 700;
    }
    .pw-main-sub {
      font-size: clamp(10px, 0.47vw, 12px);
      color: var(--muted);
    }
    .pw-cards-grid {
      flex: 1;
      overflow-y: auto;
      padding: 0 clamp(16px, 0.94vw, 24px);
      display: grid;
      grid-template-columns: repeat(auto-fill, minmax(110px, 1fr));
      gap: clamp(5px, 0.31vw, 8px);
      align-content: start;
    }
    .pw-card {
      background: transparent;
      border: none;
      border-radius: clamp(10px, 0.55vw, 14px);
      padding: clamp(7px, 0.39vw, 10px) clamp(8px, 0.47vw, 12px) clamp(5px, 0.31vw, 8px);
      text-align: center;
      cursor: pointer;
      transition: transform .12s;
      display: flex;
      flex-direction: column;
      align-items: center;
      gap: clamp(5px, 0.31vw, 8px);
    }
    .pw-card:hover {
      transform: translateY(-3px);
    }
    .pw-card-icon {
      line-height: 1;
    }
    .pw-card-icon-bg {
      display: inline-flex;
      align-items: center;
      justify-content: center;
      width: clamp(48px, 2.85vw, 73px);
      height: clamp(48px, 2.85vw, 73px);
      font-size: clamp(22px, 1.33vw, 34px);
      transition: transform .12s;
    }
    .pw-card:hover .pw-card-icon-bg {
      transform: scale(1.5);
    }
    .pw-card-name {
      font-size: clamp(11px, 0.59vw, 15px);
      font-weight: 700;
      color: var(--text);
      white-space: nowrap;
      width: 100%;
    }
    .pw-card-desc {
      display: none;
    }
    .pw-empty {
      grid-column: 1 / -1;
      text-align: center;
      padding: clamp(40px, 2.34vw, 60px) clamp(13px, 0.78vw, 20px);
      color: var(--muted);
      font-size: clamp(11px, 0.55vw, 14px);
    }
    .pw-cat-content {
      flex: 1;
      overflow: hidden;
      padding: 0 15px;
      display: none;
    }
    .pw-cat-content.active {
      display: flex !important;
      flex-direction: column;
    }

    /* ── 内联文件浏览器（嵌入右侧面板�?── */
    .pw-inline-fb {
      display: flex; flex-direction: column; height: 100%;
      overflow: hidden;
      /* 项目资料页左右贴边：抵消 .pw-cat-content 的 0 15px 内边距（2026-09-02） */
      margin: 0 -15px;
    }
    .pw-inline-fb .pw-fb-header {
      /* 2026-09-02 统一内联浏览器头部控件高度：搜索框与右侧按钮同高 */
      --ifb-ctl-h: clamp(28px, 1.6vw, 34px);
      cursor: default; flex-shrink: 0; margin-top: -10px;
    }
    .pw-inline-fb .pw-fb-header:active { cursor: default; }
    /* 项目资料页路径文字（2026-08-31 用户要求 +2px：15→17） */
    .pw-inline-fb .pw-fb-header .fb-title { font-size: 17px; }
    /* ★ 2026-10-14 Edge 标签模式"左留白 / 右裁 1px"根因修复（实机像素取证）：
       `.pw-fb-body` 是 `overflow-y:auto` 滚动容器，其溢出裁切边界 = padding box。而它的水平
       padding 为 0，行的 padding box 宽（实测 ow=2080）恰好等于它的 clientWidth（2080）⇒ 行右侧
       1px 边框盒**精准压在裁切边界上**，被浏览器按物理像素取整裁掉；左侧因是裁切起点、行左缘未贴边
       （列表行间 gap / 半像素相位）留有可见留白，于是呈现「左有留白、右被裁 1px」。
       按《Bug记录》第 15840-15876「容器宽 vs 表实际渲染宽 → 留 1px 边线余量」（同类：`.cbd-pane .cf-freeze-area` 551→552px）
       给滚区水平各留 1px ⇒ 行两侧边框都移出裁切边界，左右对称。
       注：上一版注释所说"will-change / translateZ 合成层取整"已被用户实机证伪（强刷后仍无效），
       上面的裁切边界才是真实根因。Chrome 视口比 Edge 宽 8px、小数缩放相位不同，故 Chrome 不触发。 */
    .pw-inline-fb .pw-fb-body { flex: 1; overflow-y: auto; contain: layout; padding: 1px 1px; }
    .pw-inline-fb .pw-fb-body.view-switching {
      opacity: 0;
      transition: opacity .15s;
    }
    .pw-inline-fb .pw-fb-footer {
      display: flex; align-items: center; justify-content: space-between;
      padding: 0 clamp(12px, 0.7vw, 18px);
      font-size: clamp(10px, 0.51vw, 13px); color: var(--muted); flex-shrink: 0;
      line-height: 1;
    }
    #ifbStatusInfo, #fbStatusInfo { margin-top: -3px; display: none; }
    .ifb-view-toggle, .ifb-explorer-btn, .ifb-upload-btn {
      width: clamp(20px, 1.1vw, 28px); height: var(--ifb-ctl-h, clamp(20px, 1.1vw, 28px)); border-radius: clamp(5px, 0.31vw, 8px); border: none;
      background: transparent; color: var(--muted); font-size: clamp(11px, 0.55vw, 14px); cursor: pointer;
      display: flex; align-items: center; justify-content: center; flex-shrink: 0;
    }
    .ifb-view-toggle:hover, .ifb-explorer-btn:hover, .ifb-upload-btn:hover { background: var(--sidebar-hover); color: var(--text); }
    /* 管理工作左上角文件夹图标加大 35%（仅文件夹按钮，不影响视图/上传按钮） */
    .ifb-explorer-btn {
      width: clamp(27px, 1.49vw, 38px); height: clamp(27px, 1.49vw, 38px);
      font-size: clamp(15px, 0.85vw, 22px);
    }
    /* 上传按钮 ＋ 放大 50% 并加粗（2026-09-02；基准 clamp(11px,0.55vw,14px) ×1.5） */
    .ifb-upload-btn {
      font-size: clamp(16.5px, 0.825vw, 21px);
      font-weight: 700;
      padding: 0; /* 2026-09-02 ＋ 上下左右内边距为0 */
    }
    .ifb-view-toggle.active { background: color-mix(in srgb, var(--primary) 18%, transparent); color: var(--primary); }
    #ifbViewToggleBtn {
      width: var(--ifb-ctl-h, 26px);
      height: var(--ifb-ctl-h, 26px);
    }

    /* 内联文件浏览器搜索框 */
    .ifb-search-box {
      position: relative;
      flex: 1; min-width: 0; max-width: clamp(240px, calc(11vw + 60px), 340px);
      margin-left: clamp(5px, 0.31vw, 8px);
      height: var(--ifb-ctl-h, auto);
    }
    .ifb-inline-switch {
      flex-shrink: 0;
      font-size: clamp(11px, 0.55vw, 14px) !important;
      padding: 1px 10px;
      height: var(--ifb-ctl-h, 24px);
      border-radius: clamp(8px, 0.47vw, 12px);
      border: 1px solid var(--primary);
      background: var(--primary-soft);
      color: var(--primary);
      cursor: pointer;
      transition: all .2s;
      line-height: 1;
    }
    .ifb-inline-switch:hover {
      border-color: var(--primary);
      background: var(--primary-soft);
      color: var(--primary);
    }
    .ifb-inline-switch.disabled {
      opacity: 0.35;
      cursor: default;
      pointer-events: none;
      border-color: var(--muted);
    }
    .ifb-timeline-btn {
      flex-shrink: 0;
      font-size: clamp(11px, 0.55vw, 14px) !important;
      padding: 1px 10px;
      height: var(--ifb-ctl-h, 24px);
      border-radius: clamp(8px, 0.47vw, 12px);
      border: 1px solid var(--primary);
      background: var(--primary-soft);
      color: var(--primary);
      cursor: pointer;
      display: flex;
      align-items: center;
      gap: 3px;
      white-space: nowrap;
      transition: background .15s;
    }
    .ifb-timeline-btn:hover {
      background: var(--primary);
      color: #fff;
    }
    .ifb-search-input {
      width: 100%;
      height: 100%;
      padding: 0 clamp(18px, 1.1vw, 28px) 0 clamp(9px, 0.55vw, 14px);
      border: 1px solid var(--line);
      border-radius: clamp(7px, 0.39vw, 10px);
      background: var(--panel);
      color: var(--text);
      font-size: clamp(11px, 0.55vw, 14px);
      outline: none;
      transition: border-color .2s, box-shadow .2s;
      box-sizing: border-box;
    }
    .ifb-search-input:focus {
      border-color: var(--primary);
      box-shadow: 0 0 0 3px var(--primary-soft);
    }
    .ifb-search-input::placeholder { color: var(--muted); }
    .ifb-search-icon {
      position: absolute; right: clamp(4px, 0.27vw, 7px); top: 50%; transform: translateY(-50%);
      width: clamp(10px, 0.55vw, 14px); height: clamp(10px, 0.55vw, 14px);
      color: var(--muted);
      pointer-events: none;
    }

    /* 卡片视图（固定尺寸：卡片 260×180，内部用固定值） */
    .ifb-card-grid {
      /* 2026-09-02 改 flex 换行 + space-evenly：一行放满 N 个卡片后，若左右留白
         不够放下下一个，卡片间距按该行等分（不再写死 gap）；行满无剩余时回落 gap 15px。
         卡片宽度由 .ifb-card-item 固定，flex 中保持 322.4px 不拉伸。 */
      display: flex;
      flex-wrap: wrap;
      justify-content: space-evenly;
      gap: 15px;
      padding: 13px 5px 16px;
    }
    .ifb-card-item {
      position: relative;
      display: flex; flex-direction: column; align-items: center; justify-content: center;
      gap: 6px;
      width: 322.4px; height: 257.92px; overflow: hidden;
      padding: 8px 10px 6px;
      background: transparent;
      border: 1px solid transparent;
      border-radius: 14px;
      cursor: grab;
      transition: transform .2s, outline-color .2s, border-color .2s;
      user-select: none;
      box-sizing: border-box;
      text-align: center;
    }
    .ifb-card-item:active { cursor: grabbing; }
    .ifb-card-item:hover { transform: translateY(-3px) scale(1.1); } /* 2026-09-02 整卡(图标+文字+间距)同步放大；2026-09-02 悬停放大 1.35→1.2→1.1 */
    .ifb-card-item.ifb-thumb-card:hover { transform: scale(1.03); } /* 2026-09-02 缩略图卡片悬停轻微放大 1.03 */
    body:has(.fb-selection-box) .ifb-card-item:hover { transform: none !important; } /* 2026-09-02 框选期间禁止卡片悬停放大 */
    body:has(.fb-selection-box) .ifb-card-item.ifb-thumb-card:hover { transform: none !important; }
    /* ── 远程演示：接收端的"模拟悬停"（2026-09-13 用户实测）──
       演示端鼠标悬停在文件/图片卡片上会轻微放大，但 `:hover` 是按**本机指针位置**算的，
       接收端的指针不在那张卡片上 → 完全没反应。演示端把"悬停在哪一项"（data-fb-name）发过来，
       接收端给同一项挂 `ldp-hover`；这里让 `.ldp-hover` 与上面那些 `:hover` 规则**一一等效**。
       新增任何卡片悬停样式时，记得在这里补一条对应规则。 */
    .ifb-card-item.ldp-hover { transform: translateY(-3px) scale(1.1); }
    .ifb-card-item.ifb-thumb-card.ldp-hover { transform: scale(1.03); }
    .ifb-card-item.selected.ldp-hover { transform: none; }
    /* 通用语义悬停（2026-09-13）：远程演示时接收端用 `.ldp-hover` 复刻演示端**当前悬停在哪个控件**上
       —— 与各控件自己的 `:hover` 规则一一等效（浏览器按本机指针算的 :hover 无法镜像，只能这样复刻）。
       用**属性选择器**一次覆盖全部表格（cb- / meb- / mib- / mex- / mss- 前缀），
       以后新增表格/控件不必再逐条补规则。
       ⚠ 新增某控件的悬停样式时，记得在下面补一条对应的 `.ldp-hover` 规则。 */
    .cb-filter-cell.ldp-hover, [class*="-filter-cell"].ldp-hover { background: var(--primary-soft); }
    .cb-filter-opt.ldp-hover,  [class*="-filter-opt"].ldp-hover  { background: var(--primary-soft); }
    /* 2026-09-14 右键菜单改真身：菜单项的**悬停高亮**也必须能跟随。
       原来是 CSS `:hover`（`--sidebar-hover`）—— 接收端鼠标并不在菜单上，`:hover` 永远不成立，
       所以必须让 `.ldp-hover` 与 `:hover` 等效，否则就会出现"菜单弹出来了、但鼠标上下移动高亮条不走"。 */
    .fb-context-menu .fb-ctx-item.ldp-hover { background: var(--sidebar-hover); }
    .fp-ctx-item.ldp-hover { background: var(--sidebar-hover); }
    /* 2026-09-14 桌面右键菜单改真身：桌面菜单项（`.smbg-item`）的 `:hover` 是
       `--primary-soft` + `--primary` 文字色（见 .smbg-item:hover）—— 同样必须让 `.ldp-hover` 等效。 */
    .smbg-menu .smbg-item.ldp-hover { background: var(--primary-soft); color: var(--primary); }
    .ifb-card-item.dragging {
      transform: scale(.95);
      border-color: var(--primary);
    }
    .ifb-card-item.ifb-drop-target {
      outline: 3px solid var(--primary, #36f);
      outline-offset: -2px;
      background: color-mix(in srgb, var(--primary, #36f) 12%, transparent);
    }
    .ifb-card-item.selected {
      outline: 2px solid var(--primary);
      outline-offset: -1px;
      box-shadow: 0 0 10px var(--primary);
    }
    .ifb-card-item.selected:hover { transform: none; }
    .ifb-card-item.ifb-box-hl {
      outline: 2px solid var(--primary, #36f);
      outline-offset: -1px;
    }
    .ifb-card-item .ifb-card-icon {
      line-height: 1;
      transition: transform .12s;
    }
    .ifb-card-item .ifb-card-icon-bg {
      display: inline-flex !important;
      align-items: center !important;
      justify-content: center !important;
      width: 39% !important;
      aspect-ratio: 5 / 4;
      font-size: 72.8px !important; /* 2026-09-02 内部文件夹/文件图标加大40%（52×1.4），选中态/未选中态统一 */
      transition: transform .12s;
    }
    .ifb-card-item .ifb-card-icon-bg svg.ifb-ficon { width: 100%; height: 100%; display: block; }
    .ifb-card-item .ifb-card-icon-bg img.ifb-thumb { width: 58%; height: 58%; object-fit: cover; border-radius: 6px; display: block; transition: opacity .15s ease; }
    /* 重命名中：图标缩小 30%（0.7）且禁止悬停放大，避免遮挡重命名输入框 */
    .ifb-card-item.ifb-renaming .ifb-card-icon { transform: scale(0.7) !important; }
    /* 后缀名显示开关（右键菜单"显示后缀名"）：关闭时隐藏卡片/列表中的扩展名 */
    .ifb-hide-ext .ifb-card-ext,
    .ifb-hide-ext .fb-name-ext { display: none !important; }
    /* 文件大小显示开关（右键菜单"显/隐文件大小"）：关闭时隐藏卡片/列表/表头的文件大小 */
    .ifb-hide-size .ifb-card-size,
    .ifb-hide-size .fb-size,
    .ifb-hide-size .fb-h-size { display: none !important; }
    /* ★★ 2026-10-11（用户）："（项目资料 / 料单审核等）所有能显示网格卡片的地方，**文件名到中间那个
       图标的距离**统一改为 **15px**"。⚠ 本卡片容器 `gap: 6px` 是"图标↔名字↔大小"**共用**的 ⇒ 不能直接
       把它改成 15（那会把"名字↔大小"也一起拉开）⇒ 用名字的 `margin-top` **补差值 9px**：
       图标↔名字 = 6 + 9 = **15px**，名字↔大小 仍是 6px 不动。 */
    .ifb-card-item .ifb-card-name {
      margin-top: 9px;   /* 图标↔名字 = 6(gap) + 9 = 15px；见上 */
      font-size: 16.8px; font-weight: 700; color: var(--text); /* 2026-09-02 内部字加大20%（14×1.2） */
      text-align: center; word-break: break-all; line-height: 1.3;
      width: 100%; overflow: hidden;
    }
    .ifb-card-item .ifb-card-name-thumb {
      font-size: 16.8px; font-weight: 700; color: var(--muted); /* 2026-09-02 内部字加大20%（14×1.2） */
    }
    .ifb-thumb-card {
      padding: 0 !important;
      border-radius: 14px;
      overflow: hidden;
    }
    .ifb-thumb-card .ifb-card-icon {
      width: 100% !important; height: 100% !important; flex: 1;
      display: flex; align-items: center; justify-content: center;
      transform: none !important;
    }
    .ifb-thumb-card .ifb-card-icon:hover { transform: none !important; }
    .ifb-thumb-card .ifb-card-icon-bg {
      width: 100% !important; height: 100% !important; font-size: 0 !important;
    }
    .ifb-thumb-card .ifb-thumb {
      width: 100% !important; height: 100% !important; object-fit: cover;
      transition: opacity .15s ease;
      image-rendering: -webkit-optimize-contrast;
    }
    .ifb-thumb-number {
      position: absolute; bottom: 4px; right: 6px;
      font-size: 12px; font-weight: 700;
      color: #fff; background: rgba(0,0,0,0.55);
      min-width: 20px; height: 20px;
      display: flex; align-items: center; justify-content: center;
      border-radius: 50%; line-height: 1;
      pointer-events: none;
    }
    /* 已缓存（打开秒开）：图片右下角序号文字 → 亮绿字；文件名整体变绿（含后缀）
       ⚠ 2026-09-28：**列表模式**（`.fb-item`）那几条三态规则**已移到下面 `.pw-fb-body .fb-item` 那段**
         —— 它们原来在这里是 3 个 class，会被下面的 `.pw-fb-body .fb-item.fb-file .fb-name`（4 个 class）
         压住、从来没生效过（class 白挂）。卡片模式那几条本来就生效，留在这里不动。 */
    .ifb-card-item.ifb-cached .ifb-thumb-number { color: #4ade80; }
    .ifb-card-item.ifb-cached .ifb-card-name { color: #16a34a; }
    /* 仅缩略图缓存（未秒开）：图片右下角序号文字 → 黄字；文件名变黄（2026-08-31 三态角标） */
    .ifb-card-item.ifb-thumb-only .ifb-thumb-number { color: #eab308; }
    .ifb-card-item.ifb-thumb-only .ifb-card-name { color: #ca8a04; }
    /* ★ 2026-09-28：PDF「只有字节、位图还没齐」= 不能秒开 ⇒ 与"仅缩略图"同色（黄）。
       语义与料单审核那边的 `.fl-leaf-card.ifb-bytes-only` 对齐（同一类名、同一色值 #ca8a04），
       来源见 lingdu-review.css 里那两条的注释。 */
    .ifb-card-item.ifb-bytes-only .ifb-thumb-number { color: #eab308; }
    .ifb-card-item.ifb-bytes-only .ifb-card-name { color: #ca8a04; }
    /* 文件夹缓存状态：全部文件已缓存=绿、部分=黄、无=不变色 */
    .ifb-card-item.ifb-dir-cached .ifb-card-name { color: #16a34a; }
    .ifb-card-item.ifb-dir-partial .ifb-card-name { color: #eab308; }
    /* 缩略图渐进式加载占位符：完全消除任何可见痕迹 */
    img.lazy-thumb {
      opacity: 0 !important;
      background: transparent !important;
      border: none !important;
      outline: none !important;
      box-shadow: none !important;
      border-radius: 0 !important;
      min-width: 1px !important; min-height: 1px !important;
    }
    /* 父卡片有占位符时去掉边框，避免抗锯齿产生的玻璃框 */
    .ifb-card-item:has(img.lazy-thumb),
    .ifb-card-placeholder:has(img.lazy-thumb) {
      border-color: transparent !important;
      border-width: 0 !important;
      outline: none !important;
    }
    img.lazy-thumb[src] {
      opacity: 1 !important;
      transition: opacity .15s ease;
    }
    .ifb-card-rename-input {
      width: 100%; font-size: 16.8px; /* 2026-09-02 重命名文字+20% */; font-weight: 700; color: var(--text);
      text-align: center; word-break: break-all; line-height: 1.3;
      border: 2px solid var(--primary, #36f); border-radius: 5px;
      padding: 1px 3px; background: transparent; outline: none;
      box-sizing: border-box;
    }
    .ifb-card-item .ifb-card-size {
      font-size: 12px; color: var(--muted); line-height: 1; /* 2026-09-02 内部字加大20%（10×1.2） */
    }
    .ifb-card-placeholder {
      width: 322.4px;
      flex: 0 0 322.4px;
      height: 257.92px;
      border-radius: 12px;
      border: 2px dashed transparent;
      transition: border-color .2s, background .2s;
    }
    .ifb-card-placeholder.drag-over {
      border-color: var(--primary, #36f);
      background: color-mix(in srgb, var(--primary, #36f) 8%, transparent);
    }
    .pw-fb-body .fb-item.drag-over {
      background: var(--primary-soft);
      border-color: var(--primary);
    }
    .ifb-list-placeholder {
      min-height: 42px; height: 42px; width: 100%;
      border-radius: 6px;
      border: 2px dashed transparent;
      transition: border-color .2s, background .2s;
    }
    .ifb-list-placeholder.drag-over {
      border-color: var(--primary, #36f);
      background: color-mix(in srgb, var(--primary, #36f) 8%, transparent);
    }
    /* 内容/列表模式下选中样式（同项目工程 .content-mode .project-overview-card.selected�?*/
    .pw-fb-body .fb-item.selected {
      background: color-mix(in srgb, var(--primary) 8%, transparent);
      border-color: var(--primary);
      box-shadow: none;
    }
    .pw-fb-body .fb-item.selected:hover {
      background: color-mix(in srgb, var(--primary) 12%, transparent);
    }
    /* 远程演示：列表模式下"接收端的模拟悬停"（同 .ifb-card-item 那组，2026-09-13） */
    .pw-fb-body .fb-item.ldp-hover {
      background: var(--primary-soft);
      border-color: var(--primary);
    }
    .pw-fb-body .fb-item.selected.ldp-hover {
      background: color-mix(in srgb, var(--primary) 12%, transparent);
    }
    .pw-fb-body .fb-item.ifb-box-hl {
      background: var(--bg-spot-b, #e8f0fe);
    }

    /* ── 文件浏览器弹窗（方案A�?── */
    .pw-filebrowser-overlay {
      position: fixed; inset: 0; z-index: 9999;
      pointer-events: none;
    }
    .pw-filebrowser-dialog {
      position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%);
      width: clamp(600px, 39vw, 1000px); min-width: clamp(240px, 14vw, 360px);
      height: clamp(420px, 27.3vw, 700px); min-height: clamp(200px, 11.7vw, 300px);
      background: var(--panel); border: 1px solid var(--sidebar-border);
      border-radius: 13px; display: flex; flex-direction: column;
      pointer-events: auto;
      overflow: hidden;
    }
    .pw-fb-header {
      display: flex; align-items: center; gap: 8px;
      padding: 14px 14px 8px; border-bottom: 1px solid var(--sidebar-border);
      flex-shrink: 0; cursor: move; user-select: none; touch-action: none; /* 窗体标题：十字箭头（虚拟鼠标只认 move） */
    }
    .pw-fb-header:active { cursor: move; }
    .pw-fb-header .fb-title {
      flex: 1; font-size: 15px; font-weight: 700; color: var(--text);
      white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
      pointer-events: auto; cursor: move; min-width: 0; /* 标题文字也属可拖动区：保持十字，不覆盖 header 的 move */
    }
    /* 地址路径面包屑：点击任意一级直接跳转到该目录 */
    .pw-fb-header .fb-title.ifb-crumb { cursor: default; overflow-x: auto; scrollbar-width: none; text-overflow: clip; }
    .pw-fb-header .fb-title.ifb-crumb::-webkit-scrollbar { display: none; }
    .pw-fb-header .ifb-crumb-seg { cursor: pointer; color: var(--text); padding: 0 2px; border-radius: 4px; user-select: none; }
    .pw-fb-header .ifb-crumb-seg:hover { background: var(--sidebar-hover); color: #2563eb; text-decoration: underline; }
    .pw-fb-header .ifb-crumb-seg.root { color: var(--muted); }
    .pw-fb-header .ifb-crumb-sep { color: var(--muted); }
    .pw-fb-header .fb-back {
      width: 36px; height: 36px; border-radius: 9px; border: none;
      background: transparent; color: var(--muted); font-size: 20px; cursor: pointer;
      display: flex; align-items: center; justify-content: center; flex-shrink: 0;
    }
    .pw-fb-header .fb-back:hover { background: var(--sidebar-hover); color: var(--text); }
    .pw-fb-header .fb-close {
      width: 24px; height: 24px; border-radius: 6px; border: none;
      background: transparent; color: var(--muted); font-size: 16px; cursor: pointer;
      display: flex; align-items: center; justify-content: center; flex-shrink: 0;
    }
    .pw-fb-header .fb-close:hover { background: var(--sidebar-hover); color: var(--text); }
    .pw-fb-body {
      flex: 1; overflow-y: auto; padding: 1px 0;
      display: flex; flex-direction: column; gap: 12px; position: relative;
    }
    /* ── 内容视图（列表） ── */
    .pw-fb-body .fb-list-header {
      display: flex; align-items: center; gap: 5px; padding: 8px 12px;
      /* ★ 2026-09-28 用户："**项目资料/施工影像 内容标签模式顶部表头行内的字体也改为 16px**"
         （12 → 16px，与下面 `.fb-item .fb-name` 的行内字号一致，整张表只有一个字号）。
         ⚠ 全站唯一真源：`.fb-list-header` 只在这里定义 ⇒ 改这一处，项目资料 / 施工影像 / 项目工程
           的"标签模式顶部表头"一起生效。
         ⚠ 审核要点那两个"智库"库**不再显示这一行**（用户同轮第 3 条："顶部表头不要"）
           —— 那是组件侧不输出该 DOM，与这条字号无关。 */
      font-size: 16px; color: var(--muted); border-bottom: 1px solid var(--sidebar-border);
      flex-shrink: 0; user-select: none; position: sticky; top: 0;
      background: var(--panel); z-index: 1;
    }
    .pw-fb-body .fb-list-header .fb-h-name { flex: 1; }
    .pw-fb-body .fb-list-header .fb-h-date { width: 150px; text-align: center; }   /* ★ 与行里 `.fb-date` 同宽（见下） */
    .pw-fb-body .fb-list-header .fb-h-size { width: 80px; text-align: center; }
    .pw-fb-body .fb-item {
      display: flex; align-items: center; gap: 5px;
      padding: 0 12px; cursor: pointer; user-select: none;
      min-height: 42px; height: 42px;
      border-radius: 6px;
      border: 1px solid var(--line);
      background: var(--panel);
      transition: background .15s, border-color .15s;
      box-sizing: border-box;
      overflow: visible;
      content-visibility: auto; contain-intrinsic-size: auto 42px; contain: layout style;
      /* 2026-10-14 去掉 `translateZ(0)`：本行没有 transform 动画，它只把行永久升为合成层（无必要）。
         这不是 1px 问题的原因——真实根因是行压在滚区裁切边界，见 `.pw-inline-fb .pw-fb-body` 上方注释。 */
    }
    .pw-fb-body .fb-item:hover { background: var(--primary-soft); border-color: var(--primary); }
    /* ── 框选矩�?── */
    .fb-selection-box {
      position: absolute; border: 1px solid #63C6FF;
      background: rgba(99,198,255,0.1); z-index: 10; pointer-events: none;
    }
    .pw-fb-body .fb-item .fb-icon { font-size: 16px; width: 22px; text-align: center; flex-shrink: 0; }
    /* ★★ 2026-09-29 用户："**智库的标签模式小图标左边也要有序号**" ⇒ 最左那列放**本页顺序**（1 起）。
       宽度 30px：三位数（16px 字号 ≈ 27px）也装得下；颜色随 `.fb-date` 用 muted（不抢名字的注意力）。 */
    .pw-fb-body .fb-item .fb-idx {
      width: 30px; flex-shrink: 0; text-align: center;
      font-size: 15px; color: var(--muted);
    }
    .pw-fb-body .fb-item .fb-icon svg.ifb-ficon { width: 20px; height: 16px; display: block; margin: 0 auto; }
    .pw-fb-body .fb-item .fb-icon img.fb-thumb,
    .ifb-body .fb-item .fb-icon img.fb-thumb { width: 14px; height: 14px; object-fit: cover; border-radius: 2px; display: block; margin: 0 auto; transition: opacity .15s ease; }
    .pw-fb-body .fb-item .fb-name {
      flex: 1; font-size: 16px; color: var(--text); white-space: nowrap;
      overflow: hidden; text-overflow: ellipsis;
    }
    /* 文件夹名：**与卡片同口径** = 正文色（不是自造的蓝）。
       ★ 2026-09-28 用户第 2 条："项目资料 施工影像，**内容标签的文件名字体颜色 是正常色 / 黄色 / 绿色**
         —— 意思是和**卡片模式下同口径**，**不要自己造别的**"。
       卡片那边（`.ifb-card-item .ifb-card-name`）文件夹就是 `var(--text)`，从来不是蓝
       ⇒ 列表这边原来那条 `#63C6FF` 是"自己造的"，本轮去掉。 */
    .pw-fb-body .fb-item.fb-dir .fb-name { color: var(--text); font-weight: 600; }
    .pw-fb-body .fb-item.fb-file .fb-name { color: var(--text); }
    /* ★★ 2026-09-28 用户第 2 条：**列表模式也要有"正常色 / 黄 / 绿"三态**。
       ⚠ 为什么必须重写一遍（同款色值、只是提高特异性）：上面"卡片/列表缓存三态"那组里，
         列表那几条是 `.fb-item.ifb-cached .fb-name`（3 个 class），会被**下面**
         `.pw-fb-body .fb-item.fb-file .fb-name`（4 个 class）压住 ⇒ 列表模式下三态颜色
         **从来没生效过**（class 白挂）。⇒ 按 5 个 class 重写；上面那组里的**列表几条已删**
         （避免"死规则"误导），**卡片那几条保留**（卡片那边本来就生效）。
         色值与卡片逐项一致：绿 `#16a34a`（已缓存/秒开）、黄 `#ca8a04`（仅缩略图）、
         黄 `#eab308`（文件夹只缓存了一部分）。 */
    .pw-fb-body .fb-item.ifb-cached .fb-name { color: #16a34a; }
    .pw-fb-body .fb-item.ifb-thumb-only .fb-name { color: #ca8a04; }
    .pw-fb-body .fb-item.ifb-bytes-only .fb-name { color: #ca8a04; }
    .pw-fb-body .fb-item.ifb-dir-cached .fb-name { color: #16a34a; }
    .pw-fb-body .fb-item.ifb-dir-partial .fb-name { color: #eab308; }
    .pw-fb-body .fb-item .fb-date {
      /* ★ 2026-09-28 用户第 1 条："**项目资料 项目工程 施工影像 内容标签 右边的文字也要 16px，
         整个行的文字要统一大小 16**" ⇒ 12 → 16px。
         ⚠ 宽度 130 → **150px**：日期串最长是 `2026-09-28 18:30`（16 个半角字符 ≈ 134px），
           16px 字号下 130px 装不下会在盒子里**溢出居中**、压到名字列 ⇒ 必须一起放宽；
           表头那条 `.fb-h-date` 同步放宽（两处必须同值，否则列对不齐）。 */
      width: 150px; font-size: 16px; color: var(--muted); text-align: center; flex-shrink: 0;
    }
    .pw-fb-body .fb-item .fb-size {
      width: 80px; font-size: 16px; color: var(--muted); text-align: center; flex-shrink: 0;
    }
    /* ── 新建文件夹重命名─ */
    .ifb-list-filler {
      min-height: 42px; height: 42px;
    }
    .ifb-list-filler.drag-over {
      background: var(--primary-soft); border-radius: 6px;
    }
    .pw-fb-body .fb-item.fb-new-row { background: var(--sidebar-hover); }
    .pw-fb-body .fb-item.fb-new-row:hover { background: var(--sidebar-hover); }
    .pw-fb-body .fb-name-inline { flex: 1; }
    .pw-fb-body .fb-inline-input {
      width: 100%; padding: 2px 5px; font-size: 13px; color: var(--text);
      background: var(--panel); border: 1px solid #63C6FF; border-radius: 3px;
      outline: none; box-sizing: border-box;
    }
    .pw-fb-body .fb-empty {
      text-align: center; padding: 32px; color: var(--muted);
    }
    .pw-fb-footer {
      padding: 8px 14px; border-top: none;
      display: flex; justify-content: space-between; align-items: center;
      flex-shrink: 0; font-size: 12px; color: var(--muted);
    }
    .pw-fb-footer .fb-open-explorer {
      padding: 5px 12px; border-radius: 6px; border: 1px solid var(--sidebar-border);
      background: transparent; color: var(--text); cursor: pointer; font-size: 12px;
      transition: all .1s;
    }
    .pw-fb-footer .fb-open-explorer:hover { background: var(--sidebar-hover); border-color: var(--sidebar-border); }
    .pw-fb-loading {
      text-align: center; padding: 32px; color: var(--muted); font-size: 14px;
    }
    /* ── 还原按钮 ── */
    .pw-fb-header .fb-reset-pos {
      width: 24px; height: 24px; border-radius: 6px; border: none;
      background: transparent; color: var(--muted); font-size: 14px; cursor: pointer;
      display: flex; align-items: center; justify-content: center; flex-shrink: 0;
    }
    .pw-fb-header .fb-reset-pos:hover { background: var(--sidebar-hover); color: var(--text); }
    /* ── 右键菜单 ── */
    .fb-context-menu {
      position: fixed; z-index: 10001; width: 145px;
      background: var(--panel); border: 1px solid var(--sidebar-border);
      border-radius: 8px; box-shadow: 0 8px 24px rgba(0,0,0,.4);
      padding: 4px; overflow: hidden;
    }
    /* ⚠ 右键菜单的文字大小 = **16px 全站标准**（2026-09-24 用户："这个所有页面的右键菜单的文字大小要16px，
       并且把这个写入到我们的开发要求当中，以后只要有新的右键菜单出现右键菜单的文字大小必须是16px"）
       —— 原来 14px；同批一起改到 16px 的还有：`.fp-ctx-item`、`.ai-avatar-context-menu .ai-ctx-item`、
       `.project-card-context-menu .btn`、`.group-context-menu .btn`、`.photos-ctx-item`（photos 那个 css）、
       `.ldg-np-menu-title` / `.ldg-np-menu-confirm-msg`（notepad 那个 css）、`#aiHistoryCtxMenu`（ai-config 里内联）。
       ⚠ 桌面/开始菜单那一族（`.smbg-item`）本来就是 16px，没动。 */
    .fb-context-menu .fb-ctx-item {
      padding: 7px 14px; font-size: 16px; color: var(--text);
      cursor: pointer; border-radius: 5px; white-space: nowrap;
      text-align: left;
      transition: background .1s;
    }
    /* 空白处右键菜单：文字居中（2026-09-01）；文件项右键菜单默认左对齐 */
    .fb-context-menu.fb-ctx-center .fb-ctx-item { text-align: center; }
    .fb-context-menu .fb-ctx-item:hover { background: var(--sidebar-hover); }
    /* ── 上传进度条（右下角浮动卡片，不阻断网页交互）── */
    .upload-progress-overlay {
      position: fixed; z-index: 99999; bottom: 70px; right: 20px;
      background: none; pointer-events: none;
    }
    .upload-progress-card {
      background: var(--panel); border-radius: 12px;
      box-shadow: 0 8px 24px rgba(0,0,0,.35);
      padding: 14px 18px 8px 18px;
      /* 宽度随文字自适应（卡片贴右缘，文字多时向左加宽）；最小 300px，上限不超出视口 */
      width: max-content; min-width: 300px;
      max-width: min(560px, calc(100vw - 40px));
      pointer-events: none;
    }
    .upload-progress-title {
      font-size: 13px; font-weight: 600; color: var(--text);
      white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
      margin-bottom: 8px;
    }
    .upload-progress-bar-wrap {
      width: 100%; height: 6px; background: var(--sidebar-hover);
      border-radius: 3px; overflow: hidden; margin-bottom: 4px;
    }
    .upload-progress-bar {
      height: 100%; background: var(--primary, #36f);
      border-radius: 3px; transition: width .2s ease;
      width: 0%;
    }
    .upload-progress-info {
      font-size: 12px; color: var(--muted); display: flex; justify-content: space-between;
      margin-bottom: 2px;
    }
    .upload-progress-text { font-size: 12px; color: var(--muted); }
    .upload-progress-footer {
      display: flex; justify-content: flex-end; height: 20px; align-items: center;
    }
    .upload-progress-cancel {
      font-size: 12px; cursor: pointer; color: var(--muted); pointer-events: auto;
      user-select: none;
    }
    .upload-progress-cancel:hover { color: var(--primary); }
    /* ── 下载进度条（右下角浮动卡片，不阻断网页交互）── */
    .download-progress-overlay {
      position: fixed; z-index: 99999; bottom: 70px; right: 20px;
      background: none; pointer-events: none;
    }
    .download-progress-card {
      background: var(--panel); border-radius: 12px;
      box-shadow: 0 8px 24px rgba(0,0,0,.35);
      padding: 14px 18px 8px 18px; width: 300px;
      pointer-events: none;
    }
    .download-progress-title {
      font-size: 13px; font-weight: 600; color: var(--text);
      white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
      margin-bottom: 8px;
    }
    .download-progress-bar-wrap {
      width: 100%; height: 6px; background: var(--sidebar-hover);
      border-radius: 3px; overflow: hidden; margin-bottom: 4px;
    }
    .download-progress-bar {
      height: 100%; background: var(--primary, #36f);
      border-radius: 3px; transition: width .2s ease;
      width: 0%;
    }
    .download-progress-info {
      font-size: 12px; color: var(--muted); display: flex; justify-content: space-between;
      margin-bottom: 2px;
    }
    .download-progress-footer {
      display: flex; justify-content: flex-end; height: 20px; align-items: center;
    }
    .download-progress-cancel {
      font-size: 12px; cursor: pointer; color: var(--muted); pointer-events: auto;
      user-select: none;
    }
    .download-progress-cancel:hover { color: var(--primary); }
    /* ── 文件预览弹窗 ── */
    .file-preview-overlay {
      position: fixed; z-index: 20000; inset: 0;
      background: transparent; pointer-events: none;
    }
    .file-preview-modal {
      position: fixed;
      background: var(--modal-bg); border-radius: 14px;
      box-shadow: 0 16px 48px rgba(0,0,0,.5);
      display: flex; flex-direction: column; overflow: hidden;
      min-width: 320px; min-height: 200px;
      pointer-events: auto;
    }
    .file-preview-header {
      display: flex; align-items: center; justify-content: space-between;
      padding: 14px 20px; border-bottom: 1px solid var(--line);
      flex-shrink: 0; cursor: move; user-select: none;
    }
    .file-preview-title { font-size: 15px; font-weight: 600; color: var(--text); }
    .file-preview-actions {
      display: flex; align-items: center; gap: 6px;
    }
    .file-preview-action-btn {
      /* ★★ 2026-10-15 用户："这几个按钮的外宽度都加宽 30px。" ⇒ 先按字面做成 62px（32+30），
         随后用户复测改口："刚才加 30px 有点太宽了，把它改成 **45px**" ⇒ 定稿 **45px**（高 32px 不变）。 */
      width: 45px; height: 32px; border: none; border-radius: 8px;
      background: transparent; color: var(--muted); font-size: 24px;
      cursor: pointer; display: flex; align-items: center; justify-content: center;
      transition: background .15s, color .15s;
      padding: 0; flex-shrink: 0;
    }
    .file-preview-action-btn:hover { background: var(--sidebar-hover); color: var(--text); }
    /* 图标 = 内联 SVG（7 颗统一；颜色走按钮的 currentColor → 悬停随主题变亮变暗）
       ★★ 2026-10-15 用户两轮："这 5 个按钮里的图形比右边的「全屏」小一点，给它加大 20%" +
          "右上角那一排 7 个要一致方法；左右箭头**在电脑上偏得严重、还是很偏下**，但平板档位又合适"
          ⇒ ① 尺寸统一 **21.6px**（= 原 18 × 1.2）；
             ② ← → ⛶ ✕ 由**字符**改为**画出来的 SVG**（与分屏那 3 颗同款）：
                字符图形的墨迹位置随**字体**与**像素吸附**变，电脑与平板不是同一套符号字体 ⇒
                同一个 `line-height` 不可能两边同时居中（结论见 `lingdu-core.js` 的 ldgInkFix 注释）；
                画出来的图形是几何居中 ⇒ 与字体 / DPR / 缩放档位全无关。
             ⚠ 不要把它们退回字符：一旦退回，"电脑偏低 / 平板正常"这个老问题必然复发。 */
    .file-preview-action-btn svg { width: 21.6px; height: 21.6px; display: block; }
    .file-preview-action-btn svg rect { stroke: currentColor; fill: none; stroke-width: 1.85; }
    .file-preview-action-btn svg rect.fp-svg-fill { fill: currentColor; stroke: none; }
    .file-preview-action-btn svg path {
      /* 1.85 = 让屏幕线条恒等于 **2px**：20 视口 / 21.6px ⇒ 2 ÷ (21.6/20)。
         ★ 2026-10-15 用户："线条都统一用 2px"（悬浮组 ↑↓主页 同口径，那边是 1.26 / 1.6）。 */
      stroke: currentColor; fill: none; stroke-width: 1.85;
      stroke-linecap: round; stroke-linejoin: round;
    }
    .file-preview-action-btn:disabled { color: var(--muted); opacity: .35; cursor: not-allowed; background: transparent; }
    .file-preview-close:hover { background: var(--danger-bg,#fee2e2); color: var(--red,#ef4444); }
    .file-preview-modal.file-preview-fullscreen {
      inset: 0 !important; border-radius: 0; max-width: none; max-height: none;
    }
    /* 档位模式：预览弹窗跟随缩放（2026-08-14 用户拍板"弹窗也走缩放档位逻辑"）。
       不再做 zoom: calc(1/--ld-gear) 反向补偿 —— 弹窗视觉 = 布局 × 实际应用 zoom（--ld-zoom）。
       JS 中 clientX/rect/innerWidth 均为视觉CSS，换算回 style 布局坐标须 ÷--ld-zoom（_fpDivX/Y 返回 1/zApp）；
       全屏几何由 JS 按 innerWidth/Height÷--ld-zoom 设置（2026-08-22 修正：原 ÷档位在浏览器缩放≠100%
       时算小不铺满；--ld-zoom = 档位 ÷ 加载时浏览器缩放，才是实际渲染缩放）。 */
    .file-preview-body {
      flex: 1; overflow: auto; display: flex;
      align-items: center; justify-content: center;
      position: relative; min-height: 0;
    }
    .file-preview-loading { color: var(--muted); font-size: 15px; }
    .file-preview-error { color: var(--red); font-size: 14px; text-align: center; padding: 40px; }
    .file-preview-image {
      max-width: 100%; max-height: 100%; object-fit: contain;
      display: block;
    }
    .file-preview-zoom-layer {
      position: absolute; inset: 0;
      display: flex; align-items: center; justify-content: center;
      transform-origin: 0 0;
    }
    .file-preview-zoom-layer.file-preview-fit .file-preview-image {
      width: 100%; height: 100%; max-width: 100%; max-height: 100%; object-fit: contain;
    }
    .file-preview-zoom-layer .file-preview-image {
      max-width: none; max-height: none;
    }
    .file-preview-iframe {
      width: 100%; height: 100%; border: none;
    }
    /* ── PDF 操作工具栏 ── */
    .file-preview-pdfbar {
      display: flex; align-items: center; gap: 6px;
      padding: 7px 20px; border-bottom: 1px solid var(--line);
      flex-shrink: 0; flex-wrap: nowrap;
      overflow-x: auto; overflow-y: hidden;
      white-space: nowrap;
      /* 隐藏水平滚动条（保留滚轮/触控板滚动能力） */
      scrollbar-width: none;
      -ms-overflow-style: none;
    }
    .file-preview-pdfbar::-webkit-scrollbar { display: none; width: 0; height: 0; }
    .file-preview-pdfbar > * { flex-shrink: 0; }
    /* ★ 2026-10-11（用户）："图集预览 / 文件预览上面那一行按钮（文件批注、打印、下载、正文视图、
       到顶部、到底部…）的文字**是不是 16px？不是就改成 16px**，并且**不要加高按钮**（16px 完全放得下），
       宽度自适应。"
       ⇒ 字号 13 → **16px**；`height: 30px` 与左右内边距 11px **照旧**（不加高；宽度由文字宽度自适应）。 */
    .fp-btn {
      /* ★★ 2026-10-15（用户复测反馈 + 拍板）
         "在电脑上，文件预览顶部的按钮（文件批注 / 打印 / 下载）偏下；**料单审核的二级预览是好的**"
         ⇒ 用户定调：**撤掉此前两次"补丁式修补"，从按钮类本身根治** —— 照二级预览那套按钮的口径做。

         ▍老口径与二级预览**尺寸本来就一样**（关键前提，别再搞错）：
           本文件 L4203 有全局重置 `*, *::before, *::after { box-sizing: border-box }`
           ⇒ 老口径 `height:30px` 是**含边框的 30px**（内容盒 = 30 − 1 − 1 = 28），
             与二级预览 `box-sizing:border-box; height:30px` **完全同高**。
           实测佐证：真机截图里那条工具条，改前 44px 高（= 上 7 + 按钮 30 + 下 7），
             我先前误设 `height:32px` 后变成 46px（= 7 + 32 + 7）—— 这一栏**涨高 2px 是我的错**，已纠回。

         ▍于是老口径与二级预览**只差一处**：`line-height`。
           二级预览：`line-height:28px`（**恰等于内容盒高**）⇒ 行盒高 ≡ 内容盒高 ⇒ **半行距恒为 0**，
             文字基线在盒内没有多出来的小数余量 ⇒ 任意 `html{zoom}` / 缩放档位下吸附在同一处。
           老口径：**不写行高**（= `normal`）⇒ 内容盒 28 ≠ 行盒 ≈21 ⇒ 上下各留约 3.5px 小数余量 ⇒
             低档位取整漂移。真机逐像素取证（0.5 档、框内上下留白）：改前「上 4 行空 / 下 2 行空」= 文字偏低 2.5 CSS px；
             按下面口径改后「上 3 / 下 4」= 只在 1 CSS px 内（肉眼已分辨不出），与用户认可的二级预览一致。

         ▍本口径 = **二级预览那套原样**，只把字号留成本页的 16px（尺寸一个字都不改）：
           `box-sizing:border-box; height:30px; line-height:28px` + 原有 `padding:0 11px; border:1px`。
           ⇒ 按钮总高仍 30px（与改前**逐像素相同**）、字号仍 16px（用户 2026-10-11 拍板"16px 字、不加高按钮"）、
             宽度自适应 / 内边距 / 圆角 / 颜色全不变 —— 唯一变化是**行高从 normal 变成显式 28px**。
         ⚠ 二级预览那条规则里另有 `display:block` / `text-align:center` / `overflow+ellipsis` 三项，
           那是为它**竖栏里固定 83px 宽**（要省略号）写的，**与垂直居中无关**（flex 项本就被块级化），
           故此处不抄 —— 抄了反而会让本横条按钮在非 flex 场景下被拉成整行宽。

         ▍已撤掉的两次补丁（均不再保留）：
           ① "照抄二级预览口径（含尺寸）"的试改 —— 当时覆测用的自制 harness 没还原真机的 `border-box` 前提
              与缩放机制，把「本来就同高」误判成"会把总高压成 30"，结论不可信 ⇒ 撤（本次以真机截图为准）。
           ② `transform: translateY(var(--fp-btn-inkfix, 0em))` 运行时墨迹补偿 —— 它是**视觉平移**、
              量级仅 ~1px，低档位被取整直接抹掉（用户实测"还是不对"）⇒ 撤。
           ⚠ 由此本文件**不再消费** `--fp-btn-inkfix`（`lingdu-core.js` 同日起也不再写它）。 */
      box-sizing: border-box; height: 30px; line-height: 28px;
      padding: 0 11px; border: 1px solid var(--line);
      border-radius: 8px; background: transparent; color: var(--text);
      font-size: 16px; cursor: pointer; white-space: nowrap;
      transition: background .15s, border-color .15s;
    }
    .fp-btn:hover { background: var(--sidebar-hover); border-color: var(--primary); }
    .fp-btn:disabled { opacity: .4; cursor: not-allowed; }
    .fp-btn-primary { background: var(--primary); border-color: var(--primary); color: #fff; }
    .fp-btn-primary:hover { opacity: .88; background: var(--primary); border-color: var(--primary); }
    .fp-navgroup { margin-left: auto; display: flex; align-items: center; gap: 6px; }
    /* ★ 2026-10-11（用户）："『第 X 页 / 共 Y 页』这一串也按 16px。" ⇒ 12 → 16px（竖栏里另有 15px 的覆盖）。 */
    /* ★★ 2026-10-15（用户）："之前正确了的文件预览那个，现在测试案例『第 1 页 / 共 7 页』——数字是对的，
       『第 页 / 共 7 页』那一串字没对齐、有点偏下。"（= 旁边的「到顶部 / 到底部」今天已按新口径修好，
        这一串没跟上 ⇒ 两下一比就显出来了）
       ⇒ 同 `.fp-btn` 那套口径：**行盒 ≡ 所在盒** ⇒ 半行距恒为 0、不随缩放档位漂移：
         · `line-height: 26px` = **页码框（`.fp-page-input`）的高度** —— 本串的盒高就是它撑起来的
           （flex 容器取最高的子项）⇒ 文字行盒与容器盒同高；
         · 里面的空格文本（`第` / `页 / 共` / `页`）与 `#fpAnnTotalLabel` 都吃这一条。
       ⚠ 26 这个数**跟着 `.fp-page-input` 的 height 走**：改了框高，这里一起改（否则又差一点点）。 */
    .fp-pageinfo { font-size: 16px; color: var(--muted); display: flex; align-items: center; gap: 2px;
                   white-space: nowrap; line-height: 26px; }
    /* ★ 2026-10-11（用户）："中间那个**页码输入框太宽**（第 1 页时也很宽）——它就该像**文字原地可输**、
       宽度跟着内容走，不要一个专门的框。"
       ⇒ ① 宽度不再写死 44px，退回一个**很窄的兜底** `2ch`（真宽由 JS 按当前值量出来写进行内 `width`，
         见 `lingdu-files-annotate.js::_fpFitPageInput`）；② 外观照旧"无框无底"，只有 `:focus` 才现出边框。
       ★★ 2026-10-15（同上）：补 `line-height: 24px`（= **内容盒**高：26 − 上下各 1px 边框）——
         与 `.fp-btn` 同一口径（行盒 ≡ 内容盒）；不补的话框里的数字与外圈的中文基线不齐
         （Chrome 对 `<input>` 内部文字的行盒另走一套定位，与相邻的纯文本行盒吸附不到一起）。 */
    .fp-page-input {
      width: 2ch; height: 26px; box-sizing: border-box; margin: 0 2px;
      border: 1px solid transparent; border-radius: 6px; background: transparent;
      outline: none; text-align: center; font-size: 16px; line-height: 24px; color: var(--text);
    }
    .fp-page-input:focus { border-color: var(--primary, #2f6fed); background: var(--panel, #fff); }
    .fp-result-tag {
      font-size: 12px; color: #fff; background: var(--primary);
      border-radius: 6px; padding: 2px 8px; margin-left: 6px;
      cursor: pointer; user-select: none;
    }
    /* ── 高级编辑（自研页面级编辑器） ── */
    .fp-editor { width: 100%; height: 100%; display: flex; flex-direction: column; }
    .fp-ed-main { display: flex; flex: 1; min-height: 0; }
    .fp-ed-thumbs {
      width: 218px; min-width: 218px; overflow-y: auto; padding: 8px;
      box-sizing: border-box; border-right: 1px solid var(--line);
      display: flex; flex-direction: column; gap: 8px; align-content: flex-start;
    }
    .fp-ed-page {
      position: relative; border: 4px solid transparent; border-radius: 8px;
      cursor: pointer; background: var(--panel); overflow: hidden;
      transition: border-color .15s, box-shadow .15s;
      box-shadow: none;
    }
    .fp-ed-page:hover { border-color: var(--primary-soft, rgba(47,111,237,.55)); }
    .fp-ed-page.fp-ed-sel { border-color: var(--primary); }
    .fp-ed-page.fp-ed-drag { opacity: .45; border-style: dashed; }
    .fp-ed-thumb { overflow: hidden; }
    .fp-ed-thumb img { width: 100%; display: block; transition: transform .12s ease; }
    .fp-ed-num {
      position: absolute; top: 5px; left: 5px; z-index: 2;
      background: rgba(0,0,0,.55); color: #fff; font-size: 11px;
      padding: 1px 7px; border-radius: 9px; line-height: 16px; pointer-events: none;
    }
    .fp-ed-actions {
      display: flex; gap: 2px; padding: 4px 0 6px; justify-content: center;
    }
    .fp-ed-btn {
      height: 24px; min-width: 26px; padding: 0 6px; border: 1px solid var(--line);
      border-radius: 6px; background: transparent; color: var(--text);
      font-size: 12px; cursor: pointer; line-height: 1;
      transition: background .15s, border-color .15s;
    }
    .fp-ed-btn:hover { background: var(--sidebar-hover); border-color: var(--primary); }
    .fp-ed-del:hover { background: var(--danger-bg,#fee2e2); color: var(--red,#ef4444); border-color: var(--red,#ef4444); }
    .fp-ed-stage {
      flex: 1; min-width: 0; overflow: auto; padding: 14px;
      display: flex; flex-direction: column; align-items: center; justify-content: flex-start;
      gap: 10px;
    }
    .fp-ed-stage-info { font-size: 12px; color: var(--muted); align-self: flex-start; }
    .fp-ed-stage-img {
      max-width: 100%; max-height: 72vh; object-fit: contain;
      box-shadow: 0 2px 12px rgba(0,0,0,.15); border-radius: 4px;
      transition: transform .12s ease; background: #fff;
    }
    .fp-ed-bar {
      display: flex; align-items: center; gap: 8px; padding: 8px 14px;
      border-top: 1px solid var(--line); flex-shrink: 0; flex-wrap: wrap;
    }
    /* ── PDF 标注（PDF.js 预览 + 批注层） ── */
    .fp-grp { font-size: 11px; color: var(--muted); padding: 0 2px; user-select: none; }
    .fp-ann-tool { }
    .fp-ann-tool.fp-ann-active {
      background: color-mix(in srgb, var(--primary) 18%, transparent); border-color: var(--primary); color: var(--primary);
    }
    /* ★ 2026-10-15（用户）："图集预览里面的批注有两个（优效备注 / 错误备注），给它改为一个 ——
       只保留错误备注，这个按钮的名字改为『**插入批注**』。"
       ⇒ 图集/规范预览里把「优效备注」那颗备注笔藏掉（判据与改名见 annotate-ops 的 `_fpAnnApplyNoteLabels`）。
       ⚠ 必须 `!important`：那颗按钮是「文件批注」组员，点组标题展开时 `_fpAnnGrpApply()` 会给组员写
         inline `style.display = ''`（把整组放出来）—— 普通优先级压不住 inline，不用 `!important` 会被"复活"。 */
    .fp-ann-note-off { display: none !important; }
    /* 标注文字字号设置面板（文字按钮右键弹出） */
    .fp-tool-wrap { position: relative; display: inline-flex; }
    .fp-text-size-panel {
      position: absolute; top: calc(100% + 6px); left: 0; z-index: 70;
      min-width: 190px; padding: 9px 12px;
      background: var(--panel, #fff); border: 1px solid var(--line, rgba(0,0,0,.12));
      border-radius: 10px; box-shadow: 0 10px 28px rgba(0,0,0,.18);
    }
    .fp-text-size-title { font-size: 12px; color: var(--muted, #888); margin-bottom: 6px; }
    .fp-text-size-row { display: flex; align-items: center; gap: 8px; }
    .fp-text-size-row input[type="range"] { flex: 1; min-width: 120px; }
    .fp-text-size-val {
      min-width: 30px; text-align: center; font-size: 15px; font-weight: 700;
      color: var(--primary, #2563eb);
    }
    /* 画笔设置面板（画笔按钮右键弹出：颜色色块 + 粗细滑条） */
    .fp-pen-panel {
      position: absolute; top: calc(100% + 6px); left: 0; z-index: 70;
      min-width: 190px; padding: 9px 12px;
      background: var(--panel, #fff); border: 1px solid var(--line, rgba(0,0,0,.12));
      border-radius: 10px; box-shadow: 0 10px 28px rgba(0,0,0,.18);
    }
    .fp-pen-title { font-size: 12px; color: var(--muted, #888); margin: 4px 0 6px; }
    .fp-pen-title:first-child { margin-top: 0; }
    .fp-pen-colors { display: flex; gap: 8px; margin-bottom: 8px; }
    .fp-pen-color {
      width: 24px; height: 24px; padding: 0; border-radius: 50%;
      border: 2px solid transparent; cursor: pointer;
      box-shadow: inset 0 0 0 1px rgba(0,0,0,.15);
      transition: transform .12s, border-color .12s;
    }
    .fp-pen-color:hover { transform: scale(1.15); }
    .fp-pen-color.fp-pen-active {
      border-color: var(--primary, #2563eb);
      transform: scale(1.1);
    }
    #fpLineDropBtn.fp-ann-active {
      background: color-mix(in srgb, var(--primary) 18%, transparent); border-color: var(--primary); color: var(--primary);
    }
    .fp-ann-view { display: flex; width: 100%; height: 100%; min-height: 0; }
    .fp-ann-thumbs {
      width: 256px; min-width: 256px; max-width: 256px;
      overflow-y: auto; padding: 10px 8px; box-sizing: border-box;
      border-right: 1px solid var(--line);
      display: flex; flex-direction: column; gap: 8px; align-items: center;
    }
    .fp-ann-thumb {
      position: relative; width: 100%; cursor: pointer;
      border: 4px solid transparent; border-radius: 8px;
      overflow: hidden; background: var(--panel);
      transition: border-color .15s;
      flex-shrink: 0;
    }
    /* 缩略图占位骨架：渲染前显示页码数字，撑起与最终图一致的比例，保证高亮/滚动立即可用 */
    .fp-ann-thumb-ph {
      width: 100%; aspect-ratio: 210 / 297;
      display: flex; align-items: center; justify-content: center;
      background: var(--panel-soft, rgba(0,0,0,.04));
      color: var(--muted, #999); font-size: 15px; font-weight: 600;
      user-select: none;
    }
    .fp-ann-thumb canvas { display: block; width: 100%; height: auto; }
    .fp-ann-outline {
      width: 100%; box-sizing: border-box; flex-shrink: 0;
      border: 1px solid var(--line); border-radius: 8px;
      background: var(--panel); overflow: hidden;
    }
    .fp-ann-outline-head {
      display: flex; justify-content: space-between; align-items: center;
      padding: 6px 8px; cursor: pointer; font-size: 12px;
      color: var(--text); border-bottom: 1px solid var(--line);
      user-select: none;
    }
    .fp-ann-outline-fold { font-size: 10px; color: var(--muted); }
    .fp-ann-outline-list { overflow-y: auto; }
    .fp-ann-outline-item {
      padding: 3px 8px; font-size: 12px; cursor: pointer;
      color: var(--text); white-space: nowrap; overflow: hidden;
      text-overflow: ellipsis;
    }
    .fp-ann-outline-item:hover { background: rgba(47,111,237,.08); color: var(--primary); }
    .fp-ann-outline-empty { padding: 6px 8px; font-size: 12px; color: var(--muted); }
    /* 展开书签：隐藏缩略图，整个左侧栏给书签用 */
    .fp-ann-thumbs.fp-ann-outline-open .fp-ann-thumb { display: none; }
    .fp-ann-thumbs.fp-ann-outline-open .fp-ann-outline {
      flex: 1; display: flex; flex-direction: column;
    }
    .fp-ann-thumbs.fp-ann-outline-open .fp-ann-outline-list {
      flex: 1; max-height: none; overflow-y: auto;
    }
    .fp-ann-thumb:hover { border-color: var(--primary-soft, rgba(47,111,237,.55)); }
    .fp-ann-thumb.fp-ann-thumb-sel { border-color: var(--primary); }
    .fp-ann-thumb canvas { width: 100%; display: block; }
    .fp-ann-thumb-num {
      position: absolute; top: 4px; left: 4px; z-index: 2;
      background: rgba(0,0,0,.55); color: #fff; font-size: 14px;
      padding: 0 9px; border-radius: 12px; line-height: 21px;
      pointer-events: none;
    }
    .fp-ann-pages {
      flex: 1; min-width: 0; overflow-y: auto; position: relative;
      padding: 12px 14px 64px; box-sizing: border-box;
      display: flex; flex-direction: column; align-items: center;
    }
    .fp-ann-page {
      position: relative; margin: 0 0 16px;
      box-shadow: 0 1px 8px rgba(0,0,0,.18); background: #fff;
      flex-shrink: 0;
    }
    /* 正文页骨架占位：canvas 填充前显示极浅灰底，撑起完整滚动范围/高亮/跳转 */
    .fp-ann-page-ph {
      background: linear-gradient(180deg, #fbfcfd, #f4f5f7);
    }
    /* 视图旋转内容层：svg 相对该层定位，旋转后白底贴合内容包围盒 */
    .fp-ann-rot {
      position: absolute; left: 50%; top: 50%;
      transform-origin: center center;
      /* 布局由 JS 设宽高 + transform rotate 完成 */
    }
    .fp-ann-page canvas { display: block; }
    .fp-ann-page svg {
      position: absolute; left: 0; top: 0; overflow: visible;
      pointer-events: auto;
      /* pan-y：允许触摸垂直滚动正文，水平/捏合仍禁用（none 会禁掉整页触摸滚动） */
      touch-action: pan-y;
    }
    .fp-ann-page svg .fp-ann-sel { outline: 1.5px solid #1a73e8; outline-offset: 1px; }
    /* 框选虚线框（指针模式拖拽选择） */
    .fp-ann-boxsel {
      position: absolute; z-index: 7; box-sizing: border-box;
      border: 1.5px dashed #1a73e8; background: rgba(26, 115, 232, .12);
      pointer-events: none; display: none;
    }
    /* ── PDF 预览 Ctrl+框选→区域 OCR（2026-09-01 新增）── */
    .fp-ocr-sel {
      position: absolute; z-index: 60; box-sizing: border-box;
      border: 1.5px solid #1a73e8;
      background: rgba(26, 115, 232, .12);
      box-shadow: 0 0 0 1px rgba(255, 255, 255, .7);
      pointer-events: none;
    }
    .fp-ocr-toast {
      position: fixed; left: 50%; top: 50%; transform: translate(-50%, -50%);
      z-index: 999999; max-width: 70vw; box-sizing: border-box;
      background: rgba(20, 20, 30, .93); color: #fff;
      font-size: 13px; padding: 9px 16px; border-radius: 9px;
      box-shadow: 0 4px 18px rgba(0, 0, 0, .28);
      white-space: pre-line; line-height: 1.5;
      display: none; pointer-events: none;
    }
    .fp-ocr-toast.ok { background: rgba(10, 125, 46, .95); }
    .fp-ocr-toast.err { background: rgba(198, 40, 40, .95); }
    /* 文字批注输入框（拖框直接打字） */
    .fp-ann-text-ed {
      position: absolute; z-index: 8; box-sizing: border-box;
      min-width: 40px; min-height: 20px;
      outline: 1px dashed var(--primary, #1a73e8); /* outline 不占布局：文字起点即 x1，与提交后渲染一致，左边固定 */
      padding: 0 2px 0 0; line-height: 1.3; overflow: hidden;
      white-space: pre-wrap; word-break: break-all; font-family: inherit;
    }
    .fp-ann-nav {
      display: flex; align-items: center; gap: 6px;
      background: var(--panel); border: 1px solid var(--line);
      border-radius: 10px; padding: 4px 8px; box-shadow: 0 2px 10px rgba(0,0,0,.12);
      margin: 2px 0 14px; flex-shrink: 0;
    }
    .fp-ann-nav .fp-ann-plabel { font-size: 12px; color: var(--text); min-width: 44px; text-align: center; }
    .fp-ann-nav .fp-ann-sep { width: 1px; height: 18px; background: var(--line); margin: 0 2px; }
    .fp-ann-plabel { font-size: 12px; color: var(--text); min-width: 36px; text-align: center; white-space: nowrap; }
    input.fp-ann-plabel {
      width: 52px; height: 26px; box-sizing: border-box;
      border: 1px solid transparent; border-radius: 6px;
      background: transparent; outline: none;
    }
    input.fp-ann-plabel:focus { border-color: var(--primary, #2f6fed); background: var(--panel, #fff); }
    .fp-ann-loading {
      display: flex; align-items: center; justify-content: center;
      height: 100%; color: var(--muted); font-size: 14px;
    }
    /* ── PDF 操作参数面板 ── */
    .file-preview-pdfpanel {
      padding: 10px 20px; border-bottom: 1px solid var(--line);
      flex-shrink: 0; background: var(--sidebar-bg, rgba(0,0,0,.03));
    }
    .fpp-row { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
    .fpp-label { font-size: 13px; color: var(--muted); white-space: nowrap; }
    .fpp-input {
      height: 30px; padding: 0 10px; border: 1px solid var(--line);
      border-radius: 8px; background: var(--panel); color: var(--text);
      font-size: 13px; min-width: 180px; box-sizing: border-box;
    }
    .fpp-input:focus { outline: none; border-color: var(--primary); }
    .fpp-btns { display: flex; gap: 8px; }
    .fpp-btn {
      height: 30px; padding: 0 14px; border: 1px solid var(--line);
      border-radius: 8px; background: transparent; color: var(--text);
      font-size: 13px; cursor: pointer; transition: background .15s;
    }
    .fpp-btn:hover { background: var(--sidebar-hover); }
    .fpp-btn-primary { background: var(--primary); border-color: var(--primary); color: #fff; }
    .fpp-btn-primary:hover { opacity: .88; background: var(--primary); }
    .fpp-btn-danger { background: var(--red,#ef4444); border-color: var(--red,#ef4444); color: #fff; }
    .fpp-msg { font-size: 12px; color: var(--muted); flex: 1; min-width: 120px; }
    .fpp-err { font-size: 12px; color: var(--red,#ef4444); flex: 1; min-width: 120px; }
    .fpp-loading { font-size: 13px; color: var(--muted); padding: 4px 0; }
    .fpp-file-list {
      max-height: 150px; overflow-y: auto; border: 1px solid var(--line);
      border-radius: 8px; padding: 6px; background: var(--panel);
      margin-top: 8px; display: flex; flex-direction: column; gap: 2px;
    }
    .fpp-file-item {
      display: flex; align-items: center; gap: 8px; padding: 5px 8px;
      border-radius: 6px; cursor: pointer; font-size: 13px; color: var(--text);
    }
    .fpp-file-item:hover { background: var(--sidebar-hover); }
    .fpp-file-item.checked { background: var(--primary-soft, rgba(0,120,255,.12)); }
    .fpp-file-item input { pointer-events: none; }
    /* 预览弹窗左右翻页热区 */
    .fp-nav-left, .fp-nav-right {
      position: absolute; top: 20%; height: 60%; width: 84px;   /* ★ 2026-10-05 用户：热区过宽 ⇒ 120px 减 30% = 84px */
      z-index: 12; touch-action: none; cursor: default;
    }
    .fp-nav-left { left: 5px; }
    .fp-nav-right { right: 5px; }
    .fp-nav-left.active, .fp-nav-right.active { cursor: pointer; }
    .fp-nav-left.active:hover { background: linear-gradient(to right, rgba(0,0,0,.08), transparent); }
    .fp-nav-right.active:hover { background: linear-gradient(to left, rgba(0,0,0,.08), transparent); }
    .file-preview-text {
      width: 100%; height: 100%; margin: 0; padding: 16px 20px;
      overflow: auto; white-space: pre-wrap; word-break: break-all;
      font-size: 13px; line-height: 1.6; color: var(--text);
      background: var(--sidebar-bg,#f5f5f5); box-sizing: border-box;
    }
    .file-preview-download {
      text-align: center; padding: 60px 20px;
    }
    .file-preview-download-icon { font-size: 48px; margin-bottom: 12px; }
    .file-preview-download-msg { color: var(--muted); margin-bottom: 20px; font-size: 14px; }
    .file-preview-download-btn {
      display: inline-block; padding: 10px 28px; border-radius: 10px;
      background: var(--primary); color: #fff; text-decoration: none;
      font-size: 14px; font-weight: 500; transition: opacity .15s;
    }
    .file-preview-download-btn:hover { opacity: .85; }
    /* 预览弹窗右键菜单 */
    .fp-ctx-menu {
      position: fixed; z-index: 30000;
      background: var(--panel); border: 1px solid var(--line);
      border-radius: 10px; box-shadow: 0 8px 24px rgba(0,0,0,.4);
      padding: 6px 0; min-width: 150px;
    }
    .fp-ctx-item {
      padding: 8px 16px; font-size: 16px; color: var(--text);   /* 13→16：右键菜单字号全站统一（见 .fb-ctx-item 那条） */
      cursor: pointer; white-space: nowrap;
      transition: background .1s;
    }
    .fp-ctx-item:hover { background: var(--sidebar-hover); }
    .fp-ctx-item.disabled {
      color: var(--muted); opacity: .4; cursor: not-allowed;
      pointer-events: none;
    }
    /* ★★ 2026-09-29（再二轮）用户："落定到正文区的**文本字体右键要可以设置字号，私有**（不用弹框），
       右键菜单**列出来**" ⇒ PDF 预览右键菜单里追加一组：小标题 + 数字网格，当前字号那颗高亮（`.on`）。
       ★★ 2026-09-30 用户："这个文字的右键菜单的 **11-50**（下限 17→13→11），**菜单高度改为能放下**"
       ⇒ 值变多，**高度封顶放到能一次放下全部（不滚动）**。
       ★★ 2026-09-30 用户："**4 列改为 5 列**" ⇒ 11–50 有 **40** 个值，5 列 ⇒ ceil(40/5)=**8 行**，
         每行 ≈ 16px 字号行盒 + 上下各 4px padding（约 30~34px），8 行 + 7 个 2px gap ≈ 250~290px
         ⇒ 封顶仍取 **380px**（只封顶；实际高度=自然高度，超视口时由 `showContextMenuAt` 给整菜单限高+滚动兜底）。 */
    /* ★★ 2026-09-29 用户："正文区的文本「字号」那组的菜单 **文字大小统一为 16px**
       —— 这个开发要求有说吧右键菜单字号最低 16px" ⇒ 全站硬规则（《开发要求》「右键菜单字号」那一节：
       **菜单条目 / 标题说明行 / 小角标一律 16px，不开特例**）⇒ 这一组原来 13/14px，**改回 16px**。
       ⚠ 5 列网格也要放得下两位数（16px 下约 18px 宽 / 列）⇒ 列宽用 `minmax(0,1fr)` 允许收缩。 */
    /* ★★ 2026-09-30 用户："字号本张……描述去掉" ⇒ 删除 `.fp-ctx-fs-cap` 小标题；
       本轮用户又补："去掉之后 有个分割线也不要了" ⇒ **连从 cap 迁移过来的上边框（分割线）也去掉**，
       只留一点上间距（`margin-top`），与上方菜单条目靠留白分隔。 */
    .fp-ctx-fs-grid {
      display: grid; grid-template-columns: repeat(5, minmax(0, 1fr)); gap: 2px;
      margin-top: 4px;
      padding: 6px 8px 6px;
      max-height: 380px; overflow-y: auto;
    }
    .fp-ctx-fs-grid .fp-ctx-item { padding: 4px 0; font-size: 16px; text-align: center; border-radius: 6px; }
    .fp-ctx-fs-grid .fp-ctx-item.on {
      background: var(--primary-soft); color: var(--primary); font-weight: 700;
    }
    /* 标题栏卡片圆圈序号 */
    .file-preview-card-num {
      display: inline-flex; align-items: center; justify-content: center;
      min-width: 23px; height: 23px; border-radius: 50%;
      border: 1.5px solid currentColor;
      font-size: 12px; font-weight: 700; padding: 0 4px;
      margin-left: 6px; vertical-align: middle;
      box-sizing: border-box; line-height: 1;
    }
    /* 预览弹窗缩放把手 */
    .fp-resize { position: absolute; z-index: 11; touch-action: none; }
    .fp-resize-n { top: 0; left: 6px; right: 6px; height: 5px; cursor: n-resize; }
    .fp-resize-s { bottom: 0; left: 6px; right: 6px; height: 5px; cursor: s-resize; }
    .fp-resize-e { right: 0; top: 6px; bottom: 6px; width: 5px; cursor: e-resize; }
    .fp-resize-w { left: 0; top: 6px; bottom: 6px; width: 5px; cursor: w-resize; }
    .fp-resize-ne { top: 0; right: 0; width: 10px; height: 10px; cursor: ne-resize; }
    .fp-resize-nw { top: 0; left: 0; width: 10px; height: 10px; cursor: nw-resize; }
    .fp-resize-se { bottom: 0; right: 0; width: 10px; height: 10px; cursor: se-resize; }
    .fp-resize-sw { bottom: 0; left: 0; width: 10px; height: 10px; cursor: sw-resize; }
    /* ── 删除确认浮层 ── 2026-10-09 用户："300*100 大小都改为 350*150" → 再定稿 350*130 */
    .fb-confirm-popup {
      position: fixed; z-index: 10002; width: 350px; min-height: 130px;
      display: flex; flex-direction: column; justify-content: space-between;
      background: var(--panel); border: 1px solid #ef4444; border-radius: 8px;
      box-shadow: 0 8px 24px rgba(0,0,0,.5); padding: 12px 14px;
      box-sizing: border-box;
    }
    /* 2026-10-09 用户："300*100 这个对话框的文字微调下统一 16px" ⇒ 正文/按钮一律 16px（原来 14/13） */
    .fb-confirm-msg { font-size: 16px; color: var(--text); line-height: 1.5; word-break: break-all; }
    .fb-confirm-btns { display: flex; gap: 8px; justify-content: flex-end; }
    .fb-confirm-btn {
      padding: 4px 14px; border-radius: 5px; font-size: 16px; cursor: pointer; border: none;
      background: #ef4444; color: #fff; font-weight: 600; transition: background .1s;
    }
    .fb-confirm-btn:hover { background: #dc2626; }
    .fb-confirm-btn.fb-confirm-cancel { background: var(--sidebar-hover); color: var(--text); }
    .fb-confirm-btn.fb-confirm-cancel:hover { background: var(--sidebar-border); }
    .fb-confirm-btn.fb-confirm-focus { outline: 2px solid var(--primary, #36f); outline-offset: 2px; }
    /* ── 缩放把手 ── */
    .fb-resize-handle { position: absolute; z-index: 10; touch-action: none; }
    .fb-resize-n  { top: 0; left: clamp(5px, 0.31vw, 8px); right: clamp(5px, 0.31vw, 8px); height: clamp(4px, 0.23vw, 6px); cursor: n-resize; }
    .fb-resize-s  { bottom: 0; left: clamp(5px, 0.31vw, 8px); right: clamp(5px, 0.31vw, 8px); height: clamp(4px, 0.23vw, 6px); cursor: s-resize; }
    .fb-resize-e  { top: clamp(5px, 0.31vw, 8px); right: 0; bottom: clamp(5px, 0.31vw, 8px); width: clamp(4px, 0.23vw, 6px); cursor: e-resize; }
    .fb-resize-w  { top: clamp(5px, 0.31vw, 8px); left: 0; bottom: clamp(5px, 0.31vw, 8px); width: clamp(4px, 0.23vw, 6px); cursor: w-resize; }
    .fb-resize-ne { top: 0; right: 0; width: clamp(11px, 0.63vw, 16px); height: clamp(11px, 0.63vw, 16px); cursor: ne-resize; }
    .fb-resize-nw { top: 0; left: 0; width: clamp(11px, 0.63vw, 16px); height: clamp(11px, 0.63vw, 16px); cursor: nw-resize; }
    .fb-resize-se { bottom: 0; right: 0; width: clamp(11px, 0.63vw, 16px); height: clamp(11px, 0.63vw, 16px); cursor: se-resize; }
    .fb-resize-sw { bottom: 0; left: 0; width: clamp(11px, 0.63vw, 16px); height: clamp(11px, 0.63vw, 16px); cursor: sw-resize; }

    /* ========== 智慧管理 3 列布局 ========== */
    .ai-center {
      position: relative;
      flex: 1;
      min-height: 0;
      border-radius: 18px;
      border: 1px solid var(--line);
      background: var(--panel);
      overflow: hidden;
      display: flex;
      flex-direction: column;
    }
    /* 智慧管理(#智慧管理)去掉底层容器框：.ai-center 去掉圆角/边框/背景/剪切，
       保留布局属性，不影响其他视图。 */
    #智慧管理 .ai-center {
      border: none;
      border-radius: 0;
      background: transparent;
      overflow: visible;
    }
    .ai-stage {
      position: relative;
      z-index: 1;
      flex: 1;
      min-height: 0;
      display: grid;
      grid-template-columns: 7fr 20fr;
      /* 2026-09-06 用户：对话列底部要贴到列底。
         行高固定 1fr：让各列(grid items)按容器高拉伸，卡片 flex:1 随之撑满，
         避免行高 auto 时列只在内容高度处结束、下方留白。 */
      grid-template-rows: 1fr;
      gap: 20px;
      padding: 22px 19px 20px;
      width: 100%;
      max-width: 1720px;
    }
    /* 智慧管理(#智慧管理)：外框已去掉，卡片距外框的距离改为 0，
       让内容直接贴合视图边缘。 */
    #智慧管理 .ai-stage {
      padding: 0;
    }
    /* 2026-09-06 用户：主对话移到第二列(最右)且保持最宽。
       不改 DOM 顺序，用 grid 显式列定位，避免影响窄屏单列堆叠次序。
       必须同时显式 grid-row:1：DOM 顺序是 left(1)→center(2)，列号回退时
       grid 自动放置会把光标推到第 2 行(整体下移、ai-stage 变 2 行导致对话列底部撑不满)。
       ⚠ 2026-09-21 用户："待办事项、记事本不要了" → 原来的第 2 列（待办+记事本）已删除，
         现在是两列：历史(1) + 对话(2)。 */
    #智慧管理 .ai-left-col   { grid-column: 1; grid-row: 1; }
    #智慧管理 .ai-center-col { grid-column: 2; grid-row: 1; }
    /* 2026-09-06 用户：聊天列在"可见侧列右侧的剩余区域"里铺满——本身宽度铺满，
       历史列折叠/展开时用 transform 左右平移（位移量由 JS updateAiChatCenter 算）。 */
    #智慧管理 .ai-center-col { transition: transform .25s ease; }
    /* 2026-09-06 用户：历史对话列上浮，占住顶部按钮行避让让出的空间，
       顶部与按钮行齐平；聊天列(.ai-center-col)保持被按钮行压在下方不动。
       上浮量 = 导航行高(41px) + 行下间距(16px) = 57px，列同步加高 57px，
       保证历史列底部仍与聊天列底部对齐。 */
    #智慧管理 .ai-left-col {
      margin-top: -57px;
      height: calc(100% + 57px);
    }
    .ai-left-col,
    .ai-center-col {
      min-width: 0;
      min-height: 0;
      display: flex;
      flex-direction: column;
    }
    .ai-left-col {
      transition: width .25s ease, opacity .25s ease, padding .25s ease;
      overflow: hidden;
    }
    .ai-left-col-collapsed {
      width: 0 !important;
      padding: 0 !important;
      opacity: 0;
    }
    .ai-card {
      display: flex;
      flex-direction: column;
      border: 1px solid var(--line);
      border-radius: 20px;
      background: var(--card-gradient);
      min-height: 0;
      flex: 1;
      overflow: hidden;
    }
    .ai-col-title {
      margin: 0;
      font-size: 18px;
      font-weight: 700;
      color: var(--text);
      flex-shrink: 0;
    }

    /* 左列：历史对�?*/
    .ai-history-card {
      padding: 20px 14px 14px;
      gap: 16px;
    }
    .ai-history-header {
      display: flex;
      flex-direction: column;
      align-items: stretch;
      gap: 14px;
      flex-shrink: 0;
    }
    .ai-history-topbar {
      display: flex;
      align-items: center;
      justify-content: flex-start;
      gap: 8px;
      margin-top: -10px;
    }
    .ai-history-actions {
      display: flex;
      align-items: center;
      gap: 4px;
    }
    .ai-history-action-btn {
      width: 35px; /* 2026-09-03 30→35 用户要求 */
      height: 35px; /* 2026-09-03 30→35 用户要求 */
      display: flex;
      align-items: center;
      justify-content: center;
      border-radius: 8px;
      border: none;
      background: transparent;
      color: var(--muted);
      font-size: 17px;
      cursor: pointer;
      transition: color .15s, background .15s;
      padding: 0;
    }
    .ai-history-action-btn svg {
      width: 18px;
      height: 18px;
    }
    .ai-history-action-btn:hover {
      color: var(--text);
      background: var(--primary-soft);
    }
    .ai-history-search-box {
      flex-shrink: 0;
    }
    .ai-history-search-input {
      width: 100%;
      padding: 8px 12px;
      border-radius: 10px;
      border: 1px solid var(--line);
      background: var(--panel);
      color: var(--text);
      font-size: 13px;
      outline: none;
      box-sizing: border-box;
    }
    .ai-history-search-input:focus {
      border-color: var(--primary);
      box-shadow: 0 0 0 3px var(--primary-soft);
    }
    .ai-history-search-input::placeholder {
      color: var(--muted);
    }
    .ai-new-chat-btn {
      width: 100%;
      display: flex;
      align-items: center;
      justify-content: center;
      gap: 8px;
      padding: 10px 14px;
      border-radius: 12px;
      border: 1px solid rgba(255,255,255,.1);
      background: rgba(255,255,255,.12);
      color: var(--text);
      font-size: 14px;
      font-weight: 600;
      cursor: pointer;
      transition: background .15s, transform .1s;
      margin-top: -10px;
    }
    .ai-new-chat-btn:hover {
      background: rgba(255,255,255,.18);
    }
    .ai-new-chat-btn:active {
      transform: scale(.98);
    }
    .ai-new-chat-icon {
      width: 18px;
      height: 18px;
      display: flex;
      align-items: center;
      justify-content: center;
      line-height: 1;
    }
    .ai-new-chat-icon svg {
      width: 100%;
      height: 100%;
    }
    .ai-history-list {
      flex: 1;
      overflow-y: auto;
      display: flex;
      flex-direction: column;
      gap: 18px;
      min-height: 0;
    }
    .ai-history-group {
      display: flex;
      flex-direction: column;
      gap: 4px;
    }
    .ai-history-group-title {
      font-size: 15px;
      color: var(--muted);
      padding: 0 8px;
      margin-bottom: 2px;
      font-weight: 600;
      cursor: pointer;
      user-select: none;
    }
    .ai-history-group-caret {
      display: inline-block;
      width: 14px;
      margin-right: 2px;
      font-size: 10px;
      color: var(--muted);
    }
    .ai-history-group-caret::before {
      content: '▼';
    }
    .ai-history-group-collapsed .ai-history-group-caret::before {
      content: '▶';
    }
    .ai-history-group-items {
      display: flex;
      flex-direction: column;
      gap: 4px;
    }
    .ai-history-group-collapsed .ai-history-group-items {
      display: none;
    }
    .ai-history-item {
      padding: 7px 0;
      border-radius: 6px;
      padding-left: 12px;
      padding-right: 12px;
      border: none;
      background: transparent;
      color: var(--text);
      font-size: 15px;
      cursor: pointer;
      transition: background .15s;
      white-space: nowrap;
      overflow: hidden;
      text-overflow: ellipsis;
      user-select: none;
    }
    .ai-history-item:hover {
      background: var(--primary-soft);
    }
    .ai-history-item.active {
      background: var(--primary-soft);
      color: var(--primary);
      font-weight: 600;
    }

    /* ── 历史搜索：内容搜索结果列表（2026-09-10）── */
    .ai-search-group {
      display: flex;
      flex-direction: column;
      gap: 2px;
      margin-bottom: 10px;
    }
    .ai-search-group-title {
      font-size: 15px;
      font-weight: 600;
      color: var(--text);
      padding: 4px 10px;
      border-radius: 6px;
      cursor: pointer;
      user-select: none;
      white-space: nowrap;
      overflow: hidden;
      text-overflow: ellipsis;
    }
    .ai-search-group-title:hover,
    .ai-search-group-title.active {
      background: var(--primary-soft);
      color: var(--primary);
    }
    .ai-search-group-date {
      font-size: 12px;
      font-weight: 400;
      color: var(--muted);
      margin-left: 6px;
    }
    .ai-search-hit {
      display: flex;
      gap: 6px;
      align-items: flex-start;
      padding: 5px 10px 5px 14px;
      border-radius: 6px;
      border-left: 2px solid transparent;
      font-size: 13px;
      line-height: 1.45;
      color: var(--muted);
      cursor: pointer;
    }
    .ai-search-hit:hover {
      background: var(--primary-soft);
      border-left-color: var(--primary);
      color: var(--text);
    }
    .ai-search-hit-role {
      flex: 0 0 auto;
      font-size: 11px;
      color: var(--primary);
      opacity: .85;
      padding-top: 1px;
    }
    .ai-search-hit-text {
      flex: 1;
      min-width: 0;
      overflow: hidden;
      display: -webkit-box;
      -webkit-line-clamp: 2;
      -webkit-box-orient: vertical;
      word-break: break-word;
    }
    .ai-search-mark {
      background: rgba(255, 196, 0, .35);
      color: inherit;
      border-radius: 2px;
    }
    .ai-search-empty {
      font-size: 13px;
      color: var(--muted);
      padding: 8px 12px;
    }
    /* 搜索定位到消息后气泡短暂高亮（只动 box-shadow，避免覆盖气泡自身底色） */
    .ai-message-bubble.ai-msg-jump-flash {
      animation: aiMsgJumpFlash 1.8s ease-out;
    }
    @keyframes aiMsgJumpFlash {
      0%   { box-shadow: 0 0 0 3px rgba(255, 196, 0, .85), 0 0 18px rgba(255, 196, 0, .55); }
      100% { box-shadow: 0 0 0 3px rgba(255, 196, 0, 0), 0 0 18px rgba(255, 196, 0, 0); }
    }

    /* 中国红主题：历史对话记录文字使用白色 */
    html[data-theme="hongyun"] .ai-history-item,
    html[data-theme="hongyun"] .ai-history-item:hover,
    html[data-theme="hongyun"] .ai-history-item.active {
      color: #ffffff;
    }
    /* 中国红主题：用户发问气泡文字使用五角星黄色（#f5b400） */
    html[data-theme="hongyun"] .ai-message-outgoing .ai-message-bubble,
    html[data-theme="hongyun"] .ai-float-messages .ai-message-outgoing .ai-message-bubble {
      color: #f5b400;
    }

    /* 中列：对�?*/
    .ai-chat-card {
      padding: 18px;
      position: relative;
    }
    /* 2026-09-06 用户：去掉主页对话页面中间主对话框的底层卡片容器（背景/边框透明化） */
    #智慧管理 .ai-center-col .ai-chat-card {
      background: transparent;
      border: none;
    }
    /* ══ 智慧管理 顶部二级导航行（2026-09-06 用户定稿 B）══
       三个按钮(☰/开放问答/智慧零度)为 .ai-stage 上方的独立整行（列在其下方），
       与聊天对话框无关；样式同结算定审 .stl-group-tab。
       - 行贴内容区顶（按钮顶 = 内容区顶，实测 rect ÷ zoom ≈ 18px）；
       - 展开(左侧可见)时，JS(updateAiToolbarDodge) 写入 padding-left 让开左侧可见列宽，
         按钮起点 = 最右侧可见列的右缘 + 一个列距；左侧隐藏时 padding-left 归 0，回整行最左。 */
    .ai-chat-toolbar {
      display: flex;
      align-items: center;
      gap: 8px;
      flex-shrink: 0;
      width: 100%;
      max-width: 1720px;          /* 与 .ai-stage 同宽封顶 */
      box-sizing: border-box;     /* padding-left 内缩，不把行撑出右侧 */
      margin: 0 0 16px;           /* 顶 0：贴内容区顶；下留 16px 与三列隔开 */
      transition: padding-left .25s ease; /* 与左侧列收展宽度过渡同步 */
    }
    .ai-chat-toolbar-btn {
      display: inline-flex;
      align-items: center;
      justify-content: center;
      gap: 6px;
      padding: 0 16px;
      border-radius: 12px;
      border: 1px solid var(--line);
      background: var(--panel);
      color: var(--text);
      font-size: 17px;
      font-weight: 600;
      height: 41px;          /* 固定高度：基础态/选中态一致(41px)，杜绝切换重排抖动 */
      line-height: 1;        /* 行高=字号，配合 align-items:center 精确垂直居中 */
      cursor: pointer;
      transition: background .2s, color .2s, border-color .2s, box-shadow .2s;
      user-select: none;
    }
    .ai-chat-toolbar-btn:hover {
      background: var(--primary-soft);
      border-color: var(--primary);
      color: var(--text);
    }
    .ai-mode-toggle {
      display: flex;
      align-items: center;
      gap: 6px;
    }
    /* 开放问答被"全员设置"关闭 → 开放问答按钮/API 设置页签对所有人（含系统管理员）隐藏（2026-09-10） */
    html.ldg-ai-general-off .ai-mode-btn[data-mode="general"],
    html.ldg-ai-general-off .ai-api-tab[data-mode="general"] {
      display: none !important;
    }
    .ai-mode-btn {
      border: 1px solid var(--line);
      background: var(--panel);
      color: var(--text);
      font-size: 12px;
      font-weight: 600;
      padding: 5px 14px;
      border-radius: 12px;
      cursor: pointer;
      transition: .2s;
      white-space: nowrap;
      outline: none;
    }
    .ai-mode-btn:hover {
      background: var(--primary-soft);
      color: var(--text);
    }
    .ai-mode-btn.active {
      background: color-mix(in srgb, var(--primary) 18%, transparent);
      color: var(--primary);
      border-color: var(--primary);
      box-shadow: 0 4px 12px color-mix(in srgb, var(--primary) 30%, transparent);
    }
    .ai-mode-toggle-float .ai-mode-btn {
      font-size: 11px;
      padding: 3px 8px;
      border-radius: 8px;
    }
    /* 2026-09-06：智慧管理 页面级二级导航「开放问答/智慧零度」模式切换按钮
       （样式同结算定审 .stl-group-tab / 全站统一标准 .project-group-tab）：
       高度41px/17px/600、边框+panel底、圆角12px、line-height:1、user-select:none。
       选中态沿用 .ai-mode-btn.active（文字不放大——Bug #3 定稿"选中不要放大"）。 */
    #aiModeToggleMain .ai-mode-btn {
      display: inline-flex;
      align-items: center;
      gap: 6px;
      height: 41px;
      font-size: 17px;
      font-weight: 600;
      line-height: 1;
      padding: 0 16px;
      user-select: none;
    }
    .ai-api-tab {
      flex: 1;
      border: 1px solid var(--line);
      background: var(--panel);
      color: var(--muted);
      font-size: 13px;
      padding: 7px 0;
      border-radius: 8px;
      cursor: pointer;
      transition: color .15s, background .15s, border-color .15s;
    }
    .ai-api-tab:hover {
      color: var(--text);
    }
    .ai-api-tab.active {
      background: var(--primary-soft);
      border-color: var(--primary);
      color: var(--primary);
      font-weight: 600;
    }
    .ai-chat-messages {
      flex: 1;
      overflow-y: auto;
      display: flex;
      flex-direction: column;
      gap: 14px;
      padding: 0 0 14px;
      min-height: 0;
    }
    .ai-message {
      display: flex;
      max-width: 80%;
      padding-bottom: 35px; /* 覆盖下方图标 hover 区域 */
    }
    .ai-message-incoming {
      align-self: flex-start;
      position: relative;
    }
    .ai-message-outgoing {
      align-self: flex-end;
      justify-content: flex-end;
    }
    .ai-message-bubble {
      position: relative;
      padding: 8px 16px;
      border-radius: 15px;
      font-size: 15px;
      line-height: 1.5;
      border: 1px solid var(--line);
      word-break: break-word;
    }
    .ai-message-incoming .ai-message-bubble {
      background: var(--panel-soft);
      color: var(--text);
      border-bottom-left-radius: 4px;
    }
    .ai-message-outgoing .ai-message-bubble {
      background: var(--primary-soft);
      color: var(--primary);
      border-color: var(--primary-soft);
      border-bottom-right-radius: 4px;
    }
    .ai-message-text { word-break: break-word; }
    .ai-message-version-control {
      display: inline-flex;
      align-items: center;
      gap: 2px;
      font-size: 14px;
      color: var(--muted);
      user-select: none;
      white-space: nowrap;
    }
    .ai-message-version-control button {
      width: 30px;
      height: 18px;
      border: none;
      border-radius: 4px;
      background: transparent;
      color: var(--muted);
      cursor: pointer;
      display: inline-flex;
      align-items: center;
      justify-content: center;
      font-size: 15px;
      line-height: 1;
      padding: 0;
    }
    .ai-message-version-control button:hover:not(:disabled) {
      background: var(--panel-soft);
      color: var(--text);
    }
    .ai-message-version-control button:disabled {
      opacity: 0.3;
      cursor: default;
    }

    .ai-message-user-actions,
    .ai-message-ai-actions {
      position: absolute;
      top: 100%;
      display: flex;
      align-items: center;
      gap: 4px;
      margin-top: 2px;
      opacity: 0;
      visibility: hidden;
      transition: opacity .25s ease, visibility .25s ease;
      pointer-events: none;
      z-index: 10;
    }
    .ai-message:hover .ai-message-user-actions,
    .ai-message:hover .ai-message-ai-actions,
    .ai-message-user-actions.ai-user-actions-visible {
      opacity: 1;
      visibility: visible;
      pointer-events: auto;
    }
    .ai-message-ai-actions { left: 8px; }
    .ai-message-user-actions { right: 8px; }
    .ai-msg-action {
      width: 30px;
      height: 30px;
      border-radius: 50%;
      border: none;
      background: transparent;
      color: var(--muted);
      cursor: pointer;
      display: inline-flex;
      align-items: center;
      justify-content: center;
      transition: background .15s, color .15s, transform .1s;
    }
    .ai-msg-action svg {
      display: block;
    }
    .ai-msg-action:hover {
      background: transparent;
      color: var(--text);
    }
    .ai-msg-action:active { transform: scale(.92); }
    .ai-message-edit { display: none; }
    .ai-message-edit-input {
      width: 100%;
      min-height: 60px;
      padding: 8px 10px;
      border-radius: 10px;
      border: 1px solid var(--primary);
      background: var(--panel);
      color: var(--text);
      font-size: 14px;
      line-height: 1.5;
      outline: none;
      box-sizing: border-box;
      resize: vertical;
      font-family: inherit;
    }
    .ai-message-bubble.editing {
      width: 600px;
      max-width: none;
    }
    .ai-message-bubble.editing .ai-message-edit-input {
      width: 100%;
      height: 135px;
      padding: 3px;
      min-height: auto;
      resize: none;
    }
    .ai-message-edit-btns {
      display: flex;
      justify-content: flex-end;
      gap: 8px;
      margin-top: 8px;
    }
    .ai-message-edit-btns button {
      padding: 5px 14px;
      border-radius: 8px;
      border: 1px solid var(--line);
      background: var(--panel);
      color: var(--text);
      font-size: 13px;
      cursor: pointer;
      transition: background .15s, box-shadow .15s;
    }
    .ai-message-edit-btns button:hover {
      background: var(--panel-soft);
      box-shadow: 0 0 10px var(--primary);
    }
    .ai-message-card {
      align-self: center;
      max-width: 90%;
      width: 90%;
      margin-top: auto;
    }
    .ai-message-card .ai-message-bubble {
      background: transparent;
      color: var(--text);
      border: 1px dashed var(--line);
      border-radius: 14px;
      text-align: center;
      width: 100%;
    }
    .ai-chat-input-area {
      flex-shrink: 0;
      padding-top: 12px;
    }
    .ai-chat-input-wrap {
      position: relative;
    }
    .ai-chat-input {
      width: 100%;
      height: 135px;      /* 2026-09-06 用户：主聊天输入框加高 30→15px（120→135） */
      padding: 12px 16px 56px 16px;
      border-radius: 14px;
      border: 1px solid var(--line);
      background: var(--panel);
      color: var(--text);
      font-size: 15px;
      line-height: 1.5;
      outline: none;
      box-sizing: border-box;
      resize: none;
      transition: border-color .15s, box-shadow .15s;
    }
    .ai-chat-input:focus {
      border-color: var(--primary);
      box-shadow: 0 0 0 3px var(--primary-soft);
    }
    .ai-chat-input::placeholder {
      color: var(--muted);
    }
    /* 标准竖向滚动条组件样式已独立到 static/css/ldg-vscroll.css（配套 ldg-vscroll.js）；
       此处仅隐藏 AI 对话/输入/消息区原生滚动条，由 .ldg-vscroll 接管（2026-08-25）。 */
    .ai-chat-messages,
    .ai-chat-input,
    .ai-float-input,
    .ai-float-messages {
      scrollbar-width: none;
    }
    .ai-chat-messages::-webkit-scrollbar,
    .ai-chat-input::-webkit-scrollbar,
    .ai-float-input::-webkit-scrollbar,
    .ai-float-messages::-webkit-scrollbar {
      width: 0; height: 0; display: none;
    }
    /* ══ 中间聊天对话固定竖向滚动条（2026-09-06 用户：参照施工预算量 .cb-vscroll）══
       position:fixed 钉在页面最右缘（视口 right:6px，main 右留白内），挂 body 下不参与布局；
       轨道本体由标准组件 ldgAttachVScroll(mode:'fixed', prefix:'ai-chat') 创建，JS 侧只剩
       「视图切换 / 默认隐藏 / 仅智慧管理视图激活时显示」的判断。
       2026-09-20 收编后类名：显示类 ai-chat-show、拖动类 body.ai-chat-vscroll-dragging，
       无溢出改由 ldg-vscroll.css 的 [data-ldg-empty] 通用规则处理。 */
    .ai-chat-vscroll {
      position: fixed;
      right: 6px;
      width: 11px;
      border-radius: 6px;
      background: transparent;
      z-index: 200;
      opacity: 0;
      transition: opacity .18s ease;
      cursor: pointer;
    }
    .ai-chat-vscroll.ai-chat-show {
      opacity: 1;
    }
    .ai-chat-vscroll-thumb {
      position: absolute;
      left: 0;
      width: 12px;
      border-radius: 6px;
      background: color-mix(in srgb, var(--text) 45%, transparent);
      cursor: grab;
    }
    body.ai-chat-vscroll-dragging,
    body.ai-chat-vscroll-dragging .ai-chat-vscroll-thumb {
      cursor: grabbing;
      user-select: none;
      -webkit-user-select: none;
    }
    /* 手机/平板聚焦输入框时浏览器不会自动缩放页面的关键：字号不得小于 16px。
       2026-09-17 用户："我们图标 输入并搜索 文字 26px 很大了，为什么到平板手机上 比图标名字还小" ——
       根因就是这条兜底**把桌面「网络搜索」框也一并压成 16px**（26→16，比图标名 18 还小）。
       该框是**桌面元素**、本身就是大字号（26px > 16px，同样满足"聚焦不缩放"的前提）→ 用 :not 排除，
       让它保留自己 CSS 里的 26px。以后新增"桌面上的大字号输入框"照此加入排除。 */
    /* ld-device-mobile/tablet 由 lingdu.html 内联脚本按 LDDevice 判定后加到 <html>（2026-08-21） */
    html.ld-device-mobile,
    html.ld-device-tablet {
      touch-action: manipulation;   /* 禁双击缩放，正常滚动/双指捏合不受影响 */
    }
    html.ld-device-mobile input:not(.sm-desk-websearch-inp),
    html.ld-device-mobile textarea,
    html.ld-device-mobile select,
    html.ld-device-tablet input:not(.sm-desk-websearch-inp),
    html.ld-device-tablet textarea,
    html.ld-device-tablet select {
      font-size: 16px !important;
    }
    .ai-chat-actions {
      position: absolute;
      /* 2026-09-20：右侧发送/麦克风圆钮让位 —— 竖向滚动条宽度统一为 11px（right:2px，左缘到 13px），
         原来是 8px（左缘 10px）刚好相切，加宽后会压到按钮，故 10→13px */
      right: 13px;
      bottom: 10px;
      z-index: 2;
      display: flex;
      align-items: center;
      gap: 15px;   /* 2026-09-06 用户：输入框右下图标间距 6→15 */
    }
    .ai-new-chat-bottom-btn {
      position: absolute;
      left: 10px;
      bottom: 10px;
      z-index: 2;
      width: 32px;
      height: 32px;
      border-radius: 50%;
      border: 1px solid var(--line);
      background: var(--panel);
      color: var(--text);
      font-size: 20px;
      line-height: 1;
      cursor: pointer;
      display: flex;
      align-items: center;
      justify-content: center;
      padding: 0;
      transition: background 0.15s;
    }
    .ai-new-chat-bottom-btn:hover { background: var(--primary); color: #fff; border-color: var(--primary); }
    .ai-send-btn {
      width: 34px;
      height: 34px;
      border-radius: 50%;
      border: none;
      background: linear-gradient(135deg, var(--primary), var(--accent-2));
      color: #fff;
      font-size: 15px;
      cursor: pointer;
      display: inline-flex;
      align-items: center;
      justify-content: center;
      transition: transform .15s, filter .15s;
      box-shadow: 0 3px 10px rgba(0,0,0,.18);
    }
    .ai-send-btn:hover {
      transform: scale(1.08);
      filter: brightness(1.1);
    }
    .ai-send-btn:active { transform: scale(.95); }
    .ai-mic-btn {
      width: 34px;
      height: 34px;
      border-radius: 50%;
      border: 1px solid transparent;
      background: rgba(128,128,128,.12);
      color: var(--text);
      font-size: 15px;
      cursor: pointer;
      display: inline-flex;
      align-items: center;
      justify-content: center;
      transition: color .15s, background .15s, transform .15s, border-color .15s;
    }
    .ai-mic-btn:hover {
      background: var(--panel-soft);
      border-color: var(--line);
      transform: scale(1.08);
    }
    .ai-mic-btn:active { transform: scale(.95); }
    .ai-mic-btn.recording {
      background: var(--red);
      color: #fff;
      animation: aiMicPulse 1.2s infinite;
    }
    @keyframes aiMicPulse {
      0% { box-shadow: 0 0 0 0 rgba(var(--red-rgb, 239,68,68), .4); }
      70% { box-shadow: 0 0 0 10px rgba(var(--red-rgb, 239,68,68), 0); }
      100% { box-shadow: 0 0 0 0 rgba(var(--red-rgb, 239,68,68), 0); }
    }
    /* ── AI 图片上传按钮 ── */
    .ai-img-btn {
      width: 34px;
      height: 34px;
      border-radius: 50%;
      border: 1px solid transparent;
      background: rgba(128,128,128,.12);
      color: var(--text);
      font-size: 15px;
      cursor: pointer;
      display: inline-flex;
      align-items: center;
      justify-content: center;
      transition: color .15s, background .15s, transform .15s, border-color .15s;
    }
    .ai-img-btn:hover {
      background: var(--panel-soft);
      border-color: var(--line);
      transform: scale(1.08);
    }
    /* 附件回形针图标：矢量 SVG 高清，横向拉伸加宽（16px × 1.3 ≈ 21px 视觉宽，2026-08-12） */
    .ai-img-btn .ai-clip { display: inline-flex; align-items: center; justify-content: center; }
    .ai-img-btn .ai-clip svg { display: block; transform: scaleX(1.3); }
    .ai-img-btn:active { transform: scale(.95); }
    .ai-img-btn:disabled { opacity: .35; cursor: not-allowed; transform: none; }
    /* ── AI 图片预览（发送前）── */
    .ai-img-preview {
      display: none;
      flex-wrap: wrap;
      gap: 8px;
      padding: 6px 4px 2px 4px;
    }
    .ai-img-preview.has-imgs { display: flex; }
    .ai-img-preview-item {
      position: relative;
      width: 52px;
      height: 52px;
      border-radius: 8px;
      border: 1px solid var(--line);
      overflow: hidden;
    }
    .ai-img-preview-item img {
      width: 100%;
      height: 100%;
      object-fit: cover;
      display: block;
    }
    .ai-img-preview-item .ai-img-preview-del {
      position: absolute;
      top: 2px;
      right: 2px;
      width: 16px;
      height: 16px;
      border-radius: 50%;
      border: none;
      background: rgba(0,0,0,.55);
      color: #fff;
      font-size: 10px;
      line-height: 1;
      cursor: pointer;
      display: flex;
      align-items: center;
      justify-content: center;
      padding: 0;
    }
    /* ── 聊天消息内图片 ── */
    .ai-message-imgs { display: flex; flex-wrap: wrap; gap: 6px; }
    .ai-msg-img {
      max-width: 180px;
      max-height: 160px;
      border-radius: 8px;
      margin-top: 6px;
      cursor: zoom-in;
      display: block;
      border: 1px solid var(--line);
    }
    /* ── 图片放大查看 ── */
    .ai-img-lightbox {
      position: fixed;
      inset: 0;
      z-index: 99999;
      background: rgba(0,0,0,.75);
      display: flex;
      align-items: center;
      justify-content: center;
      cursor: zoom-out;
    }
    .ai-img-lightbox img {
      max-width: 90vw;
      max-height: 90vh;
      border-radius: 8px;
    }
    .ai-message-incoming .ai-speak-btn {
      position: absolute;
      top: -13px;
      left: 9px;
      float: none;
      margin: 0;
      z-index: 1;
      background: transparent;
      border-radius: 50%;
      padding: 0;
    }
    .ai-speak-btn {
      background: transparent;
      border: none;
      border-radius: 6px;
      cursor: pointer;
      opacity: 1;
      transition: opacity .15s;
    }
    .ai-speak-btn:hover {
      opacity: .85;
    }
    .ai-speak-btn:hover .ai-speak-avatar {
      width: 25px;
      height: 25px;
    }
    .ai-speak-btn.speaking {
      opacity: 1;
      /* 第三圈波纹 */
      box-shadow: 0 0 0 0 rgba(239,68,68,.36);
      animation: ai-speak-ripple-3 2.4s ease-out infinite;
    }
    .ai-speak-avatar.ai-cloud-avatar {
      display: block;
      width: 20px;
      height: 20px;
      background: linear-gradient(180deg, #3b7dd8 0%, #5a9ee8 45%, #8ec5fc 100%);
      box-shadow: inset 0 -2px 5px rgba(255,255,255,.35), inset 0 2px 4px rgba(255,255,255,.5), 0 2px 6px rgba(14,165,233,.35);
      animation: none;
      transition: width .15s, height .15s;
    }
    .ai-speak-btn.speaking .ai-speak-avatar {
      animation: aiCloudBreathe .8s ease-in-out infinite;
    }
    .ai-speak-btn.speaking::before,
    .ai-speak-btn.speaking::after {
      content: '';
      position: absolute;
      border-radius: 50%;
      pointer-events: none;
      border: 1.5px solid rgba(239,68,68,.72);
      animation: ai-speak-ripple 2.4s ease-out infinite;
    }
    .ai-speak-btn.speaking::before {
      inset: -8px;
      animation-delay: 0s;
    }
    .ai-speak-btn.speaking::after {
      inset: -8px;
      animation-delay: .8s;
      border-color: rgba(239,68,68,.48);
    }
    /* 本地合成（speechSynthesis）通道：水波纹用蓝色，区分 edge-tts 的红色 */
    .ai-speak-btn.speaking.speaking-synth {
      box-shadow: 0 0 0 0 rgba(59,130,246,.36);
      animation: ai-speak-ripple-3-blue 2.4s ease-out infinite;
    }
    .ai-speak-btn.speaking.speaking-synth::before,
    .ai-speak-btn.speaking.speaking-synth::after {
      border-color: rgba(59,130,246,.72);
    }
    .ai-speak-btn.speaking.speaking-synth::after {
      border-color: rgba(59,130,246,.48);
    }

    /* （原「右列：待办事项」那块样式 .ai-todo-card / .ai-todo-list / .ai-todo-item / .ai-todo-text
       已随聊天页右列一起删除，2026-09-21 用户："待办事项、记事本不要了"。） */

    /* ── 悬浮 AI 助手 ── */
    .ai-float {
      position: fixed;
      right: 22px;
      bottom: 22px;
      z-index: 1000;
      display: flex;
      flex-direction: column;
      align-items: flex-end;
      gap: 12px;
      pointer-events: none;
    }
    .ai-float > * { pointer-events: auto; }
    .ai-float-avatar {
      position: relative;
      width: 52px;
      height: 52px;
      left: auto;
      top: 7px;
      border-radius: 50%;
      border: none;
      outline: none;               /* 去掉聚焦时浏览器默认黑边（如按 ESC 后） */
      background: linear-gradient(135deg, #3b82f6, #0ea5e9);
      color: #fff;
      font-size: 28px;
      display: flex;
      align-items: center;
      justify-content: center;
      cursor: pointer;
      box-shadow: 0 8px 28px rgba(0,0,0,.22), 0 0 18px rgba(59,130,246,.28);
      transition: transform .2s ease, box-shadow .2s ease;
    }
    .ai-float-avatar:hover {
      transform: scale(1.08);
      box-shadow: 0 10px 32px rgba(0,0,0,.26), 0 0 24px rgba(59,130,246,.28);
    }
    .ai-float-avatar:active { transform: scale(.95); }
    .ai-float-avatar.recording {
      /* 语音监听中：背景保持默认蓝色渐变不变色；改用下方 .ai-float-avatar-ring 规则让水波纹变红 */
    }
    /* 助手形象说话状态：水波纹随 TTS 通道变色（edge-tts 红 / 本地合成蓝），2.4s→1.85s 提速30% */
    .ai-float-avatar.speaking {
      animation: aiFloatSpeaking 1.85s ease-out infinite;
    }
    .ai-float-avatar.speaking.speaking-synth {
      animation: aiFloatSpeakingBlue 1.85s ease-out infinite;
    }
    @keyframes aiFloatSpeaking {
      0% { box-shadow: 0 0 0 0 rgba(239,68,68,.42), 0 8px 28px rgba(0,0,0,.22); }
      100% { box-shadow: 0 0 0 18px rgba(239,68,68,0), 0 8px 28px rgba(0,0,0,.22); }
    }
    @keyframes aiFloatSpeakingBlue {
      0% { box-shadow: 0 0 0 0 rgba(59,130,246,.42), 0 8px 28px rgba(0,0,0,.22); }
      100% { box-shadow: 0 0 0 18px rgba(59,130,246,0), 0 8px 28px rgba(0,0,0,.22); }
    }
    .ai-cloud-avatar {
      position: relative;
      width: 46px;
      height: 46px;
      border-radius: 50%;
      overflow: hidden;
      background: linear-gradient(180deg, #3b7dd8 0%, #5a9ee8 45%, #8ec5fc 100%);
      box-shadow: inset 0 -6px 12px rgba(255,255,255,.4), inset 0 4px 10px rgba(255,255,255,.6), 0 4px 14px rgba(14,165,233,.35);
      animation: aiCloudBreathe 3.2s ease-in-out infinite;
    }
    #aiFloatAvatarCloud {
      width: 40px;
      height: 40px;
      border-radius: 50px;
      left: auto;
      top: auto;
      display: grid;
      flex-direction: column;
    }
    .ai-cloud-avatar-small { width: 26px; height: 26px; }
    .ai-cloud-layer {
      position: absolute;
      left: -20%;
      right: -20%;
      bottom: -15%;
      height: 78%;
      animation: aiCloudDrift 5s ease-in-out infinite;
      pointer-events: none;
    }
    .ai-cloud-puff {
      position: absolute;
      background: rgba(255,255,255,.90);
      filter: blur(2px);
      transition: opacity .8s ease, transform .8s ease;
      transform-origin: center bottom;
    }
    .ai-cloud-puff.front {
      background: rgba(255,255,255,.98);
      filter: blur(1.5px);
      z-index: 2;
    }
    .ai-cloud-puff.back {
      background: rgba(255,255,255,.62);
      filter: blur(3.5px);
      z-index: 0;
    }
    .ai-cloud-ring {
      position: absolute;
      inset: -8px;
      border-radius: 50%;
      border: 2px solid rgba(14,165,233,.25);
      opacity: 0;
      animation: aiCloudRing 3.2s ease-out infinite;
      pointer-events: none;
    }
    @keyframes aiCloudBreathe {
      0%, 100% { transform: scale(1); }
      50% { transform: scale(var(--ai-breathe-scale, 1.04)); }
    }
    @keyframes aiCloudDrift {
      0%, 100% { transform: translateX(-3px) translateY(0); }
      33% { transform: translateX(1px) translateY(-1.5px); }
      66% { transform: translateX(3px) translateY(1px); }
    }
    @keyframes aiCloudRing {
      0% { transform: scale(.9); opacity: .45; }
      100% { transform: scale(1.35); opacity: 0; }
    }
    .ai-float-avatar.recording .ai-cloud-avatar {
      animation: aiCloudBreathe .8s ease-in-out infinite;
      box-shadow: 0 8px 28px rgba(0,0,0,.22);                  /* 去掉内层 var(--red) 深红环，避免和外层淡红叠成两层 */
    }
    .ai-float-avatar.recording .ai-cloud-puff {
      background: rgba(255,255,255,.96);
    }
    .ai-float-avatar.recording .ai-cloud-puff.back {
      background: rgba(255,255,255,.75);
    }
    .ai-float-avatar-ring {
      position: absolute;
      inset: -4px;
      border-radius: 50%;
      border: 2px solid #3b82f6;
      opacity: .6;
      animation: ai-float-pulse 2s ease-out infinite;
      pointer-events: none;
    }
    .ai-float-avatar.recording .ai-float-avatar-ring {
      border-color: color-mix(in srgb, #ef4444 70%, #000);       /* 语音监听中：背景不变色，水波纹环变红（加深30%） */
      opacity: .8;
    }
    @keyframes ai-float-pulse {
      0% { transform: scale(1); opacity: .6; }
      100% { transform: scale(1.35); opacity: 0; }
    }
    @keyframes ai-speak-ripple {
      0% { transform: scale(.7); opacity: .96; }
      100% { transform: scale(2.1); opacity: 0; }
    }
    @keyframes ai-speak-ripple-3 {
      0% { box-shadow: 0 0 0 0 rgba(239,68,68,.42); }
      100% { box-shadow: 0 0 0 18px rgba(239,68,68,0); }
    }
    /* 本地合成通道的第三圈波纹动画：蓝色（默认红色由 ai-speak-ripple-3 提供） */
    @keyframes ai-speak-ripple-3-blue {
      0% { box-shadow: 0 0 0 0 rgba(59,130,246,.42); }
      100% { box-shadow: 0 0 0 18px rgba(59,130,246,0); }
    }
    .ai-listening-label {
      position: absolute;
      right: calc(100% + 10px);
      top: 50%;
      transform: translateY(-50%);
      white-space: nowrap;
      padding: 0;
      border-radius: 0;
      background: transparent;
      border: none;
      color: var(--text);
      font-size: 13px;
      font-weight: 500;
      opacity: 0;
      pointer-events: none;
      transition: opacity .35s ease, transform .35s ease;
      will-change: opacity, transform;
    }
    .ai-listening-label.show {
      opacity: 1;
      animation: ai-listening-breath 2s ease-in-out infinite;
    }
    @keyframes ai-listening-breath {
      0%, 100% { transform: translateY(-50%) scale(1); }
      50% { transform: translateY(-50%) scale(1.03); }
    }
    .ai-float-avatar.recording .ai-listening-label { color: var(--red); }
    /* ── 零度助手头像右键菜单 ── */
    .ai-avatar-context-menu {
      position: fixed; z-index: 10003; min-width: 180px;
      background: var(--panel); border: 1px solid var(--sidebar-border);
      border-radius: clamp(7px, 0.39vw, 10px); box-shadow: 0 8px 24px rgba(0,0,0,.4);
      padding: clamp(3px, 0.16vw, 4px); overflow: hidden;
    }
    .ai-avatar-context-menu .ai-ctx-item {
      padding: clamp(6px, 0.35vw, 9px) clamp(12px, 0.7vw, 16px);
      /* 右键菜单字号全站统一 16px（原 clamp(12px, .6vw, 14px)，见 .fb-ctx-item 那条） */
      font-size: 16px; color: var(--text);
      cursor: pointer; border-radius: clamp(4px, 0.23vw, 6px);
      white-space: nowrap; transition: background .1s;
      display: flex; align-items: center; gap: 8px;
    }
    .ai-avatar-context-menu .ai-ctx-item:hover { background: var(--sidebar-hover); color: var(--primary); }
    /* 行内小角标（如"（当前）"）：右键菜单字号统一 16px 之后这里也跟到 16（原 11px —— 用户要"菜单里文字全 16"） */
    .ai-avatar-context-menu .ai-ctx-item .ctx-hint {
      margin-left: auto; font-size: 16px; color: var(--muted);
    }
    .ai-avatar-submenu {
      min-width: 150px;
      z-index: 10004;
    }
    .ai-avatar-submenu .ai-ctx-input-wrap {
      padding: 6px 12px;
      display: flex;
      align-items: center;
      gap: 6px;
    }
    .ai-avatar-submenu .ai-ctx-input-wrap input {
      width: 80px;
      padding: 5px 8px;
      border: 1px solid var(--line);
      border-radius: 6px;
      background: var(--input-bg, var(--panel-soft));
      color: var(--text);
      font-size: 13px;
      outline: none;
    }
    .ai-avatar-submenu .ai-ctx-input-wrap input:focus {
      border-color: var(--primary);
    }
    .ai-avatar-submenu .ai-ctx-input-wrap span {
      font-size: 13px;
      color: var(--text);
    }
    .ai-avatar-submenu .ai-ctx-btns {
      padding: 6px 12px 10px;
      display: flex;
      gap: 8px;
    }
    .ai-avatar-submenu .ai-ctx-btns button {
      flex: 1;
      padding: 5px 10px;
      border: 1px solid var(--line);
      border-radius: 6px;
      background: var(--panel-soft);
      color: var(--text);
      font-size: 12px;
      cursor: pointer;
      transition: background .15s, border-color .15s;
    }
    .ai-avatar-submenu .ai-ctx-btns button:hover {
      background: var(--sidebar-hover);
    }
    .ai-avatar-submenu .ai-ctx-btns button.primary {
      background: var(--primary);
      border-color: var(--primary);
      color: #fff;
    }
    .ai-avatar-submenu .ai-ctx-btns button.primary:hover {
      background: var(--primary-dark, var(--primary));
      opacity: .9;
    }
    .ai-float-panel {
      position: fixed;
      right: 22px;
      bottom: 94px;
      width: 380px;
      height: 620px;
      /* vw/vh 按被浏览器缩放后的视觉视口解析，面板跟随档位缩放（无反向补偿，2026-08-14），
         须 ÷--ld-gear（档位）把"视觉 100vw/100vh"换算回布局坐标（视觉 = 布局 × 档位） */
      max-width: calc(100vw / var(--ld-gear, 1) - 44px);
      max-height: calc(100vh / var(--ld-gear, 1) - 120px);
      border-radius: 18px;
      border: 1px solid var(--line);
      background: var(--panel);
      box-shadow: 0 16px 50px rgba(0,0,0,.28);
      display: none;
      flex-direction: column;
      overflow: hidden;
      transform-origin: bottom right;
      animation: ai-float-panel-in .2s ease;
    }
    .ai-float.open .ai-float-panel { display: flex; }
    @keyframes ai-float-panel-in {
      from { opacity: 0; transform: scale(.92); }
      to { opacity: 1; transform: scale(1); }
    }
    .ai-float-header {
      flex-shrink: 0;
      display: flex;
      align-items: center;
      justify-content: space-between;
      gap: 10px;
      padding: 12px 14px;
      border-bottom: 1px solid var(--line);
      background: var(--card-gradient);
      cursor: grab;
      user-select: none;
    }
    .ai-float-header:active { cursor: grabbing; }
    .ai-float-title {
      display: flex;
      align-items: center;
      gap: 8px;
      font-size: 15px;
      font-weight: 700;
      color: var(--text);
    }
    .ai-float-actions {
      display: flex;
      align-items: center;
      gap: 6px;
    }
    .ai-float-action-btn {
      width: 28px;
      height: 28px;
      border-radius: 8px;
      border: none;
      background: transparent;
      color: var(--muted);
      font-size: 18px;
      line-height: 1;
      cursor: pointer;
      display: inline-flex;
      align-items: center;
      justify-content: center;
      transition: color .15s, background .15s;
    }
    .ai-float-action-btn:hover { color: var(--text); background: var(--primary-soft); }
    .ai-float-messages {
      flex: 1;
      min-height: 0;
      overflow-y: auto;
      display: flex;
      flex-direction: column;
      gap: 12px;
      padding: 14px;
    }
    .ai-float-messages .ai-message { max-width: 86%; }
    .ai-float-messages .ai-message-bubble {
      padding: 9px 13px;
      font-size: 13px;
      border-radius: 12px;
    }
    .ai-float-messages .ai-message-incoming .ai-message-bubble {
      background: var(--panel-soft);
      color: var(--text);
      border-bottom-left-radius: 3px;
    }
    .ai-float-messages .ai-message-outgoing .ai-message-bubble {
      background: var(--primary-soft);
      color: var(--primary);
      border-color: var(--primary-soft);
      border-bottom-right-radius: 3px;
    }
    .ai-float-messages .ai-msg-action {
      width: 26px;
      height: 26px;
      font-size: 11px;
    }
    .ai-float-messages .ai-message-version-control {
      font-size: 10px;
      top: 4px;
      right: 6px;
    }
    .ai-float-messages .ai-message-version-control button {
      width: 16px;
      height: 16px;
      font-size: 12px;
    }

    /* ── 指令训练：过滤按钮 ── */
    .training-filter-group {
      display: inline-flex;
      align-items: center;
      gap: 4px;
      margin-left: 16px;
    }
    .training-filter-btn {
      padding: 3px 12px;
      font-size: 13px;
      font-weight: 400;
      border: 1px solid var(--line);
      border-radius: 14px;
      background: transparent;
      color: var(--muted);
      cursor: pointer;
      transition: all .15s;
    }
    .training-filter-btn:hover {
      border-color: var(--primary);
      color: var(--primary);
    }
    .training-filter-active {
      background: color-mix(in srgb, var(--primary) 18%, transparent);
      color: var(--primary);
      border-color: var(--primary);
    }
    .training-filter-active:hover {
      background: color-mix(in srgb, var(--primary) 18%, transparent);
      color: var(--primary);
    }

    /* ── 指令训练：行选中 ── */
    .training-row {
      cursor: pointer;
      transition: background .12s, box-shadow .12s;
    }
    .training-row:hover {
      background: var(--primary-soft, #e8f0fe);
    }
    .training-row-selected {
      background: var(--primary-soft, #e8f0fe) !important;
      box-shadow: inset 3px 0 0 var(--primary);
    }

    /* ── 指令训练：框选框 ── */
    .training-box-select {
      position: fixed;
      z-index: 9999;
      pointer-events: none;
      border: 1px dashed var(--primary);
      background: rgba(59, 130, 246, 0.08);
    }

    /* ── 历史记录：选中状态（原"待办事项"那份选中/完成样式已随该功能删除，2026-09-21） ── */
    .ai-history-item.ai-history-selected {
      background: var(--primary-soft, #e8f0fe);
      box-shadow: inset 3px 0 0 var(--primary);
    }
    .ai-float-messages .ai-message-version-control {
      font-size: 13px;
    }
    .ai-float-messages .ai-message-version-control button {
      width: 26px;
      height: 16px;
      font-size: 14px;
    }
    .ai-float-messages .ai-message-edit-input {
      min-height: 48px;
      font-size: 13px;
    }
    .ai-float-messages .ai-message-edit-btns button {
      padding: 4px 10px;
      font-size: 12px;
    }
    .ai-float-input-area {
      flex-shrink: 0;
      padding: 10px 12px 12px;
      background: var(--panel);
    }
    .ai-float-input-wrap {
      position: relative;
    }
    .ai-float-input {
      width: 100%;
      height: 110px;
      padding: 10px 12px 56px 12px;
      border-radius: 14px;
      border: 1px solid var(--line);
      background: var(--panel-soft);
      color: var(--text);
      font-size: 15px;
      line-height: 1.45;
      outline: none;
      box-sizing: border-box;
      resize: none;
      transition: border-color .15s, box-shadow .15s;
    }
    .ai-float-input:focus { border-color: var(--primary); box-shadow: 0 0 0 3px var(--primary-soft); }
    .ai-float-new-chat-btn {
      position: absolute;
      left: 8px;
      bottom: 8px;
      z-index: 2;
      width: 30px;
      height: 30px;
      border-radius: 50%;
      border: 1px solid var(--line);
      background: var(--panel);
      color: var(--text);
      font-size: 18px;
      line-height: 1;
      cursor: pointer;
      display: flex;
      align-items: center;
      justify-content: center;
      padding: 0;
      transition: background 0.15s;
    }
    .ai-float-new-chat-btn:hover { background: var(--primary); color: #fff; border-color: var(--primary); }
    .ai-float-actions {
      position: absolute;
      /* 2026-09-20：同上，竖向滚动条统一 11px 后让位（8→11px） */
      right: 11px;
      bottom: 8px;
      z-index: 2;
      display: flex;
      align-items: center;
      gap: 5px;
    }
    .ai-float-send {
      width: 32px;
      height: 32px;
      border-radius: 50%;
      border: none;
      background: linear-gradient(135deg, var(--primary), var(--accent-2));
      color: #fff;
      font-size: 14px;
      cursor: pointer;
      display: inline-flex;
      align-items: center;
      justify-content: center;
      transition: transform .15s, filter .15s;
      box-shadow: 0 3px 10px rgba(0,0,0,.18);
    }
    .ai-float-send:hover { transform: scale(1.08); filter: brightness(1.1); }
    .ai-float-send:active { transform: scale(.95); }
    .ai-float-mic {
      width: 32px;
      height: 32px;
      border-radius: 50%;
      border: 1px solid transparent;
      background: rgba(128,128,128,.12);
      color: var(--text);
      font-size: 14px;
      cursor: pointer;
      display: inline-flex;
      align-items: center;
      justify-content: center;
      transition: color .15s, background .15s, transform .15s, border-color .15s;
    }
    .ai-float-mic:hover { background: var(--panel-soft); border-color: var(--line); transform: scale(1.08); }
    .ai-float-mic:active { transform: scale(.95); }
    .ai-float-mic.recording {
      background: var(--red);
      color: #fff;
      border-color: transparent;
      animation: aiMicPulse 1.2s infinite;
    }

    /* ── 语音字幕�?── */
    .ai-subtitle {
      position: fixed;
      left: 50%;
      bottom: 130px;
      transform: translateX(-50%);
      width: min(max(calc(60vw - 300px), 400px), calc(100vw - 40px));
      z-index: 9999;
      padding: 0;
      background: transparent;
      color: var(--theme-color);
      font-size: 22px;
      font-weight: bold;
      line-height: 32px;
      height: 32px;
      text-align: center;
      pointer-events: none;
      opacity: 0;
      transition: opacity .3s ease;
      white-space: nowrap;
      overflow: hidden;
      text-shadow: none;
      -webkit-font-smoothing: antialiased;
      -moz-osx-font-smoothing: grayscale;
    }
    .ai-subtitle.show {
      opacity: 1;
    }
    .ai-subtitle .sub-text {
      display: inline-block;
      white-space: nowrap;
      min-width: 100%;
      transition: transform 0.3s linear;
    }
    .ai-subtitle .sub-user {
      color: var(--muted);
      font-size: 20px;
    }
    .ai-subtitle .sub-ai {
      color: var(--theme-color);
      font-size: 22px;
    }
    .ai-subtitle .sub-text.scroll {
      /* JS 驱动 transform，让最新文字保持在可视区，不再用无限循环动画 */
      text-align: left;
    }
    .ai-subtitle .sub-label {
      display: none;
    }
    @media (max-width: 480px) {
      .ai-float { right: 14px; bottom: 14px; }
      .ai-float-panel { width: calc(100vw - 28px); height: 70vh; }
    }

    @media (max-width: 1180px) {
      .ai-stage {
        grid-template-columns: 1fr;
        grid-template-rows: auto 1fr;
        overflow-y: auto;
      }
      .ai-left-col,
      .ai-center-col {
        min-width: 0;
      }
      .ai-left-col {
        flex: 0 0 auto;
        max-height: 240px;
      }
      .ai-center-col {
        min-height: 420px;
      }
    }

    /* ── 聊天页「真窄屏」= 保持左右两列（2026-09-13 用户实测：手机/平板竖屏下聊天页被挤成一条缝；
       ⚠ 用户明确要求**保留左右结构**，不要上下堆叠）──
       现象：竖屏时输入框卡片只剩中间一点点宽、左右留白很大，左边历史对话被挤成 ~60px 一条。
       根因（当时是三列）：档位模式(html.ld-zoom-gear)把 .ai-stage 钉在设计稿三列，右列**固定
       520px**，在窄布局宽（~740px）下占去大半；JS 又按该口径给聊天列写宽度与居中位移 → 又窄又偏。
       为什么不能只靠上面那条 @media(max-width:1180px)：档位模式里 html zoom 会把"布局宽"放大，
       浏览器 300% 时 innerWidth 很小、布局仍是设计稿宽——那种情况**必须保持设计稿列宽**（见上方
       「档位模式（ld-zoom-gear）下媒体查询失效修正」）。
       故判据 = 媒体查询(≤1180)命中 且 .ai-stage 真实布局宽也 < 1180（ai-chat.js 的
       aiIsNarrowLayout()），此时：① 列宽由 JS 按**窄屏口径**写成像素轨道（走普通模式比例，
       不加"历史+80"）→ 两条轨道恰好铺满；② 本组规则只负责**抵消媒体查询的
       "单列堆叠"假设**（两行/限高/最小高/整卷滚动），让两列回到设计稿的"整列高、列内滚动"。
       2026-09-21 删掉原第2列（待办+记事本）后剩两列，本组规则照旧适用。
       ⚠ `html:not([data-ldp-recv-chat])`：接收演示时聊天页几何由演示端直传接管（下方那组 !important），
       本组整组让位，免得两套口径抢同一批属性。 */
    html:not([data-ldp-recv-chat]) #智慧管理 .ai-center.ai-narrow-layout .ai-stage {
      grid-template-rows: 1fr;   /* 抵消窄屏的 auto 1fr（两行=上下堆叠） */
      overflow-y: visible;       /* 抵消窄屏的 auto：两列整列高、各自列内滚动，不要整卷滚动条 */
    }
    html:not([data-ldp-recv-chat]) #智慧管理 .ai-center.ai-narrow-layout .ai-left-col {
      max-height: none;          /* 抵消窄屏给侧列的 240px 限高（两列要整列高，卡片贴到底） */
    }
    html:not([data-ldp-recv-chat]) #智慧管理 .ai-center.ai-narrow-layout .ai-center-col {
      min-height: 0;             /* 抵消窄屏给聊天列的 420px 最小高 */
    }

    /* ── 远程演示·接收端「聊天页几何以演示端为准」（2026-09-13 用户实测：平板竖屏宽度来回跳）──
       现象：接收端是**平板竖屏**时，聊天输入框与左边历史对话的**宽度一会儿宽一会儿窄地跳**（横屏正常）。
       根因：竖屏 innerWidth 变小 → 命中上面那条 `@media (max-width:1180px)`（`.ai-stage` 塌缩成单列 +
       `auto 1fr` 两行 + `overflow-y:auto`，侧列加 `max-height:240px`）；同时接收端本机 JS
       （`applyAiStageGrid()` 在窄屏**主动清空** inline grid、`updateAiChatCenter()` 继续按窄屏口径重算）
       与"照抄演示端算好的几何"**互相覆盖** → 列宽在"演示端 px"和"本机 1fr"之间来回，`overflow-y` 的
       滚动条也跟着出现/消失（滚动条占宽又让列宽再变一次）→ 看着就是跳。
       解法：演示端的值写入 `<html>` 的 `--ldp-cg-*` 变量（由 lingdu-present.js 写），这里用 **!important**
       钉死 —— **作者 !important 胜过本机写的普通 inline**，本机之后再怎么写都改变不了最终显示。
       `html[data-ldp-recv-chat]` 只在"接收演示且已收到演示端聊天页帧"时由 JS 挂上（用 data 属性而不是
       class：`<html>` 的 class 会被 DOM 镜像整体替换，data-* 不会被冲掉）。 */
    html[data-ldp-recv-chat] .ai-stage {
      grid-template-columns: var(--ldp-cg-g, none) !important;
      grid-template-rows: 1fr !important;   /* = 基础样式的值，抵消窄屏的 auto 1fr（否则只剩 auto 行高） */
      overflow-y: visible !important;        /* 抵消窄屏的 auto：滚动条忽现忽隐会让列宽反复变 */
    }
    html[data-ldp-recv-chat] .ai-center-col {
      width: var(--ldp-cg-w, auto) !important;
      transform: var(--ldp-cg-t, none) !important;
    }
    html[data-ldp-recv-chat] .ai-chat-toolbar {
      padding-left: var(--ldp-cg-p, 0px) !important;
    }
    html[data-ldp-recv-chat] .ai-left-col {
      max-height: none !important;           /* 抵消窄屏给侧列的 240px 限高 */
    }

    /* ── 侧边栏最终布局修复：导航区滚动 + 消息/设置固定底部可滚动 ── */
    @media (min-width: 761px) {
      .sidebar {
        display: flex !important;
        flex-direction: column !important;
        overflow: hidden !important;
      }
      .sidebar-main {
        flex: 1 1 auto !important;
        min-height: 0 !important;
        overflow-y: auto !important;
        overflow-x: hidden !important;
      }
      .sidebar-spacer {
        display: none !important;
      }
      .sidebar-bottom {
        flex: 0 0 auto !important;
        margin-top: auto !important;
        display: flex !important;
        flex-direction: column !important;
        gap: 10px !important;
      }
      .sidebar-footer {
        flex: 0 0 auto !important;
      }
      /* ★ 2026-10-10：折叠态**不再整块 display:none**（那会让左下角变空、系统设置点不出来）——
         见上方 `.sidebar-footer.collapsed` 那段说明；这里只隐藏"除标题外的项"。
         （同时删掉了本块里 `.sidebar-announce-wrapper` 的两条 —— 那块卡片已按用户要求撤掉。） */
      .sidebar-footer.collapsed > *:not(.sidebar-tool-title) {
        display: none !important;
      }
      .app.sidebar-icon .sidebar-bottom {
        overflow: visible !important;
        align-items: center !important;
      }
      .app.sidebar-icon .sidebar-footer {
        width: 100% !important;
      }
    }

    /* ═══ 高倍页面缩放兜底（2026-08-11，用户反馈"300%/400% 导航栏较宽、覆盖右边区域"）═══
       lingdu.css L2842 的 @media (max-width:860px)（移动端适配）会把侧边栏改成
       position:fixed + z-index:90 悬浮抽屉（宽 min(290px,86vw)），并让 .app 退化为单列。
       浏览器 Ctrl+滚轮放大到 300%+ 时（用户 2560 屏：300%→布局视口 852px、400%→639px，
       均 ≤860）命中该媒体查询 → 悬浮抽屉覆盖预算翻样等表格的冻结列，且宽度（290px）
       与正常侧边栏（--sidebar-width: 240px）不符。
       修复：浏览器模式下 ≤860 恢复正常 grid 布局——侧边栏始终作为普通列显示，
       宽度 = var(--sidebar-width)（240px，与 100% 一致），内容在其右侧、不再被覆盖。
       折叠/图标态（.app.sidebar-icon / .sidebar-hidden）随 --sidebar-width 同步生效，
       左侧竖条仍可循环切换 全显示/仅图标/全折叠。
       注意：L5919 `@media (min-width:761px) .sidebar { display:flex !important }` 在
       761–860 视口也会命中，本规则以更高特异度（0,3,1）覆盖之。 */
    @media (max-width: 860px) {
      html.ld-browser-mode .app,
      html.ld-browser-mode .app.sidebar-icon,
      html.ld-browser-mode .app.sidebar-hidden {
        grid-template-columns: var(--sidebar-width) minmax(0, 1fr);
        --sidebar-gap: 0px;
      }
      html.ld-browser-mode .app .sidebar {
        position: static;
        z-index: auto;
        left: auto;
        display: flex;
        flex-direction: column;
        width: var(--sidebar-width);
        min-width: 0;
        padding: 22px 12px 22px 0;
        opacity: 1;
        pointer-events: auto;
        transform: none;
      }
      html.ld-browser-mode .app.sidebar-hidden .sidebar {
        width: 0;
        padding-left: 0;
        padding-right: 0;
        opacity: 0;
        pointer-events: none;
      }
      /* 图标模式文字真隐藏：上方移动端媒体查询（L3061）会把 .app.sidebar-icon 文字恢复显示
         （opacity:1/width:auto），但在本"浏览器模式列布局"下侧边栏宽度 = var(--sidebar-width)=88px，
         文字完整渲染会溢出漏字（用户反馈"宽度刚好不合适就看到一点文字漏出来"）。
         此处用更高特异性（0,4,1）覆盖之，确保该场景图标模式文字仍隐藏 */
      html.ld-browser-mode .app.sidebar-icon .brand-text,
      html.ld-browser-mode .app.sidebar-icon .nav-label,
      html.ld-browser-mode .app.sidebar-icon .nav-title,
      html.ld-browser-mode .app.sidebar-icon .side-card,
      html.ld-browser-mode .app.sidebar-icon .sidebar-tool-title,
      html.ld-browser-mode .app.sidebar-icon .sidebar-tool-text {
        opacity: 0;
        width: 0;
        height: 0;
        margin: 0;
        padding: 0;
        overflow: hidden;
        pointer-events: none;
      }
      /* 图标模式布局恢复居中：上方移动端媒体查询（L3119/L3121）把 brand/nav 按钮改成
         flex-start 左对齐（为移动端抽屉 290px 布局设计），但在"浏览器模式列布局"下侧边栏
         仅 88px 宽，flex-start 会让图标贴左、不居中（用户反馈"文字去了之后，图标没居中到
         宽度内"）。此处用更高特异性恢复居中对齐 */
      html.ld-browser-mode .app.sidebar-icon .brand {
        justify-content: center;
        gap: 0;
        padding: 6px 0 13px;
      }
      html.ld-browser-mode .app.sidebar-icon .brand img,
      html.ld-browser-mode .app.sidebar-icon .brand svg {
        margin-left: 0;
      }
      html.ld-browser-mode .app.sidebar-icon .nav button {
        justify-content: center;
        gap: 0;
        padding: 13px 0;
        font-size: 16px;
      }
    }

    /* ═══ 触屏虚拟鼠标（手机/平板）═══════════════════════════════════
       入口开关在侧边栏"系统设置"面板（仅触屏显示）。
       z-index 200000：必须高于所有弹窗/蒙版——缩放比例弹窗 .ld-zoom-picker-overlay
       (99999)、图片放大 .ai-img-lightbox (99999)、上传进度 (99999)、远程演示角色互换
       弹窗 .ldp-modal-mask (100000)——否则弹窗压在覆盖层之上，虚拟光标被盖住、触摸被
       弹窗拦截，虚拟鼠标"移动不到弹窗上"。覆盖层背景透明 + targetAt 过滤自身，
       下层弹窗仍可被合成事件命中操作。光标为覆盖层子元素。
       光标尺寸位置由 JS 按 ÷scale 换算，保证视觉大小恒定。 */
    .ld-vmouse {
      position: fixed;
      inset: 0;
      z-index: 200000;
      display: none;
      touch-action: none;
      -webkit-user-select: none;
      user-select: none;
      -webkit-touch-callout: none;
    }
    .ld-vmouse.on { display: block; }
    .ld-vmouse-cursor {
      position: absolute;
      top: 0;
      left: 0;
      z-index: 2;
      background: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIAAAACACAQAAABpN6lAAAACcElEQVR4nO2c247iQAxEK0f8/y9nxKLdB3aUdJJ2ty9d0oiHuMv4uADBSJGWlpaWlpaWlr607/uuAuLoYgUEHF/Oj4CzguwIOLq4FUDA8eX8CDgryI6A85LcCGgpyoyAtrK8CGgtzIqA9tKcCLhSnBEB18rzIeDqgWwIuH4kFwLuHMqEgHvH8iDg7sEsCLh/NAcCnhzOgIBnx+Mj4KlBdAQ8t4iNgB4mkRHQxyYuAnoZRUVAP6uYCOhpFhEBfe3iIaC3YTQE9LeMhQAL00gIsLGNgwAr4ygIsLOOgQBL8wgIsLX3jwDrBt4RYN/CNwJGNPGMgDFt/CJgVCOvCBjXyicCRjbziICx7fwhYHRDbwgY39IXAmY09YSAOW39IGBWYy8ImNfaBwJmNveAgJnNPSBAqo0AqTYCpNoIkGojQKqNAKk2AqTaCJBqI0CqjQCpNgKk2giQaiNAqo0AqTYCpNoIkGojeMlUvZ75vm8fFtUSYK+Xrf32JwNW2+shVFxYN9gc/PR9JFRcPDXYT9/pfWeAZ8fdzjUGwP71GDED3D/6mcjzR5wpgP3f+O+/uBmg8vZvA/geP3IGqLz9WwB+Hz9uBqi8/csAjsaPmgEqb/8SgPPxY2aAyttvBtA6fsQMUHn7bTdWvjR+vAxQefvnN1e/MX60DHBWkHn7LbfWvjF+rAxQeftvGY343u6ZtY//GaHiwsY2zvsAKi6sjKNkABUXdtYxMoCKC0vzCBlAxYWtvf8MoOLCukFLBmYKFdc2osnRd8PZP7q9NFF/XxozvxRvY9r8nwEPw09LgJfh3xr2FL4/6T0MPy0BXoZf0pJ+AAFT5bkaJi/wAAAAAElFTkSuQmCC') no-repeat center / 100% 100%;
      pointer-events: none;
      display: none;
      will-change: transform;
      filter: drop-shadow(0 2px 4px rgba(0,0,0,.35));
    }
    /* 悬停在可点击元素上变手型（系统 aero_link 提取的纯白小手；base64 内嵌，防 no-cache 下换图闪白） */
    .ld-vmouse-cursor.pointer {
      background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIAAAACACAYAAADDPmHLAAAGXUlEQVR4nO3dW0gcVxwG8G/XGrVt3IoRaWzFEBNfloIJFBsjFJIn+xSCoZVQaaElpK2UFkqlL3lInoSAFFJqKSUkfShEGl9aoclDN5BqhGpN1dqusZLiDeNmNfGS7s4p/+VM2KTedqPuzJzvBwsbnWw25//N9ZwzA2yebQAaAfwCYE6/5P37+nfkYTsB/ApArfDq0cuQB+XoAqvy8nJ16dIlFY1GEy95Lz/TIejVy5LHfCgF3rt3r4pEIupx8jP5nQ6BLEseI/v5xNq+EvmdDoAsSx6zJMWVTf5K5ubm7AAsZvrLms63CZ8phYVSavV/2OfbzO9A6+Rf74LkTQyA4RgAwzEAhmMADMcAGI4BMBwDYDgGwHAMgOEYAMM5KQAySug9ANc5gsjdEj19a0kaHSRKAPRxBJGZAZA1/7c0RhBt0+MLucVweQA+SGMEEbcYHgpAd4ojiLbprQHHHHokAIspjiBKZ4tBDg7AZm8xbJyn4JEApLrFEJyn4KEApLo85ykYHgDOUzA8AJyn4PBh4djk5R/IAWA0GkV+fv6yy967dw/bt2+35zTkwiAmBCDV5X0wiJM6gygDGADDMQCGYwAMxwAYjgEwHANgOAbAcAyA4RgAw2XsUrDT+HgpmEzEXYDhGADDMQCGSw5AHoB3AfwI4B89OGIeQCeAz3hzZ2+rAPDnKnPzlA7EVwCeX+Oz1jVky2nw6FxFozwDYEj+83v27FGtra1qZGRExWIxNTMzozo6Oqz6+norOzvbbiC57//HALJW+DwGwGUSM20qKyvV/fv3V1xDwuGwOnbsWPKaIruG8mU+jwFwmZ+laO3t7evaVF6+fDleXFwc14WOAqh/7PMYAJeZkKJNTU2te395584ddfTo0eStQXPSLoEBcJkFKdrS0pJK1dmzZ+NJxwZy9vAcA+A+shlXo6OjKh3Xrl1TRUVF9i7hDwbAfdqkaCdPnlTpunXrllVRUfEglZk7TgODTwNfAvCvz+dTFy5cSLsB5bigpqYmsTthANwnMYEyLy9PdXZ2ph2ChYUFVVdXZzEA7vSNFG7Hjh2qv78/7RBYlqUaGxst5TIweBdgk9O4dmmEkpISNTw8rEwCBuBhh9BVaYzdu3eryclJZQowAA8F7PvwBINBdffuXWUCMACPKALwlzTKoUOHEh1DXgcG4H+ko2dKGubEiRPK68AALOsV+0mgFy9eVF4GBmBF70jjBAIBS8YJeBUYgFV9Lw108ODBuFePB8AArHlQOC6N1NzcrLxmfn6eAViHWgBWbm6uGhgYUF4yMTFhB2AGhkllWPgPAL5eXFxEQ0MDYrEYvGJsbMx++zcMk+q8gI+kkbq7u3HmzBl4xc2bN+23DMAaZETwWwDip0+fxvXr8rAO9+vp6bHfdmX2m7iHrP6qrKxs2Xv2u00wGLSPAWoy3bBu8ZR+Vo86cuSIJV3AbjU0NGQXPwIgO9MN6yZlutFcfWrY1NRkB0BmPVGKXgMQy8rKkhlEym1mZ2dVYWGhHYBKVj89n0gDFhQUuO76wKlTp+zi/8TiP9ltZr61RxLdvn1buYF8z/z8fCm+jGGsYgCezNN6rmDiiFomlTpdbW2tvfZLeGmD+gv6pVH37dvn6NPDlpYWu/gTAIpZ/Y3zAoBhadz9+/c7cjjZlStXlJ7OZun+DdpgLwII6+7jxCPcnKKrq0vGNdhr/6es/BZsCQ4cOBB3wu4gFAolF/9LFn9rLhSN2nceGRwczFjxz58/r3JycpKLz5tjbZFSAL9Lw8spV2tra3wrLxvL00UbGhrswlu6D8Ooh0I5gTyr7Tt7yNXhw4dVX1/fpqegra1NlZaW2sWfBVCX6YYw3esAJqUgfr8/fvz4cau3t3dDgxCPx+UWNqqqqip5iNdVvTsiBygE8Ln9AGh5VVdXx8+dOxcfHx9/oh49uawrxxpJhZfBHW9wk786XwbPEpoAvAngWfmB3+9HMBhEdXW1XEjyydzEXbt2+QKBAAoKChJ/KRKJYHp6GiMjIwiHw7hx4wZCoVDiz0kGAbTo2c5y0wpy+PHB2wA67HsVpfmSGUxfAHiVa3xqfA7rT3hZd8wE9dS0nXq3Ib+L6SFpEX16KRebegGEAAzoo3wiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIpf7DyxtVw4WMlrtAAAAAElFTkSuQmCC');
    }
    /* 悬停在输入框/文本域上变竖 I 输入光标（系统 beam_r 提取；base64 内嵌，防 no-cache 下换图闪白） */
    .ld-vmouse-cursor.text {
      background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIAAAABaCAYAAABwm16CAAACLElEQVR4nO3cMY7aUBDG8ZnYsEFKQYlyjNwhDRJNCgpKRJU0HGGPQJNUaEsXtEgUOURukYhi6SKh4KwmMruReJvFJiIS2Zn/T7IszBtky9972M2IAAAAAAAAAAAAAAAAAAAA4NlTccbMGq9JVe3cGi/cBeAUZtY6/KyqpQTlLgBm9rppjKp+O7fGi1z8+VoURe0AMxsffi6K4qZu/Gg0cjlZXF6Umf1Qrb2s9mQySQ7M5/Nqt6v5zWoFuBKHPK4A7fE4meCJ9Xpd3fDkP7/f77d6vV5bAvK4ArxvGPKx1UqeAaUs93n4UFekqp/+wenh0sqyrF7nkq28PxaSxxUgnd5/2j1+RjDb3//av4DIr4qu2P3dTraKBPXi0ieAyyIAwRGA4AhAcAQgOAIQHAEIjgAERwCCIwDBEYDgCEBwBCA4AhAcAQiOAARHAIIjAMERgOAIQHAEIDgCEBwBCI4ABEcAgiMAwRGA4AhAcAQgOAIQnLsWMaf0/DtSl4vIXbQ+geHQIcT/CvDqb2vyPK/qPovIu2NjVPW7OOQuACJyu1wuj36ZZZk8XupXq1XW7Xbfbjab26dqBoNBtXspDnnsEfSzoU/gXafTSfoBbbfb3UMo2jV9Aj1OFpcrQPYwY5+kqtlsNvtyeGw6nb6p9hFbBXlcAa6bxqjq9bk1XrgLwCkWi8X+QeC34XB49PXPO3cBMLPGlq+quju3BgAAAAAAAAAAAAAAAAAAQP4jvwDzAKkLO/STyQAAAABJRU5ErkJggg==');
    }

    /* 系统设置面板内开关行：仅触屏设备显示 */
    .ld-touch-only { display: none !important; }
    html.ld-touch .ld-touch-only { display: inline-flex !important; }

    /* ═══ 修复：透明横向滚动条轨道/热区拦截标签点击（2026-08-29） ═══
       钢筋物资视图(trace)二级标签栏内，各"施工预算控制表"解耦引擎
       （预算 cb / 钢筋采购 meb / 现场调出 mex / 内部调拨 mib / 统计汇总 mss）
       会在 #trace .mat-tabs 内创建绝对定位的水平滚动条轨道(z-index:8，高12px)
       与悬停热区(z-index:7，高30px)。这两类元素默认 opacity:0（不可见），
       但 opacity:0 不影响命中测试——透明的轨道/热区仍会拦截其下方标签按钮的点击，
       导致"统计汇总↔物资指数"往返切换后物资指数文字区点不动（只剩左侧小图标可点）。
       修复：隐藏态一律 pointer-events:none 不参与命中；仅滚动条显示(.xx-show)时
       恢复可交互（拖动滑块 / 点击轨道跳转）。热区不再承担鼠标命中，
       滚动条改由真实滚动(syncFrom→showHScroll)触发显示，功能不受影响。 */
    .cb-hscroll, .meb-hscroll, .mex-hscroll, .mib-hscroll, .mss-hscroll,
    .cb-hscroll-zone, .meb-hscroll-zone, .mex-hscroll-zone, .mib-hscroll-zone, .mss-hscroll-zone {
      pointer-events: none;
    }
    .cb-hscroll.cb-show, .meb-hscroll.meb-show, .mex-hscroll.mex-show,
    .mib-hscroll.mib-show, .mss-hscroll.mss-show {
      pointer-events: auto;
    }
    /* ══ 盈亏分析二级导航内容区（2026-08-30，标准同项目工程 .project-group-tab）══ */
    #delivery .analysis-pane {
      display: none;
      align-items: center;
      justify-content: center;
      min-height: 240px;
      color: var(--muted);
      font-size: clamp(13px, 0.7vw, 18px);
    }
    #delivery .analysis-pane.active {
      display: flex;
    }
    /* ══ 形象进度二级导航内容区（2026-08-30，标准同项目工程 .project-group-tab）══ */
    #progress .progress-pane {
      display: none;
      align-items: center;
      justify-content: center;
      min-height: 240px;
      color: var(--muted);
      font-size: clamp(13px, 0.7vw, 18px);
    }
    #progress .progress-pane.active {
      display: flex;
    }
    /* ══ 管理工作-工作汇报内联内容区（2026-08-30 由一级导航 processing 移入）══ */
    #cat-report {
      display: none;
      flex-direction: column;
    }
    .stl-back-btn {
      border: 1px dashed var(--line) !important;
      background: transparent !important;
      color: var(--muted) !important;
    }
    .stl-back-btn:hover {
      color: var(--text) !important;
      border-color: var(--primary) !important;
    }

    /* ══ 工作汇报独立铺放：不显示管理工作容器与头部（2026-08-30）══ */
    #projectWorks.pw-report-mode .pw-layout {
      border: none;
      border-radius: 0;
      background: transparent;
    }
    #projectWorks.pw-report-mode .pw-layout::before { display: none; }
    #projectWorks.pw-report-mode .pw-main-header { display: none; }
    #projectWorks.pw-report-mode .pw-cat-content {
      padding: 0;
      overflow-y: auto;
    }
    /* ══ 项目工程独立铺放（2026-08-30 简单版内联：作为管理工作二级页面，隐藏管理工作头部）══ */
    #projectWorks.pw-projects-mode .pw-layout {
      border: none;
      border-radius: 0;
      background: transparent;
    }
    #projectWorks.pw-projects-mode .pw-layout::before,
    #projectWorks.pw-projects-mode .pw-layout::after { display: none; }
    #projectWorks.pw-projects-mode .pw-main-header { display: none; }
    #projectWorks.pw-projects-mode .pw-cat-content {
      padding: 0;
      overflow: hidden;
    }
    /* ══ 料单审核「四级页·审核前明细数据」独立铺放（2026-10-11 用户："改成覆盖式"）══
       与 工作汇报(`#cat-report`)/项目工程(`#cat-projects`) **同一套**（那两处见第 8181-8188 行）：
         · 隐藏管理工作头部那条二级导航行（工作汇报 / 项目资料 / 项目工程…）—— 只这一件事；
         · 四边距离**全部复用现成链**，不另造：
             左右 = `.main` 的 22px（`#cat-review` 的 `margin:0 -15px` 已抵消 `.pw-cat-content` 的 15px）；
             顶   = 自己补 18px（见下）；
             底   = 贴浏览器底（同施工预算量的 `.main.budget-view-active{padding-bottom:0}`）。
         · ⚠ **必须自己补回顶部 18px**：`#projectWorks{margin-top:-18px}` 把整块上移了 18，
           正常模式靠 `.pw-main-header{padding-top:18px}` 补回来；头部一藏就少了这 18
           ⇒ 同 `#cat-projects{margin-top:18px}` 的做法，给分类内容补 `margin-top:18px`。
         · ⚠ 别再给 `.pw-layout` 写 transparent / 去边框：`#projectWorks .pw-layout`（第 4572 行）
           **本来就是** border:none + background:transparent（"黑边"不是它引起的，重复写只会误导）。
         · ⚠ 别再动 `.pw-cat-content` 的 padding：它那 15px 与 `#cat-review` 的 -15px 是一对，
           动一半 = 左右被裁（2026-10-11 实测踩过一次）。
       类由 `lingdu-review.js` 的 `openDetailData()/closeDetailData()` 在 `#projectWorks` 上增删。 */
    #projectWorks.pw-dd-mode .pw-main-header { display: none; }
    #projectWorks.pw-dd-mode #cat-review {
      /* 只补**顶部 18px**（头部隐藏后 `#projectWorks{margin-top:-18px}` 抵消的 .main 顶 padding 没人补了）。
         左右**一概不动**：`#cat-review` 本来就 `margin: 0 -15px` 去抵消 `.pw-cat-content` 的 `padding:0 15px`
         ⇒ 正好落回 `.main` 的 22px（= 施工预算量口径）。
         ⚠ 2026-10-11 实测教训：上一版把 `.pw-cat-content` padding 归零，这 -15px 就**反向撑出去**了
           （实测 `#reviewDetailDataView` left=6、父 `#pwCatContent` left=20、子比父还宽）⇒ 左右被裁。
           ⇒ **要动左右，就别动父的 padding**；父 padding 一改，这对负外边距必须一起改。 */
      margin-top: 18px;
    }
    /* 底：施工预算量是 `.main.budget-view-active{padding-bottom:0}` —— **贴浏览器底**（无底边距）。
       四级页同样"贴底" ⇒ 用 `:has()` 把 `.main` 的底 padding 归零（页内不再另留底边距）。 */
    .main:has(#projectWorks.pw-dd-mode) {
      padding-bottom: 0;
    }
    #cat-projects {
      display: none;
      flex-direction: column;
      flex: 1;
      min-height: 0;
      overflow: hidden;
      position: relative;
    }
    /* 内联后背景透明，隐藏卡片装饰光斑层，避免与底层重叠（2026-08-30） */
    #projectWorks.pw-projects-mode .project-card-wrap::before,
    #projectWorks.pw-projects-mode .project-card-wrap::after { display: none; }
    /* 内联后项目工程卡片层自身也复位为铺满，去掉左右上残留边框/圆角/底(2026-08-30 修没铺满) */
    #projectWorks.pw-projects-mode .project-card-wrap {
      border: none;
      border-radius: 0;
      background: transparent;
    }

    /* 内联后项目工程卡片层自身也复位为铺满，去掉左右上残留边框/圆角/底(2026-08-30 修没铺满) */
    #projectWorks.pw-projects-mode .project-card-wrap {
      border: none;
      border-radius: 0;
      background: transparent;
    }

    /* ══ 项目工程·各分组统一贴合容器边缘：左右下归0，顶部距标签20px（2026-08-31 用户要求）══
       作用范围覆盖全部5个分组：动态地图(map) + 在建(ongoing)/竣工未结(completed)/正在结算(settling)/结算完成(done)。
       容器级(projectPageGrid/rows-scroll/tabs/sticky-header)只要任意分组激活即左右下归0；
       分组级：卡片分组(非map)由 .project-group-row 顶部padding提供20px；地图分组由 .map-stage 顶部padding提供20px。 */
    #projectWorks.pw-projects-mode #projectPageGrid:has(.project-group-row:not(.group-hidden)) {
      padding: 0;
    }
    #projectWorks.pw-projects-mode #projectPageGrid:has(.project-group-row:not(.group-hidden)) .project-rows-scroll {
      padding: 0;
    }
    #projectWorks.pw-projects-mode #projectPageGrid:has(.project-group-row:not(.group-hidden)) .project-group-tabs {
      /* 标签与说明行的间距：tabs 底部 padding 14px + desc-bar margin-top 6px = 20px（用户要求）。
         同时为选中态41px定高按钮保留底部空间，避免 sticky 叠层裁掉按钮底边0.5~1px；基础样式同为14px。 */
      padding-bottom: 14px;
    }
    #projectWorks.pw-projects-mode #projectPageGrid:has(.project-group-row:not(.group-hidden)) .project-sticky-header {
      /* 标签顶部与工作日报对齐（实测两处 top 均为 16px）。
         -18px 负偏移使标签顶部贴合容器顶部；顶部裁边由下方容器 overflow:visible 解决。 */
      top: -18px;
      margin-top: -18px;
      padding-bottom: 0;
      margin-bottom: 0;
    }
    /* 项目工程贴边模式：容器不再裁切顶部。标签(-18 对齐时)顶部贴合容器顶部，
       若 overflow:hidden 会裁掉选中态顶部0.5~1px（工作日报 #cat-report 无 overflow 故不裁）。
       滚动由 .project-rows-scroll 独立承担；projects-mode 下光斑层已 display:none，overflow 放开无副作用。 */
    #projectWorks.pw-projects-mode #cat-projects,
    #projectWorks.pw-projects-mode .project-card-wrap {
      overflow: visible;
    }
    /* 卡片分组（在建/竣工未结/正在结算/结算完成）：左右下归0，顶部20px由行padding提供（网格/内容模式一致） */
    #projectWorks.pw-projects-mode .project-group-row:not([data-group="map"]):not(.group-hidden) {
      padding: 20px 0 0;
    }
    /* 地图分组：顶部20px由 .map-stage 顶部padding 提供 */
    #projectWorks.pw-projects-mode .project-group-row[data-group="map"]:not(.group-hidden) .map-stage {
      padding: 20px 0 0;
    }
    /* 动态地图分组：desc-bar 已由 JS 隐藏（.project-map-mode），标签栏底部归0，
       标签按钮底部 → 地图面板顶部 间距 = .map-stage 顶部20px（2026-08-31 恢复此前丢失规则）。
       特异性与上方通用 .project-group-tabs 规则相等，置于其后可覆盖 14px。 */
    #projectWorks.pw-projects-mode #projectPageGrid:has(.project-group-row[data-group="map"]:not(.group-hidden)) .project-group-tabs {
      padding-bottom: 0;
    }


    /* ══ 工作汇报模板预览：原地打开页面预览（同图集书架阅读页，2026-08-30）══ */
    #cat-report { position: relative; flex: 1; min-height: 0; }
    .ppt-inline-reader {
      display: none;
      position: absolute;
      inset: 0;
      z-index: 20;
      flex-direction: column;
      overflow: hidden;
      background: var(--bg);
    }
    .ppt-inline-reader .std-reader-body iframe {
      width: 100%;
      height: 100%;
      border: none;
      display: block;
      background: #0b0b0e;
    }
    /* 2026-09-14 远程演示：演示端在模板预览里按 Q 全屏 → 观看端**这一页也铺满整屏**。
       `requestFullscreen()` 需要"用户手势"，观看端是被动接收（多半会被浏览器拒）→ 这条 CSS 全屏是**保底**，
       做法与「施工影像放映」（`.photos-fs`）完全一致：升为 fixed inset:0 直接铺满视口，
       与页面布局彻底解耦（原稿模式下 fixed 的基准是 body 画布，scale 后同样铺满）。
       由 lingdu-present.js 的 `_pptFsSet()` 加/去；退出预览或会话结束时收回。 */
    .ppt-inline-reader.ldp-ppt-fs {
      position: fixed;
      inset: 0;
      z-index: 9990;
      background: #000;
    }

    /* ══ 工作汇报预览顶部：模板快速切换（2026-08-30）══
       2026-09-01：容器样式与图集规范阅读页 .std-reader-tabs 完全一致（含 height:38px），
       按钮复用 .std-reader-tab（见 _views.html pptRenderTabs 类名），不再自造样式。
       2026-09-02：去掉固定 height:38px 并把 align-items 改为 flex-start——让标签按钮
       顶边与「返回模板列表」(.std-back-btn) 顶边对齐（原先标签在 38px 容器内垂直居中，
       顶边偏低约 3.65px，导致顶部不对齐）。 */
    .ppt-switch-tabs {
      flex: 1;
      min-width: 0;
      display: flex;
      align-items: flex-start;
      gap: 4px;
      overflow-x: auto;
      overflow-y: hidden;
      scrollbar-width: none;
    }
    .ppt-switch-tabs::-webkit-scrollbar { display: none; }
    .ppt-inline-reader { width: 100%; height: 100%; }
    .ppt-inline-reader .std-reader-body iframe {
      position: absolute;
      inset: 0;
      width: 100%;
      height: 100%;
    }
    /* 2026-09-01 工作汇报模板预览：顶部按钮标签距页顶 18px。
       pptPreview() 打开时同图集规范一样隐藏 .pw-main-header，使阅读页顶端即面板顶端，
       这里 padding-top=18px 即按钮标签到页面顶边的实际距离（无需 align-items 偏移修正）。 */
    .ppt-inline-reader .std-reader-top {
      align-items: flex-start;
      padding: 18px 12px 8px;
    }
    /* 2026-09-01 预览打开(.ppt-inline-reader 显示为 flex)时，清零 #cat-report 的 +18px 补偿
       （该补偿使工作汇报列表页在 #projectWorks 的 -18px 上移后保持原位），否则预览顶栏被
       整体下推 18px。关闭预览(:has 不匹配 display:none)自动恢复 +18px。 */
    #cat-report:has(.ppt-inline-reader[style*="display: flex"]),
    #cat-report:has(.ppt-inline-reader[style*="display:flex"]) {
      margin-top: 0;
    }




/* 管理工作(#projectWorks)整体上移 18px：让 .pw-main-header 里的二级导航
   (.pw-nav) 高度位置与预算翻样(.mat-tabs)一致，与《项目工程》此前
   top:-18px/margin-top:-18px 的上移值保持一致。上移作用于整个管理工作内容。 */
#projectWorks {
  margin-top: -18px;
}

/* 管理工作内联的 3 级页面（项目工程入口 cat-projects、工作汇报 cat-report）
   保持原位不动：父视图已上移 18px，这里反向补偿 18px。 */
#cat-projects {
  margin-top: 18px;
}
#cat-report {
  margin-top: 18px;
}


/* ── 侧栏隐藏时顶部标签行右侧一级导航切换按钮（2026-09-03）── */
/* 按钮组外层容器：margin-left:auto 把整组推到此行容器最右端，右对齐固定不随标签跑动 */
.ldg-topstep-wrap {
  display: inline-flex;
  align-items: center;
  gap: 10px;                 /* 2026-09-03 两箭头间距 4→10 */
  margin-left: auto;
  flex-shrink: 0;
}
.ldg-topstep-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 57px;                /* 2026-09-03 外宽 42→57（再 +35%） */
  height: 41px;               /* 2026-09-03 高度 38→41，与二级导航按钮(.stl-group-tab 等 height:41px)一致 */
  padding: 0;
  border-radius: 12px;
  border: 1px solid var(--line);
  background: var(--panel);
  color: var(--text);
  font-size: 19px;
  line-height: 1;
  cursor: pointer;
  user-select: none;
  flex-shrink: 0;
  transition: background .2s, color .2s, border-color .2s, box-shadow .2s;
}
/* 箭头图标（↑ / ↓）——★ 2026-10-15 用户："右上角的这个上下箭头和主页这三个，单按钮是不是
   也可以也用这个 SVG？" ⇒ 已改成与「主页」那枚**同款画出来的 SVG**（24×24 视口 / 19×19 /
   stroke 2.1 / round 端点 / currentColor，见 `lingdu-core-monitor.js` 的 `_stepArrowSvg`）。
   ⚠⚠ 原来给**字符**箭头叠的这三层"看着居中"补丁**已全部撤掉**，别再往回加：
       桌面：font-weight:900 + -webkit-text-stroke:.5px + `transform: scaleX(1.56) translateY(-2.5px)`；
       平板/手机：另换一套 `scaleX(1.2)`（下面那条 @html.ld-device-* 覆盖也一并删了）。
     原因同 `lingdu-core.js` 的 ldgInkFix 注释：字符墨迹随**字体 / DPR** 变，一个值只能补一头；
     画出来的图形是几何居中 —— 三枚按钮现在天然一致（本组尺寸 57×41 与间距一个字没动）。 */
.ldg-topstep-btn .ldg-topstep-ic {
  display: inline-flex;
  align-items: center;
  justify-content: center;
}
.ldg-topstep-btn .ldg-topstep-ic svg { display: block; }
/* 图标尺寸 + 线宽（本组）★ 2026-10-15 用户："逻辑正确，然后这个按钮不增大的情况下，这个图形
   有点偏小，把这个图形加大两倍就是 ×2。" + "线条用 2px" + "右上角那个主页的小房子给他用 30 大小"
   + "线条都统一用 2px" ⇒ **按钮 57×41 不动**：
     · ↑ ↓    ：19 → **38px**（×2）；
     · 主页房子：**30px**（比箭头小一档，用户指定）。
   ▍线宽为什么不是字面的 "2"：SVG 的 `stroke-width` 是**视口单位**，屏幕粗细 = 视口值 × (图标px ÷ 视口边长)
     ⇒ 图标大小不同、视口不同，写同一个数看着粗细就不一样。要"看着都是 2px"得各算一下：
       ↑ ↓    ：24 视口 / 38px ⇒ 2 ÷ (38/24) = **1.26**
       主页房子：24 视口 / 30px ⇒ 2 ÷ (30/24) = **1.60**
     预览那排：20 视口 / 21.6px ⇒ 2 ÷ (21.6/20) = **1.85**（见 `.file-preview-action-btn` 那两条）
     ⚠ CSS 的 stroke-width **压过** SVG 上的同名属性 ⇒ 组件里那个 2.1（lingdu-core-monitor.js）
       只当兜底，真正生效的是这里；要改粗细只改这里。 */
.ldg-topstep-btn .ldg-topstep-ic svg { width: 38px; height: 38px; stroke-width: 1.26; }
.ldg-topstep-btn .ldg-topstep-homeic svg { width: 30px; height: 30px; stroke-width: 1.6; }
.ldg-topstep-btn:hover {
  background: var(--primary-soft);
  border-color: var(--primary);
  color: var(--primary);
}
.ldg-topstep-btn:active { transform: scale(.94); }
/* 智慧管理(AI 对话)：wrap 以 fixed 钉在视口右上，需保证在最上层 */
.ldg-topstep-wrap { z-index: 300; }

/* ── 侧栏隐藏时「系统设置」独立浮层（2026-09-04 新增；2026-09-16 按 Win7 经典开始菜单的版式重排）
   无顶栏（用户：不要标题、不要关闭按钮）。主体左右双栏：左列＝内套一块通到底的区域（上＝桌面图标
   预留区 / 搜索结果 / 「所有程序」列表，下＝「所有程序」按钮 + 搜索框）；右列＝菜单平铺（
   用户名、主题下拉、亮度调节、缩放比例…），底部沉「退出登录」胶囊。面板高基础＝总高的 60%。 */
.ld-settings-root {
  position: fixed;
  left: 18px;
  bottom: 18px;
  z-index: 500;
  /* 2026-09-16 用户：内边距四边统一 10 → 左 290（桌面图标预留）+ gap 12 + 右 170（菜单）= 内容 472，
     再加 .ld-settings-float 的左右内边距 20 与边框 2 → 面板总宽 494 */
  width: 494px;
  max-height: calc(100vh - 36px);
  display: flex;
  flex-direction: column;
  align-items: stretch;
}
/* 毛玻璃（2026-09-16 用户定稿「C 方案」逐主题配置台实测结果）：
   底色锚定主题自带的 --panel（不引入外部色，避开主色 --primary 免得糊成实心色块），
   再用 color-mix 乘 alpha 做半透明，配合 backdrop-filter 透出背后的桌面。
   顶部白色高光已按用户要求去掉（2026-09-16），不再做玻璃厚度那道光。
   深色主题用「默认」那套（cA 78 / blur 9），
   浅色主题走下面「浅色主题套」覆盖块（cA 80 / blur 8）。边框对比 bd=0 → 直接用 var(--line)。 */
.ld-settings-float {
  flex: 1 1 auto;
  min-height: 0;
  overflow: hidden;   /* 滚动交给两列各自的溢出，整卡不滚 */
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding: 10px;   /* 2026-09-16 用户：内层到外层玻璃的四边距离统一 10px */
  border-radius: 7px;   /* 2026-09-16 用户：圆角较 14px 收一半 */
  background: var(--panel);   /* 兜底：不支持 color-mix 的浏览器退回主题面板色（不透明，仍可读） */
  /* 2026-09-16 用户：两套对应调换 —— 深色主题（本节＝基底）＝「默认」那套，浓度 78% / 模糊 9px */
  background-color: color-mix(in srgb, var(--panel) 78%, transparent);
  -webkit-backdrop-filter: blur(9px) saturate(128%);
  backdrop-filter: blur(9px) saturate(128%);
  border: 1px solid var(--line);
  /* 2026-09-16 用户：去掉顶部那道白色高光（原 background-image 顶部渐变 + inset 白色内描边） */
  box-shadow:
    0 14px 34px rgba(0, 0, 0, .28),
    0 2px 6px rgba(0, 0, 0, .14),
    inset 0 -1px 0 rgba(0, 0, 0, .10);
  font-size: 16px;   /* 2026-09-16 用户：开始菜单内文字全部统一 16px */
  color: var(--text);
}
/* 2026-09-16 用户定稿：开始菜单「只有两个颜色」——每套＝玻璃配色 + 参数（浓度 / 模糊 / 左容器）。
   ① 深色主题（本节＝基底）＝「默认」那套：站点默认主题（themes.css 的 :root 深青）原值，
      78% / blur 9px / 左容器 bd20·a20·r0·sh.22。
   ② 浅色主题（见下方「浅色主题套」）＝「暗影黑」那套：anhei 原值，
      80% / blur 8px / 左容器 bd26·a30·r0·sh.26。
   2026-09-16 用户：两套对应调换（原为「浅色配默认 / 深色配暗影黑」，现互换）。
   钉住面层变量 + 文字色（否则黑玻璃会配上主题的深字，读不出来）。 */
.ld-settings-float {
  --panel: rgba(7, 34, 43, .88);
  --bg-deep: #031116;
  --line: rgba(113, 232, 238, .18);
  --accent-2: #2dd4ff;
  --text: #e9fdff;
  --muted: #8fc7d0;
  --primary: #10e7df;
  --primary-soft: rgba(16, 231, 223, .16);
}
/* ── 系统设置浮层内部节点（2026-09-16 按 Win7 经典开始菜单的版式重排）
   这些 .ld-sm-* 节点由 lingdu-core-monitor.js 里 open() 现场构建：控件按 title 从侧栏克隆
   （保留内联 onclick 与运行时的显隐状态，侧栏里被隐藏的项不进浮层）。 */
.ld-sm-body {
  flex: 1 1 auto;
  min-height: 60vh;   /* 基础高度＝总高的 60%（2026-09-16 用户）；用 min-height 而非 height，左列以后加桌面图标时整卡会自动加高 */
  display: flex;
  align-items: stretch;
  gap: 12px;
}
/* 左列：内套的一块区域（不是靠竖线分隔），整列通到底；底部固定「所有程序」+ 搜索框 */
.ld-sm-left {
  /* 目标宽 290px；右列 130px 定死，左列（图标区）用 flex 吃掉剩余宽度 */
  flex: 1 1 290px;
  min-width: 0;
  box-sizing: border-box;
  /* 2026-09-16 用户：图标距内层（这块内嵌区）四边统一 6px */
  padding: 6px;
  border: 1px solid color-mix(in srgb, var(--accent-2) 20%, transparent);
  border-radius: 0;
  /* 比外层玻璃再沉一层 + 内阴影：做出「内嵌进去」的凹陷感，和右列拉开层次
     （2026-09-16 用户定稿「默认」那套：bd20 / a20 / r0 / sh.22） */
  background: color-mix(in srgb, var(--bg-deep) 20%, transparent);
  box-shadow: inset 0 1px 6px rgba(0, 0, 0, .22);
  display: flex;
  flex-direction: column;
  gap: 6px;
  overflow: hidden;   /* 滚动交给 .ld-sm-left-body，底部两个控件常年钉在底部 */
}
/* 左列内容区：搜索结果（有搜索词时才显示；常规态/「所有程序」展开态都是图标区） */
.ld-sm-left-body {
  flex: 1 1 auto;
  min-height: 0;
  display: flex;
  flex-direction: column;
  gap: 3px;
  overflow-y: auto;
  overflow-x: hidden;
}
/* ── 开始菜单图标区（2026-09-16 用户）─────────────────────────────────────────────
   开始菜单是**两个独立页面**（各放各的图标，互不影响）：没点＝第一层「外面」，点开「所有程序」＝第二层；
   同一时刻只显示一块（由 renderLeft 切 display）。
   每层都能**右键切换排列方式**（2026-09-16 用户）：
     · 横向标签式 .ld-layout-list＝图标左 + 文字右，一行一项；
     · 网格 .ld-layout-grid＝图上文下，列数＝能放下的个数、每列等分容器宽（能放 3 个就 3 等分）。
   高度（2026-09-17 用户定稿）：**两层都能滚** ——
     · 图标没到卡片上限时：第一层 `flex-grow` 吃掉剩余空间、卡片按内容自动加高（原行为不变）；
     · 到了卡片上限（.ld-settings-root 的 `max-height: calc(100vh - 36px)`）还在放：
       第一层改为**容器内滚动**（原来是 `overflow: visible` → 撑不下就被外层 `overflow: hidden`
       裁掉：图标点不到、也看不到）。第二层本来就是容器内滚动、不撑高外框。*/
/* 图标区容器：**两种排列都**在容器内留 6px —— 图标离"这块图标区"四边 6px，高亮描边不会再贴住容器边缘
   （2026-09-16 用户：横向标签式与网格都要）。网格的 `gap` 只管"格与格之间"，最外圈本来会顶到容器内边，
   这层内边距同样把它兜住；列表式整行铺满，也靠它把左右缩进来。 */
.ld-sm-icons {
  min-height: 0;
  padding: 6px;
}
/* 横向标签式（一行一项）：行与行之间上下 5px（2026-09-16 用户：在原来 2px 基础上加 3px） */
.ld-sm-icons.ld-layout-list {
  display: flex;
  flex-direction: column;
  gap: 5px;
}
/* 网格：auto-fill + 1fr → 列数按能放下的个数、每列等分（--ld-cell-w 由 JS 按尺寸档写） */
.ld-sm-icons.ld-layout-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(var(--ld-cell-w, 87px), 1fr));
  align-content: flex-start;
  gap: 2px;
}
/* 第一层：吃掉剩余空间 → 下方「所有程序」按钮 + 搜索框始终钉在浮层底部。
   2026-09-17 用户："图标多到超过外框限制高度时也要能滚动" —— 由 `flex: 1 0 auto; overflow: visible`
   改为与第二层同款：**撑到卡片上限后内部滚动**（`flex-shrink: 1` + `min-height: 0` 才允许它收缩；
   `min-height: 0` 必须留：flex 项默认 `min-height: auto` 会撑着不肯矮下去 → 就不滚了）。
   没到上限时 `flex-grow: 1` 照样吃满剩余空间、卡片按内容加高，两个行为互不干扰。 */
.ld-sm-icons-outer {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  overflow-x: hidden;
}
/* 第二层「所有程序」：只吃剩余空间、内部滚动 → 绝不撑高外框 */
.ld-sm-icons-inner {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  overflow-x: hidden;
}
/* 浮层里的瓦片：桌面那套 .sm-desk-icon 是 position:absolute（靠 top/left 落格）→ 这里改回流式，交给容器排布 */
.ld-settings-float .sm-desk-icon {
  position: relative;
  left: auto;
  top: auto;
}
/* 横向标签式的瓦片外观（挂在瓦片自己的类上、不靠容器）——
   拖动时瓦片会被临时搬到 body 下，靠容器选择器的话外观会当场变掉。 */
.sm-desk-icon.ld-sm-tile-list {
  flex-direction: row;
  align-items: center;
  justify-content: flex-start;
  gap: 10px;
  padding: 6px 8px;
}
.sm-desk-icon.ld-sm-tile-list .sm-desk-icon-label {
  flex: 1 1 auto;
  min-width: 0;
}
/* 鼠标经过：浮层内**两层统一**放大 1.03 + 亮「透明玻璃」背景（2026-09-16 用户）。
   桌面那套是 1.05 且只有"单击打开"档才亮背景，这里按用户要求统一。 */
.ld-settings-float .sm-desk-icon:hover {
  transform: scale(1.03);
  background: rgba(74, 158, 255, 0.15);
  outline: 1.5px solid rgba(120, 190, 255, 0.9);
  outline-offset: -1px;
}
/* 拖动中：瓦片被搬到 body 下、fixed 跟随指针（见 lingdu-core-monitor.js 开始菜单拖动段）。
   ⚠ 选择器**不能**带 .ld-settings-float 前缀 —— 拖动时元素已不在浮层里。 */
.sm-desk-icon.ld-sm-dragging,
.sm-desk-icon.ld-sm-dragging:hover {
  opacity: .9;
  z-index: 9999;
  pointer-events: none;
  /* 拖动中不再放大：hover 的 scale 会让"抓取点"和实际尺寸对不上（图标显得偏一点） */
  transform: none;
}
/* 多选整批拖动（2026-09-16 用户）：随行的那些瓦片原地不动、松手才一起搬 → 淡一档，
   让用户一眼看出"这一批都要走"（被抓住的那枚由 .ld-sm-dragging 表示） */
.sm-start-icon.ld-sm-teammate {
  opacity: .45;
}
/* 右列：菜单平铺（Win7 右列＝纯文字列表）。2026-09-16 用户：宽度减小 40px（170 → 130）
   2026-09-21 用户："开始菜单的右边文字功能在高度不够的时候，顶部的用户名和底部的退出登录要固定，
   中间的上下滚动" → **右列自己不再滚**（原 `overflow-y: auto` 会让用户名和退出登录一起滚走），
   滚动交给中间那段 `.ld-sm-right-mid`；头（.ld-sm-user + .ld-sm-sep）与脚（.ld-sm-power）留在列上。 */
.ld-sm-right {
  flex: 0 0 130px;
  width: 130px;
  min-width: 0;
  box-sizing: border-box;
  display: flex;
  flex-direction: column;
  gap: 3px;
  overflow: hidden;
}
/* 右列中间段（滚动体）：选择项目 + 各分组行 + 云回收站 + 手动更新系统。
   自己是一根与右列同款的列布局（行距 3px 原在 .ld-sm-right 上，迁到这里 → 视觉不变）。 */
.ld-sm-right-mid {
  flex: 1 1 auto;
  min-height: 0;
  display: flex;
  flex-direction: column;
  gap: 3px;
  overflow-y: auto;
  overflow-x: hidden;
}
/* 开始菜单里的行。2026-09-18 用户："贴出的样式要和开始菜单自己的样式一样" →
   右列分组「右侧贴出」面板里的行（含桌面 IIFE 造的 `_ldBuildConfirmSuppressMenu()` 那两行）也套用同一套声明
   （并列选择器，不复制第二份，保证两处永远一致）。
   2026-09-18 追加：开始菜单里贴出的「选择项目」浮层（ld-ppick 的 `#ldPpickPanel`，锚点在卡片里时加
   `.ld-sm-pick` 标记）里的项目行也套这一套 —— 当前项目那行用 `.sel`（＝下面的 `.active` 同一套：
   蓝玻璃底 + 主色边框 + 主色文字）。 */
.ld-sm-item,
.ld-sm-pop .smbg-item,
.ld-ppick-panel.ld-sm-pick .ld-ppick-opt {
  width: 100%;
  box-sizing: border-box;
  /* 行高 = **32px**（2026-09-24 第 45 轮用户："那你说那个开始菜单的文字本来就是16px那文字看着还是小，
     那问题就出在这个按钮高度身上了…那这个按钮高度给它设置成32px"）。
     ⚠ 历史：2026-09-18 用户曾要求"文字上下距离统一增加 3px"（32 → 38），本轮按新指令**收回 32**，
       并把本浮层里几处不一致的行高**统一**（主行 38→32、`.ld-sm-allprog` 30→32；`.ld-sm-power`
       与搜索框本来就是 32）。
     ⚠ **实测（线上只读量 `#ldSettingsFloat`）**：这层的 16px 字实际只渲染成 **14.4px** —— 因为全站
       自适应缩放 `html{zoom: 0.8986}`（2560 设计宽 ÷ 本次 2848.9 布局宽）。所以"看着小"的根子在
       全局缩放，**不在行高**；真要把它放大得提 `font-size`（例如 18px → 渲染 16.2px），别只动行高。 */
  min-height: 32px;
  padding: 0 8px;
  display: flex;
  align-items: center;
  justify-content: flex-start;
  gap: 6px;
  border: 1px solid transparent;
  border-radius: 8px;
  background: transparent;
  color: var(--text);
  font-family: inherit;
  font-size: 16px;
  font-weight: 600;
  text-align: left;
  white-space: nowrap;
  cursor: pointer;
  flex-shrink: 0;
}
/* 悬停高亮（2026-09-18 用户："开始菜单上面鼠标经过的时候，它的高亮条也是蓝绿色的，也要改成统一的
   蓝色玻璃"）→ 从"主色辅底 + 主色文字"改成**桌面图标那套蓝玻璃**（同 `.sm-desk-icon.sel`：
   `rgba(74,158,255,.15)` 底 + `rgba(120,190,255,.9)` 亮蓝描边、文字保持正常色）。
   第三项不带 `.ld-sm-pick` 限定：项目选择浮层是三处共用的（开始菜单 / Alt+Q 弹窗 / 管理工作左上角），
   悬停也一并统一。注：`.active`（演示中/接收中/当前主题）**不改**，仍是主色高亮。 */
.ld-sm-item:hover,
.ld-sm-pop .smbg-item:hover,
.ld-ppick-panel .ld-ppick-opt:hover {
  background: rgba(74, 158, 255, 0.15);
  outline: 1.5px solid rgba(120, 190, 255, 0.9);
  outline-offset: -1px;
  border-color: transparent;
  color: var(--text);
}
/* 演示中/接收中（侧栏 .active 随克隆带过来）同样高亮；贴出面板里用它标"当前主题" */
.ld-sm-item.active,
.ld-sm-pop .smbg-item.active {
  border-color: var(--primary);
  background: var(--primary-soft);
  color: var(--primary);
}
/* 「选择项目」浮层里的"当前项目"行 —— 蓝玻璃高亮条（2026-09-18 用户："这个高亮条要和桌面图标悬停的
   那个蓝色玻璃一样的颜色"，随后追加："管理工作里、弹窗里这两个选择项目的地方，被选中的也要加同样的"）：
   直接照搬桌面图标那套蓝玻璃（与 `.sm-desk-icon.sel` 同值：`rgba(74,158,255,.15)` 底 +
   `rgba(120,190,255,.9)` 亮蓝描边；桌面那边也不改文字颜色，这里同样保持正常文字色）。
   用 outline 而非 border → 换色时行内文字不抖动（口径同桌面图标）；圆角 8px 让它是"一块玻璃片"而不是直角框。
   ⚠ 不限定 `.ld-sm-pick`：这张面板是**三处共用**的（开始菜单 / Alt+Q 弹窗 / 管理工作左上角），三处一起生效。
   ⚠ 与 `.ld-sm-item.active`（开始菜单自己的高亮：演示中/接收中/当前主题）分开写，互不影响。 */
.ld-ppick-panel .ld-ppick-opt.sel {
  background: rgba(74, 158, 255, 0.15);
  outline: 1.5px solid rgba(120, 190, 255, 0.9);
  outline-offset: -1px;
  border-radius: 8px;
  color: var(--text);   /* 组件原样式把选中行文字染成主色（青绿）→ 蓝玻璃上要还原成正常文字色（口径同桌面） */
}
/* （2026-09-18 移除）原此处单独给 `.sel:hover` 写"保持蓝玻璃" ——
   现在通用 `:hover` 本身就是同一套蓝玻璃（见上面 `.ld-ppick-panel .ld-ppick-opt:hover`），
   选中行悬停的结果与静态态完全一致，不需要再单写一条。 */
.ld-sm-item .sidebar-tool-text,
.ld-sm-power .sidebar-tool-text {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
/* 2026-09-16 用户：开始菜单内文字全部统一 16px。
   浮层里多数行是从侧栏克隆来的（monitor.js 的 mkItem 会剥掉 sidebar-font-btn /
   sidebar-theme-select，但保留内层 .sidebar-tool-text），而 html.high-res 那套规则
   （4262-4263 行，特异性 0,2,1）会把 .sidebar-tool-text 压成 14px，与自建行
   字号不一致；这里用同特异性 + 更靠后位置盖回 16px。 */
html .ld-settings-float .sidebar-tool-text {
  font-size: 16px;
}
/* 浮层克隆来的控件仍带 .sidebar-tool-text 类，而 325-341 行的
   html[data-ss="icon"] .sidebar-tool-text 会把文字压成 0×0（侧栏处于「图标模式」时命中）。
   浮层挂在 body 下、不属于 .sidebar，这里按更高优先级把文字还原，否则图标模式下浮层只剩图标。 */
html[data-ss] .ld-settings-float .sidebar-tool-text {
  opacity: 1;
  width: auto;
  height: auto;
  margin: 0;
  padding: 0;
  overflow: hidden;
  pointer-events: auto;
  white-space: nowrap;
  text-overflow: ellipsis;
  min-width: 0;
}
.ld-sm-txt {
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
/* 右列分组行 / 「贴出」触发行的右箭头（2026-09-18 用户：子项在右侧贴出，行尾给个方向提示）
   ⚠ 2026-09-24 第 44 轮用户："左下角悬浮导航栏里鼠标悬停弹出的「系统设置」菜单里面的按钮，文字大小统一改为 16px"
     —— **线上实测**（`getComputedStyle` 逐元素量 `#ldSettingsFloat` 与它贴出的面板）结论：那一层里所有
     **可点行的文字本来就都是 16px**（`.ld-sm-txt` / `.sidebar-tool-text` 靠
     `html .ld-settings-float .sidebar-tool-text{font-size:16px}` 兜底、自建行直接继承），
     唯一不是 16px 的就是**这个箭头字形**（15px）⇒ 改成 16px，整层字号从此完全一致。
     实测里还发现"看着大小不一"更像是**字重**差异（行 600 / 所有程序·退出登录 700 / 用户名 800），
     那是刻意的层级，本轮**不动**（用户没要求）。 */
.ld-sm-arrow {
  flex: 0 0 auto;
  font-size: 16px;
  line-height: 1;
  color: var(--muted);
  opacity: .7;
}
/* 分隔线（Win7 各块之间的横线） */
.ld-sm-sep {
  flex-shrink: 0;
  height: 0;
  margin: 4px 2px;
  border-top: 1px solid var(--line);
}
/* 搜索无结果 */
.ld-sm-empty {
  padding: 10px 8px;
  color: var(--muted);
  font-size: 16px;
  text-align: center;
}
/* 用户名行（右列的"固定头"）：`flex: 0 0 auto` → 高度不够时它不参与收缩（只让中间那段滚） */
.ld-sm-user {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  justify-content: center;   /* 2026-10-20 用户：顶部账号文字居中，不要左对齐 */
  padding: 2px 2px 4px;
  font-size: 16px;
  font-weight: 800;
  color: var(--text);
}
.ld-sm-user-tx {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
/* 主题下拉（克隆自 #themeSelect，等宽于右栏） */
.ld-sm-select {
  width: 100%;
  box-sizing: border-box;
  height: 32px;
  padding: 0 8px;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: color-mix(in srgb, var(--panel) 86%, var(--bg-deep) 14%);
  color: var(--text);
  font-family: inherit;
  font-size: 16px;
  font-weight: 700;
  outline: none;
  cursor: pointer;
  flex-shrink: 0;
}
.ld-sm-select:focus {
  border-color: var(--primary);
  box-shadow: 0 0 0 3px var(--primary-soft);
}
.ld-sm-select option { background: var(--panel); color: var(--text); }
/* 「所有程序」按钮（Win7 左下角同款，钉在左列内嵌区底部、搜索框上面）：点开＝左列列出全部设置项。
   2026-09-16 用户定稿：常态即整按钮高亮（不是细亮条），高亮＝主题辅色 --accent-2 的 5%，
   不加高亮边框；hover 自动加深（底色 +12 → 17%）。圆角 8px 与卡内其它控件一致。 */
.ld-sm-allprog {
  flex-shrink: 0;
  width: 100%;
  box-sizing: border-box;
  /* 30 → **32px**：与浮层里其余可点行/按钮同一档（2026-09-24 第 45 轮用户："这个按钮高度给它设置成32px"）。 */
  min-height: 32px;
  padding: 0 8px;
  display: flex;
  align-items: center;
  gap: 7px;
  border: 1px solid transparent;
  border-radius: 8px;
  background: color-mix(in srgb, var(--accent-2) 5%, transparent);
  color: var(--text);
  font-family: inherit;
  font-size: 16px;
  font-weight: 700;
  text-align: left;
  cursor: pointer;
}
.ld-sm-allprog:hover {
  background: color-mix(in srgb, var(--accent-2) 17%, transparent);
  border-color: color-mix(in srgb, var(--accent-2) 12%, transparent);
  color: var(--accent-2);
}
.ld-sm-allprog-tx {
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.ld-sm-allprog-arrow { flex: 0 0 auto; font-size: 16px; opacity: .75; }
/* ── 浅色主题套（2026-09-16 用户：两套对应调换 —— 系统浅色主题改用「暗影黑」那套，
   深色主题改用「默认」那套＝站点默认深青，见上方基底块）
   浅色主题＝轻雅蓝 lightblue / 暖色纸 shuimo / 金秋色 jinqiu / 樱花粉 yinghuafen / 活力橙 huolicheng。
   ① 颜色：面层变量整组钉成「暗影黑」（themes.css 的 anhei）原值，文字同时翻成浅色（白字）。
   ② 参数（配置台暗影黑套）：底色锚定 --panel 不混色、浓度 80%、模糊 8px、边框对比 0（直接用 --line）、
      左容器 bd26 / a30 / r0 / sh.26；「所有程序」高亮两套相同（辅色 5%、不加边），无需覆盖。 ── */
html[data-theme="lightblue"] .ld-settings-float,
html[data-theme="shuimo"] .ld-settings-float,
html[data-theme="jinqiu"] .ld-settings-float,
html[data-theme="yinghuafen"] .ld-settings-float,
html[data-theme="huolicheng"] .ld-settings-float {
  /* 颜色：底色＝「暗影黑」半透明黑玻璃 */
  --panel: rgba(16, 21, 31, .92);
  --bg-deep: #03060d;
  --line: rgba(96, 165, 250, .14);
  --accent-2: #60a5fa;
  /* 文字/高亮一并翻成浅色，避免深底配深字 */
  --text: #f2f6ff;
  --muted: #8e9bb3;
  --primary: #00d6b9;
  --primary-soft: rgba(0, 214, 185, .14);
  /* 参数：浓度 80% / 模糊 8px（深色套为 78% / 9px） */
  background-color: color-mix(in srgb, var(--panel) 80%, transparent);
  -webkit-backdrop-filter: blur(8px) saturate(128%);
  backdrop-filter: blur(8px) saturate(128%);
}
/* 同上，给「开始菜单右列分组贴出面板」也钉一遍（2026-09-18）：面板挂 body、不在卡片里，
   拿不到 `.ld-settings-float` 上的变量覆盖 → 不写这组，浅色主题下面板会配成另一套色，与卡片不一致。
   （「选择项目」浮层贴到开始菜单里时同样并列进来。） */
html[data-theme="lightblue"] .smbg-menu.ld-sm-pop,
html[data-theme="shuimo"] .smbg-menu.ld-sm-pop,
html[data-theme="jinqiu"] .smbg-menu.ld-sm-pop,
html[data-theme="yinghuafen"] .smbg-menu.ld-sm-pop,
html[data-theme="huolicheng"] .smbg-menu.ld-sm-pop,
html[data-theme="lightblue"] .ld-ppick-panel.ld-sm-pick,
html[data-theme="shuimo"] .ld-ppick-panel.ld-sm-pick,
html[data-theme="jinqiu"] .ld-ppick-panel.ld-sm-pick,
html[data-theme="yinghuafen"] .ld-ppick-panel.ld-sm-pick,
html[data-theme="huolicheng"] .ld-ppick-panel.ld-sm-pick {
  --panel: rgba(16, 21, 31, .92);
  --bg-deep: #03060d;
  --line: rgba(96, 165, 250, .14);
  --accent-2: #60a5fa;
  --text: #f2f6ff;
  --muted: #8e9bb3;
  --primary: #00d6b9;
  --primary-soft: rgba(0, 214, 185, .14);
  background-color: color-mix(in srgb, var(--panel) 80%, transparent);
  -webkit-backdrop-filter: blur(8px) saturate(128%);
  backdrop-filter: blur(8px) saturate(128%);
}
html[data-theme="lightblue"] .ld-sm-left,
html[data-theme="shuimo"] .ld-sm-left,
html[data-theme="jinqiu"] .ld-sm-left,
html[data-theme="yinghuafen"] .ld-sm-left,
html[data-theme="huolicheng"] .ld-sm-left {
  /* 左容器 bd26 / a30 / sh.26（深色套为 bd20 / a20 / .22） */
  border-color: color-mix(in srgb, var(--accent-2) 26%, transparent);
  background: color-mix(in srgb, var(--bg-deep) 30%, transparent);
  box-shadow: inset 0 1px 6px rgba(0, 0, 0, .26);
}
/* 搜索框：包在左列内嵌区的最底部（Win7 左下「搜索程序和文件」位），圆角与「所有程序」按钮一致 */
.ld-sm-q-wrap { position: relative; display: flex; align-items: center; flex-shrink: 0; }
/* 2026-09-18 起「选择项目」贴出浮层顶部那个"搜索项目…"也套这一份（用户要求贴出的样式与开始菜单一致） */
.ld-sm-q,
.ld-ppick-panel.ld-sm-pick .ld-ppick-search {
  width: 100%;
  box-sizing: border-box;
  height: 32px;
  padding: 0 12px;   /* 2026-09-17 用户去掉右侧放大镜图标 → 右侧内边距 30px 收回 12px，左右对称 */
  border: 1px solid color-mix(in srgb, var(--accent-2) 18%, var(--line));
  border-radius: 8px;
  background: color-mix(in srgb, var(--bg-deep) 30%, transparent);
  color: var(--text);
  font-family: inherit;
  font-size: 16px;
  outline: none;
}
.ld-sm-q::placeholder,
.ld-ppick-panel.ld-sm-pick .ld-ppick-search::placeholder { color: var(--muted); }
.ld-sm-q:focus,
.ld-ppick-panel.ld-sm-pick .ld-ppick-search:focus {
  border-color: color-mix(in srgb, var(--accent-2) 65%, transparent);
  background: color-mix(in srgb, var(--bg-deep) 46%, transparent);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent-2) 16%, transparent);
}
/* （2026-09-18 移除）原此处单独给"开始菜单里那份项目列表"设 gap:3px ——
   现在三处（开始菜单 / Alt+Q 弹窗 / 管理工作左上角）统一 6px，见 `.ld-ppick-panel .ld-ppick-list`。 */
/* （2026-09-17 移除）原 `.ld-sm-q-ic`（搜索框右侧放大镜图标）—— 用户要求去掉，DOM 与样式一并删除 */
/* 2026-09-28 用户："在搜索框的右边放一个回车的那个回转那个形状" ⇒ 右侧一枚 ⏎（回车 = 走网络搜索）。
   ⚠ 只给开始菜单这一份 `.ld-sm-q` 留右侧位置；与它共用上面那条 padding 的「搜索项目…」(.ld-ppick-search)
     没有这枚图标，所以这里单开一条覆盖，不动上面那条共用规则。 */
.ld-sm-q { padding-right: 30px; }
.ld-sm-q-wrap > .ld-sm-q-enter {
  position: absolute; right: 9px; top: 50%; transform: translateY(-50%);
  font-size: 15px; line-height: 1; color: var(--muted);
  pointer-events: none; user-select: none;
}
.ld-sm-q-wrap > .ld-sm-q:focus ~ .ld-sm-q-enter { color: color-mix(in srgb, var(--accent-2) 85%, var(--text)); }

/* 退出登录：低调按钮，沉在右列底部（对应 Win7 右下「关机」），hover 才亮起来 */
.ld-sm-power {
  margin-top: auto;   /* 推到底部 */
  flex: 0 0 auto;
  width: 100%;
  box-sizing: border-box;
  min-height: 32px;
  padding: 0 14px;
  display: flex;
  align-items: center;
  justify-content: center;
  border: 1px solid color-mix(in srgb, var(--text) 14%, transparent);
  border-radius: 8px;
  background: color-mix(in srgb, var(--text) 6%, transparent);
  color: var(--muted);
  font-family: inherit;
  font-size: 16px;
  font-weight: 700;
  text-align: center;   /* 2026-10-20：底部按钮（退出登录 / 登录 / 注册）文字居中 */
  cursor: pointer;
  transition: background-color .16s ease, border-color .16s ease, color .16s ease;
}
/* 2026-09-18 用户："开始菜单上面鼠标经过的高亮条统一成蓝色玻璃" —— 退出登录是右列最后一行，
   悬停也一并统一（否则整列里只有它是青绿）。 */
.ld-sm-power:hover,
.ld-sm-power:focus-visible {
  border-color: rgba(120, 190, 255, 0.9);
  background: rgba(74, 158, 255, 0.15);
  color: var(--text);
}

/* 主页按钮：文字「主页」图标区（与箭头同组同框，桌面/移动端一致，2026-09-04） */
.ldg-topstep-btn .ldg-topstep-homeic {
  display: inline-flex;
  align-items: center;
  justify-content: center;
}
.ldg-topstep-btn .ldg-topstep-homeic svg {
  display: block;
}


/* 智慧管理·主页空白页（2026-09-05：HOME 按钮进入的主入口占位；背景壁纸由 JS 在线加载并写入浏览器缓存，底色深色兜底） */
#智慧管理 .sm-home-blank {
  flex: 1;
  min-width: 0;
  min-height: 0;
  position: relative;
  background-color: #0e1520;
  background-size: cover;
  background-position: center;
  background-repeat: no-repeat;
}
/* 主页空白页壁纸全屏铺满（2026-09-05）：HOME 进入时撤销 .main 内边距，消除上下左缝隙 */
body.ld-home-full .main { padding: 0 !important; }

/* 刷新首帧即主页（2026-09-05）：head 内联脚本读 localStorage 给 html 加 ldg-home-start，
   刷新后首帧直接显示主页、隐藏 AI 中心，不再闪对话页（!important 覆盖 #smHomeBlank 的内联 display:none）。 */
html.ldg-home-start #smHomeBlank { display: block !important; }
html.ldg-home-start .ai-center { display: none !important; }
html.ldg-home-start .main { padding: 0 !important; }

/* 主页空白页兜底深色渐变（2026-09-05）：刷新后首帧即深色，避免壁纸异步加载期间闪白屏；
   壁纸加载完成后 .cover 背景图整块覆盖其下、完全遮住兜底色。 */
#smHomeBlank {
  position: relative; /* 8 桌面切换条(.sm-desk-sw)绝对定位基准（2026-09-08） */
  background-color: #0c0f16;
  background-image: radial-gradient(120% 120% at 50% 40%, #1a2233 0%, #0b0e15 60%, #07090d 100%);
  background-size: cover;
  background-position: center;
  overflow: hidden; /* 2026-09-07 用户：图标滚动在 #smHomeIcons 层内，本层裁掉溢出，绝不顶动整页/壁纸 */
}

/* 8 桌面切换条（2026-09-08 用户）：视觉对齐"标准二级导航/↑↓ 箭头按钮"（同 .ldg-topstep-btn：
   面板底+细边框+圆角12+高41；hover 描边变主色），右缘避让右侧 ↑↓ 箭头区（offset 由 JS 动态给）。 */
#smDeskSwitch {
  position: absolute;
  top: 18px; /* 顶部=18px（2026-09-03 顶部规则：布局坐标直接写死常量，不读 getBoundingClientRect，
                避免 html zoom 下视觉/布局坐标换算偏差）；与右侧 ↑↓ 箭头同一顶部口径 */
  right: 14px; /* 默认；检测到 ↑↓ 箭头(.ldg-topstep-wrap)显示时改为其左缘外侧（2026-09-08） */
  z-index: 900;
  display: flex;
  align-items: center;
  gap: 8px;
  user-select: none;
  flex-wrap: nowrap;
  /* 2026-09-11 用户：桌面数最多 20 → 展开时按钮可能超出可视宽度，本条约横向滚动
     （max-width 由 JS 按"宿主宽 - 右缘避让"写入；滚动条隐藏以保持 41px 条高不撑高） */
  overflow-x: auto;
  overflow-y: hidden;
  scrollbar-width: none;
}
#smDeskSwitch::-webkit-scrollbar { display: none; }
/* 收起态（日常）：只留"当前桌面"数字钮常显（我在几号一目了然），其余钮收起；
   鼠标移到右上钮区宽度×60 高热区 → 全部显示（2026-09-08 用户） */
#smDeskSwitch.ldg-desk-sw-hide .sm-desk-sw { display: none; }
#smDeskSwitch.ldg-desk-sw-hide .sm-desk-sw.on { display: inline-flex; }
/* 收起态当前钮：不高亮（2026-09-08 用户：常显数字不要亮/高亮，展开时才有主色高亮） */
#smDeskSwitch.ldg-desk-sw-hide .sm-desk-sw.on {
  background: var(--panel);
  border-color: var(--line);
  color: var(--text);
  box-shadow: none;
}
/* （2026-09-08 Bug #36）原此处曾强制"手机/平板收起态不生效、始终全部常显"
   （html.ld-device-mobile/tablet 下收起态改 display:inline-flex）。那是因为 JS 只有
   mousemove 悬停判定、触摸设备没有触发源才做的权宜之计。现 lingdu-core-monitor.js
   已补 touchstart 热区判定（点右上热区展开 / 5 秒无触摸收起），移动端恢复与电脑端
   一致的收起态：日常只显示当前桌面号钮。此规则禁止再加回。 */
#smDeskSwitch .sm-desk-sw {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 41px;                 /* 同二级导航按钮高度；数字 41×41 */
  height: 41px;
  padding: 0;
  border-radius: 12px;
  border: 1px solid var(--line);
  background: var(--panel);
  color: var(--text);
  /* ★ 2026-10-15 用户："其他页面的二级导航按钮的字体是不是改成 19 了？我记得现在好像是 19，
     那我们这个数字也改成 19。" ⇒ 15 → **19px**（与标准二级导航 `.project-group-tab`
     `lingdu.css:2687` / `.mat-tab` / `.stl-group-tab` 同一口径；按钮 41×41、`line-height:1`
     不变 ⇒ 两位数（10~20）也放得下、且仍精确居中）。 */
  font-size: 19px;
  font-weight: 700;
  line-height: 1;
  cursor: pointer;
  user-select: none;
  flex-shrink: 0;
  transition: background .2s, color .2s, border-color .2s, box-shadow .2s;
}
#smDeskSwitch .sm-desk-sw:hover {
  background: var(--primary-soft);
  border-color: var(--primary);
  color: var(--primary);
}
#smDeskSwitch .sm-desk-sw.on {
  background: var(--primary, #4a9eff);
  border-color: var(--primary, #4a9eff);
  color: #fff;
  box-shadow: 0 2px 8px rgba(74, 158, 255, .45);
}

/* 注（2026-09-08 Bug #34）：曾在此处给手机/平板把 .sm-desk-sw 压到 30px，注释称"同 ↑↓
   箭头设备差异化口径"，但实际 .ldg-topstep-btn 与二级导航按钮在 html.ld-device-* 下并无
   压缩规则（仍 41px）→ 桌面 5 钮在移动端明显比标准按钮小。按用户定稿去掉该压缩，
   全设备统一 41×41、圆角12、字号15，与 ↑↓ 箭头/二级导航按钮同口径。 */

/* ── 全部桌面总览（2026-09-08 用户：不是弹窗——原地铺满整个视口，2×2 4 个"画面"；
     格子自身按实际画面比例（16:9 / 16:10 / 4:3…）由 JS 定宽高，整体在视口内居中；
     桌面名做在每格右下角角标；点击画面切换过去）
     2026-09-11 用户：桌面数 4~20 → 保持"每页 2×2 不变"，页面纵向堆叠、上下连续滚动；
     左右边缘隐形热区点击一次翻一页；末页不足 4 个补"空展位"）── */
.ldg-deskall-ov {
  position: fixed;
  inset: 0;
  z-index: 9490;
  box-sizing: border-box;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 20px;
  padding: 6px;
  overflow-y: auto;      /* 多页时纵向连续滚动 */
  overflow-x: hidden;
  overscroll-behavior: contain;
  background: #05070b;   /* 画面墙缝隙底色 */
}
/* 一页 = 2×2 四个展位（列/行尺寸由 JS 按画面比例写入） */
.ldg-deskall-page {
  display: grid;
  gap: 20px;
  flex: none;
}
/* 空展位：末页不足 4 个时占位（例如 5 个桌面 → 第 2 页左上角 1 个 + 其余三个空展位） */
.ldg-deskall-empty {
  background: rgba(255, 255, 255, .03);
  border: 1px dashed rgba(255, 255, 255, .10);
  border-radius: 10px;
  pointer-events: none;
}
/* 左右隐形翻页热区：覆盖视口左右边缘、点击翻一页；宽度固定 120px（2026-09-11 用户：80→120）。
   层叠在画面格之上，保证边缘可靠点击（右下角桌面名角标被它挡住属预期，可用「多桌面设置」改名）。
   翻页为**循环**（首页再往前=末页、末页再往后=首页）→ 不设"到头禁用"状态，两侧始终可点；
   只有整页数=1 时由 JS 把两侧 display:none。 */
.ldg-deskall-hot {
  position: fixed;
  top: 0;
  bottom: 0;
  width: 120px;         /* JS 会写同值宽度；此处兜底 */
  z-index: 2;
  cursor: pointer;
  background: transparent;   /* 隐形：不显示按钮 */
  user-select: none;
}
.ldg-deskall-hot-left { left: 0; }
.ldg-deskall-hot-right { right: 0; }
.ldg-deskall-cell {
  position: relative;
  z-index: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 10px;
  overflow: hidden;
  cursor: pointer;
  user-select: none;
  background: transparent; /* 2026-09-08 用户：不要底层外框/卡片底色，画面直接呈现 */
  border: none;
  color: var(--text, #e8ecf4);
  animation: ldgPanelIn 0.15s ease; /* 0.15s 淡入（2026-09-08 用户；ease 比 ease-out 更利落） */
}
.ldg-deskall-cell:hover {
  box-shadow: inset 0 0 0 2px rgba(74, 158, 255, .55);
}
/* 当前桌面：选中框与画面一样大、一样圆角（outline 贴合 border-radius），外发光（2026-09-08） */
.ldg-deskall-cell.on {
  outline: 4px solid var(--primary, #4a9eff); /* 2026-09-08 用户：加粗 1px */
  outline-offset: 0;
  box-shadow: 0 0 24px 3px rgba(74, 158, 255, .55), 0 0 60px 6px rgba(74, 158, 255, .25);
}
/* 画面内容：真实桌面 DOM 缩放聚合（2026-09-08 用户：不再手绘，直接聚合真实桌面） */
.ldg-deskall-frame,
.ldg-deskall-stage,
.ldg-deskall-desk,
.ldg-deskall-frame * {
  pointer-events: none; /* 画面只是预览：鼠标(含右键)一律落回格子，右键重命名不受阻挡（2026-09-08） */
}
.ldg-deskall-frame {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
  padding: 0;
  box-sizing: border-box;
}
.ldg-deskall-stage {
  position: relative;
  overflow: hidden;
}
.ldg-deskall-desk {
  position: absolute;
  left: 0;
  top: 0;
}
/* 舞台内真实图标禁用悬停放大/按压等交互感（画面层 pointer-events none 已兜底） */
.ldg-deskall-desk .sm-desk-icon:hover,
.ldg-deskall-desk .sm-desk-icon:active {
  transform: none;
}
.ldg-deskall-item {
  position: absolute;
  display: flex;
  align-items: center;
  justify-content: center;
}
.ldg-deskall-item.grp {
  border-radius: 6px;
  background: rgba(127, 127, 127, .14);
  border: 1px solid rgba(255, 255, 255, .10);
}
.ldg-deskall-mic,
.ldg-deskall-gic {
  line-height: 1;
  text-shadow: 0 1px 2px rgba(0, 0, 0, .6);
}
.ldg-deskall-fic.url {
  background-size: contain;
  background-repeat: no-repeat;
  background-position: center;
  filter: drop-shadow(0 1px 2px rgba(0, 0, 0, .5));
}
/* 桌面名角标：右下角（2026-09-08 用户：文字 20px） */
.ldg-deskall-name {
  position: absolute;
  right: 10px;
  bottom: 8px;
  max-width: calc(100% - 20px);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: 20px;
  font-weight: 600;
  color: #fff;
  background: rgba(8, 12, 20, .55);
  padding: 3px 10px;
  border-radius: 7px;
  pointer-events: none;
}
/* 2026-09-08 用户：双击名称=就地重命名 → 名称角标可双击（去掉 pointer-events:none 让双击落角标）：
   hover 给虚线框提示可改名；dblclick 前不拦单击（单击仍冒泡给格子=移动选择框）。 */
.ldg-deskall-cell .ldg-deskall-name {
  pointer-events: auto;
  cursor: text;
}
.ldg-deskall-cell .ldg-deskall-name:hover {
  outline: 1px dashed rgba(255, 255, 255, .45);
  outline-offset: -1px;
}
/* 就地改名输入框：原位替换角标，外观延续角标胶囊（2026-09-08） */
.ldg-deskall-name-input {
  position: absolute;
  right: 10px;
  bottom: 8px;
  width: 180px;
  box-sizing: border-box;
  font-size: 20px;
  font-weight: 600;
  color: #fff;
  background: rgba(8, 12, 20, .8);
  border: 1px solid var(--primary, #4a9eff);
  border-radius: 7px;
  padding: 2px 8px;
  outline: none;
  z-index: 2;
  user-select: text;
}
.ldg-deskall-name-input::selection {
  background: rgba(74, 158, 255, .35);
}
/* 2026-09-08 Bug #35：手机/平板软键盘弹出会盖住 cell 右下角输入框（fixed 原位不可滚出）→
   触屏设备改名输入框改为 fixed 居中偏上（键盘弹出后仍可见可输入）；桌面保持原位角标样式 */
html.ld-device-mobile .ldg-deskall-name-input,
html.ld-device-tablet .ldg-deskall-name-input {
  position: fixed;
  left: 50%;
  top: 34%;
  right: auto;
  bottom: auto;
  transform: translateX(-50%);
  width: min(320px, calc(100vw - 40px));
  font-size: 18px;
  padding: 8px 12px;
  border-radius: 10px;
}

/* 桌面图标（2026-09-05：模仿 Windows 桌面，图标图 + 文字标签，单击打开一级导航模块） */
.sm-desk-icon {
  position: absolute;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 11px; /* 图标与文字间距 +5px（2026-09-05） */
  padding: 8px 4px;
  border-radius: 8px;
  cursor: pointer;
  user-select: none;
  z-index: 2;
  transition: transform 0.12s ease;
  transform-origin: center;
}
.sm-desk-icon:hover {
  transform: scale(1.05); /* 2026-09-07 用户：悬停放大 1.15→1.08→1.05（更克制，减少跳动感） */
}
.sm-desk-icon:active {
  transform: scale(1.1);
}
/* 2026-09-13 用户：**单击打开**档的图标，鼠标经过也亮起"透明玻璃"背景 ——
   装饰与选中态 `.sm-desk-icon.sel` 完全一致（同底色同描边），两种状态看到的"亮"是同一个。
   原因：单击档点一下就打开、没有"已选中"的停留态，用悬停同款玻璃补上这个视觉反馈。
   2026-09-14 用户：打开方式**按图标类型分两档**（本地图标 / 网络图标）→ 不再用"桌面根上一个总开关类"，
   改由 JS 给**每个图标**挂 `ldg-icon-single`（单击档才挂，见 lingdu-core-monitor.js `_deskSyncIconOpenMode()`
   与 renderIcons 建元素处）；双击档不挂 → 维持"第 1 次点击才亮、悬停不亮"的现状。 */
#smHomeBlank .sm-desk-icon.ldg-icon-single:hover {
  background: rgba(74, 158, 255, 0.15);
  outline: 1.5px solid rgba(120, 190, 255, 0.9);
  outline-offset: -1px;
}
/* 2026-09-18 用户："自由模式下，图标拖动时让所有图标都有一个蓝色高亮背景，这样更方便对齐" ——
   拖动期间（仅「图标自由对齐」档，由 JS 给图标层挂 .ldg-align-glass）把**单图标一律点亮**
   桌面那套蓝玻璃（同 `.sm-desk-icon.sel` / `:hover` 的底色与描边）→ 每个图标的"盒子"边界都看得见。
   ⚠ **大图标组（.grp-big）与网络搜索框**本身就有可见外框，不参与；
   ⚠ 小图标组（.grp-small）2026-09-20 起**参与**（用户："自由图标的时候 拖动一个图标 其余图标的
     外蓝色玻璃都亮起来，但是小图标组没有亮"）→ 见下面单独那条（它有自己的选中态 !important 要盖）；
   ⚠ 排除"可并入的目标高亮"（.sm-desk-icon-drop 的蓝色虚框），否则拖动成组的目标提示会被本规则盖掉；
   ⚠ 被拖动的图标此刻被"抬"到 body 下、不在图标层内 → 天然不点亮（它跟着鼠标，不需要参照）。 */
#smHomeBlank.ldg-align-glass .sm-desk-icon:not(.grp-big):not(.grp-small):not(.sm-desk-websearch):not(.sm-desk-icon-drop) {
  background: rgba(74, 158, 255, 0.15);
  outline: 1.5px solid rgba(120, 190, 255, 0.9);
  outline-offset: -1px;
}
/* 同上的参照层里，**小图标组**点亮在**整块瓦片外体**上（与它"悬停 / 框选 / 拖动"的口径统一）。
   ⚠ 必须 `!important`：小图标组的选中态有一条 `!important` 把瓦片压成透明、玻璃只落内箱
     （见上面 `.sm-desk-icon.sm-grp-prev.sel` 那段）→ 不带 !important 会被它压掉，等于没亮。
   ⚠ 外框亮 ⇒ 内箱不亮（同它的悬停/框选口径）。 */
#smHomeBlank.ldg-align-glass .sm-desk-icon.sm-grp-prev.grp-small {
  background: rgba(74, 158, 255, .15) !important;
  outline: 1.5px solid rgba(120, 190, 255, .9) !important;
  outline-offset: -1px !important;
}
#smHomeBlank.ldg-align-glass .sm-desk-icon.sm-grp-prev.grp-small .sm-grp-prevbox {
  background: transparent;
  outline: none;
}
/* 2026-09-14 远程演示：桌面图标的悬停反馈（放大 + 单击档的"玻璃背景"）也要能在观看端复刻 ——
   `:hover` 是按**本机指针**算的，观看端的指针并不在你悬停的那个图标上，永远不成立，
   所以演示端把"悬停在哪个图标"（`data-icon-id`）发过去，观看端挂 `.ldp-hover`，这里让两者**等效**。
   ⚠ 以后给桌面图标加悬停样式，记得同步补一条 `.ldp-hover` 规则；并注意"分档类"要一起带上。 */
.sm-desk-icon.ldp-hover { transform: scale(1.05); }
#smHomeBlank .sm-desk-icon.ldg-icon-single.ldp-hover {
  background: rgba(74, 158, 255, 0.15);
  outline: 1.5px solid rgba(120, 190, 255, 0.9);
  outline-offset: -1px;
}
/* 重命名中：临时屏蔽悬停/按压放大，避免鼠标经过时图标跳动干扰输入（2026-09-06 用户） */
.sm-desk-icon.sm-renaming,
.sm-desk-icon.sm-renaming:hover,
.sm-desk-icon.sm-renaming:active {
  transform: none !important;
}
.sm-desk-icon-img {
  font-size: 38px;
  line-height: 1;
  filter: drop-shadow(0 2px 4px rgba(0, 0, 0, 0.5));
}
/* 本地文件真实图标（2026-09-07 任务①）：Windows 同款 PNG 铺满图标位（宽高由 JS 按尺寸档写入） */
.sm-desk-icon-imgurl {
  display: inline-block;
  background-size: contain;
  background-repeat: no-repeat;
  background-position: center;
  filter: drop-shadow(0 2px 3px rgba(0, 0, 0, 0.45));
}
.sm-desk-icon-label {
  font-size: 12px;
  color: #fff;
  text-align: center;
  text-shadow: 0 1px 3px rgba(0, 0, 0, 0.9);
  word-break: break-all;
  line-height: 1.25;
}
/* ── 桌面「网络搜索」框图标（2026-09-16 用户定稿 H 方案·玻璃胶囊 760×80）───────
   尺寸由 JS 写入（见 _deskBuildWebSearchEl），**本质仍是一个图标**：可拖动/删除/找回（同内置固定图标）。
   一行排布：**固定的系统 logo**（同导航栏左上角；点它换搜索引擎）+ 输入框（灰字「输入并搜索」）
   + 有内容时出现的清除 X + 右端简约放大镜（点它＝搜索）。
   摆放按"图标组"那套自由摆放（不吸网格），见 JS mousedown 的 drag.big。
   ⚠ 覆盖 .sm-desk-icon 的"竖排 + 悬停放大"——输入/点 logo 时框一跳就点不准。 */
.sm-desk-icon.sm-desk-websearch {
  flex-direction: row;
  align-items: center;
  gap: 16px;
  padding: 0 9px 0 5px;                                  /* +1px 边框 = logo 距框左边缘 6px、右侧文字距右边 10px（2026-09-16 用户） */
  border-radius: 999px;
  background: rgba(12, 20, 34, 0.29);                    /* 2026-09-16 用户两次「再透 30%」：0.58→0.41→0.29；弹窗另有其值 */
  border: 1px solid rgba(120, 190, 255, 0.30);
  box-shadow: 0 8px 22px rgba(0, 0, 0, 0.38), inset 0 1px 0 rgba(255, 255, 255, 0.09);
  backdrop-filter: blur(8px) saturate(1.25);             /* 玻璃：背后的壁纸透出来一点（2026-09-16 用户：有点糊 → 模糊 12→8，清晰度约 +30%） */
  -webkit-backdrop-filter: blur(8px) saturate(1.25);
  cursor: move;
}
.sm-desk-icon.sm-desk-websearch:hover,
.sm-desk-icon.sm-desk-websearch:active {
  transform: none;
}
/* 左端图标按钮：里面放一枚**固定的系统 logo**（克隆自导航栏左上角，见 _ldBrandLogoHtml）；
   点它仍是"换搜索引擎"的入口。图标 60×60、无底色 —— logo 本身自带描边/字色，
   颜色随主题（lingdu-core.js 的 updateLogoColors 已登记 wsLogoRing/wsLogoCoreCircle）。 */
.sm-desk-websearch-logo {
  flex: none;
  display: grid;
  place-items: center;
  padding: 0;
  border: none;
  background: transparent;
  cursor: pointer;
}
.sm-desk-websearch-logo svg {
  display: block;
  width: 69px;      /* 60 × 1.15：放大 15%（2026-09-16 用户）→ 80 高的框里上下各留 ≈5.5px */
  height: 69px;
}
.sm-desk-websearch-logo:hover svg {
  filter: brightness(1.15);
}
/* ★ 2026-10-02 用户："搜索栏左边那枚 logo 要变成**当前搜索引擎的图标** —— 我切换成谁就显示谁的，
   图标正常显示，但**按圆形裁出来**，不然不知道现在用的是哪个引擎。"
   ⇒ chip 里现在装的是引擎标 `.ldg-eng-logo`（**与引擎面板同一份画法**：内置 8 个=品牌色+首字，
     自定义引擎=该站真图标）。这里**只覆盖"搜索栏左端"这一处作用域** ——
     面板里那枚仍是原来的方形圆角 18px，一个像素都不动。
   尺寸 60（框高 80，上下各留 10）；"圆形切出来"= border-radius:50% + overflow:hidden，
   再把自定义引擎那层真图标（面板里是 48px `contain`）改成**铺满 + cover** ⇒ 方图被圆裁掉四角。 */
.sm-desk-websearch-logo .ldg-eng-logo {
  width: 60px;
  height: 60px;
  border-radius: 50%;
  overflow: hidden;
  font-size: 27px;
}
.sm-desk-websearch-logo .ldg-eng-logo > img.ldg-eng-fav {
  left: 0;
  top: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.sm-desk-websearch-logo:hover .ldg-eng-logo {
  filter: brightness(1.15);
}
.sm-desk-websearch-inp {
  /* ★ 2026-10-02 用户："文字输入非常多的时候会往左挤，但到最右边时**始终有几个字被裁掉**、
     没挤到最右边。" ⇒ 宽度改成**严格按分配值**：`flex-basis` 由 `auto` 改 `0` + `width:0`
     —— 原来 basis=auto 时基准宽度取 input 自身的固有宽度（`size` 属性那 ~20 字符），
     在整页自适应缩放（html zoom）下这个固有宽度与最终渲染宽度会差几个像素 ⇒
     浏览器算出的"可滚动范围"比实际小 ⇒ 末尾就是有那么几个字滚不出来。
     配套：JS 在输入事件里把滚动推到末尾（见两个搜索框的 `inp.scrollLeft = inp.scrollWidth`）。 */
  flex: 1 1 0;
  width: 0;
  min-width: 0;
  height: 48px;
  padding: 0;
  border: none;
  outline: none;
  background: transparent;
  color: #fff;
  font-size: 26px;
}
.sm-desk-websearch-inp::placeholder {
  color: rgba(255, 255, 255, 0.55);
}
/* 「清除输入内容」X（2026-09-16 用户）：夹在输入框与放大镜之间，**输入框有内容时才出现**
   （显隐由 JS 的 syncClr 挂 .on，见 _deskBuildWebSearchEl）；图标 26px ＝ 与输入框文字同大。
   纯线条、无底色；隐藏时 display:none → 不占 flex 槽位（不显示时输入框保持原本的宽度）。 */
.sm-desk-websearch-clr {
  flex: none;
  width: 40px;
  height: 40px;
  padding: 0;
  border: none;
  border-radius: 50%;
  background: transparent;
  color: rgba(255, 255, 255, 0.55);
  display: none;
  place-items: center;
  cursor: pointer;
  transition: color 0.18s ease, background 0.18s ease;
}
.sm-desk-websearch-clr.on {
  display: grid;
}
.sm-desk-websearch-clr:hover {
  color: rgba(255, 255, 255, 0.95);
  background: rgba(255, 255, 255, 0.08);
}
.sm-desk-websearch-clr:active {
  transform: scale(0.94);
}
.sm-desk-websearch-clr svg {
  display: block;
}
/* 右端「简约放大镜」（2026-09-16 用户）：纯线条 SVG、无底色，点它＝搜索（与回车同一条路）。
   线条色走 currentColor → 只改 color 就能调明暗；hover 只提亮 + 极淡底，不做填充/描边方块。 */
.sm-desk-websearch-mag {
  flex: none;
  width: 40px;
  height: 40px;
  padding: 0;
  border: none;
  border-radius: 50%;
  background: transparent;
  color: rgba(255, 255, 255, 0.55);
  display: grid;
  place-items: center;
  cursor: pointer;
  transition: color 0.18s ease, background 0.18s ease;
}
.sm-desk-websearch-mag:hover {
  color: rgba(255, 255, 255, 0.92);
  background: rgba(255, 255, 255, 0.08);
}
.sm-desk-websearch-mag:active {
  transform: scale(0.94);
}
.sm-desk-websearch-mag svg {
  display: block;
}
/* ══ 全局快速搜索浮层（Alt+A 呼出；2026-10-01 用户）═══════════════════════════════════════
   UI **原样复用**上面那套桌面「网络搜索框」（`.sm-desk-icon.sm-desk-websearch` + 四个子件），
   这里只补三件事，**不复制任何视觉值**（尺寸/配色/圆角/图标全由上面那些 class 提供）：
     ① `.ldg-qs`       = 透明承载层（**不铺遮罩、不挡鼠标**：浮层"始终显示"，只有 Alt+A 能关）；
     ② `.ldg-qs-bar`   = 覆盖桌面那套的"绝对定位 + cursor:move 可拖" ⇒ 改成屏幕水平居中、不可拖；
     ③ `.ldg-qs-res`   = 结果区（玻璃卡片；行本身复用开始菜单的 `.ld-sm-item`，不另造行样式）。
   ⚠ 选择器用 `.ldg-qs .ldg-qs-bar`（两个类）盖过 `.sm-desk-icon.sm-desk-websearch` 那条，保证能覆盖定位。 */
.ldg-qs {
  position: fixed;
  inset: 0;
  z-index: 9999;
  display: none;
  /* ⚠ 2026-10-01 用户定稿："呼出来以后应该**始终显示**，除非再按一次快捷键关掉" ⇒
     ① 不再铺暗色遮罩（那会让页面看着被"模态"盖住，也不符合"常驻"的观感）；
     ② `pointer-events:none` —— **不挡页面操作**（下面搜索条与结果区各自 `pointer-events:auto`）。 */
  background: transparent;
  pointer-events: none;
}
.ldg-qs.on { display: block; }
.ldg-qs .ldg-qs-bar {
  position: fixed;
  left: 50%;
  top: 16%;
  transform: translateX(-50%);
  width: 760px;               /* 与桌面搜索栏同一尺寸（JS 里的 WEBSEARCH_W / H） */
  height: 80px;
  box-sizing: border-box;
  cursor: default;            /* 覆盖 .sm-desk-icon 的 cursor:move —— 浮层里不可拖动 */
  pointer-events: auto;       /* 外层遮罩已是 pointer-events:none ⇒ 搜索条自己接管鼠标 */
}
.ldg-qs .ldg-qs-bar:hover,
.ldg-qs .ldg-qs-bar:active {
  transform: translateX(-50%);   /* 别被 .sm-desk-icon 的悬停放大带跑（那条对搜索框本就设了 none） */
}
.ldg-qs .ldg-qs-res {
  position: fixed;
  left: 50%;
  top: calc(16% + 92px);
  transform: translateX(-50%);
  width: 760px;
  max-height: 46vh;
  overflow: auto;
  display: none;
  pointer-events: auto;       /* 同上：外层不接管鼠标，结果区自己接管 */
  padding: 6px;
  border-radius: 18px;
  background: rgba(12, 20, 34, 0.62);
  border: 1px solid rgba(120, 190, 255, 0.22);
  box-shadow: 0 18px 44px rgba(0, 0, 0, 0.45);
  backdrop-filter: blur(10px) saturate(1.2);
  -webkit-backdrop-filter: blur(10px) saturate(1.2);
}
.ldg-qs .ldg-qs-res .ld-sm-empty {
  padding: 10px 12px;
  font-size: 15px;
  color: rgba(255, 255, 255, 0.7);
}
/* 内联重命名输入框（2026-09-05） */
.sm-desk-icon-input {
  width: 100%;
  font-size: inherit;
  color: #fff;
  text-align: center;
  background: rgba(0, 0, 0, 0.35);
  border: 1px solid var(--primary);
  border-radius: 4px;
  outline: none;
  padding: 2px 0;
}
/* 重命名后缀隔离（2026-09-06 用户）：主名输入框 + 只读后缀并排，后缀改不动 */
.sm-desk-icon-renamebox {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 1px;
  max-width: 100%;
}
.sm-desk-icon-renamebox .sm-desk-icon-input {
  width: auto;
  min-width: 0;
  flex: 0 1 auto;
  padding: 2px 0;
  text-align: center;
}
.sm-desk-icon-ext {
  flex: none;
  white-space: nowrap;
  color: rgba(255, 255, 255, 0.6);
  text-shadow: 0 1px 3px rgba(0, 0, 0, 0.9);
  user-select: none;
}
/* 本地文件图标：本机路径未设置（从其它设备同步过来尚未重设）→ 图标置灰提示（2026-09-06） */
.sm-desk-icon-nopath .sm-desk-icon-img {
  filter: grayscale(0.85);
  opacity: 0.45;
}
/* 桌面图标多选 + 框选（2026-09-07）：Windows 风格选中/候选高亮 + 选框 */
.sm-desk-icon.sel,
.sm-desk-icon.mq-hit {
  background: rgba(74, 158, 255, 0.15);
  outline: 1.5px solid rgba(120, 190, 255, 0.9);
  outline-offset: -1px;
}
/* 已选/候选图标弱化悬停放大（原 1.15），避免拖动框选时图标跳动 */
.sm-desk-icon.sel:hover,
.sm-desk-icon.sel:active,
.sm-desk-icon.mq-hit:hover,
.sm-desk-icon.mq-hit:active {
  transform: scale(1.06);
}
/* 2026-09-20 用户（微调）：**多选（≥2）时临时关掉悬停/按下的放大** ——
   "我选择两个图标一起拖动，选择的时候两个图标是一样大一样齐平的，我按住其中一个开始拖动，此时按住的那个
   由于有 1.05 放大，他会先放大在缩小，但是回正之后，相对位置就有轻微的偏移"。
   为什么放大确实会带出偏移：`:hover` / `:active` 的 scale 让**视觉盒子**与**布局盒子**在那几帧里不是同一个
   东西，而拖动落位、对齐参考线、`_ldDeskDragLift` 的"抬升自校准"全都按**实测 rect**（含缩放）算 →
   抬起与回正之间就露出 1~2px 的差；多选拖动时旁边有参照，一眼就看出来。
   `.ldg-multi` 由 JS 逐图标挂在**选中态**图标上（见 `_deskSetSelCls`，与 .sel/.mq-sel 同一次绘制）：
   未选中图标的悬停反馈、以及**单选**时的悬停放大都不受影响。 */
.sm-desk-icon.sel.ldg-multi:hover,
.sm-desk-icon.sel.ldg-multi:active,
.sm-desk-icon.mq-hit.ldg-multi:hover,
.sm-desk-icon.mq-hit.ldg-multi:active,
.sm-desk-icon.mq-sel.ldg-multi:hover,
.sm-desk-icon.mq-sel.ldg-multi:active {
  transform: none;
}
.sm-desk-marquee {
  position: absolute;
  left: 0;
  top: 0;
  border: 1px solid rgba(120, 190, 255, 0.95);
  background: rgba(74, 158, 255, 0.14);
  border-radius: 2px;
  pointer-events: none;
  z-index: 5;
}


/* 主页背景设置右键菜单（2026-09-05） */
.smbg-menu {
  position: fixed;
  z-index: 6000;
  min-width: 212px;
  box-sizing: border-box;
  padding: 6px;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 12px;
  /* 2026-09-16 用户："壁纸设置弹窗…外圈发光影子去掉" → 弹窗体一律不带投影（也作为全站弹窗统一外观） */
  box-shadow: none;
  user-select: none;
  display: flex;
  flex-direction: column;
  gap: 5px;   /* 2026-09-06 用户：菜单各设置行/条目间距 5px */
  /* 2026-09-18 修（用户实测"组内图标右键重命名点了没反应，F2 就行"）：菜单必须自己声明可点。
     `pointer-events` 是**继承**属性 —— 组浮层的根壳 `.ldg-grp-ov` 是 `pointer-events:none`
     （2026-09-16「弹窗标准」：根壳穿透，开着面板也能点桌面），面板本体自己补了 `auto`，
     而挂进该根壳的右键小菜单（成员「重命名」/ 标题「皮肤」）没补 → 整块菜单继承 `none`：
     **看得见、点不到**，点击直接穿到下面的格子。同项目内 `.font-settings-dialog` 等
     同类弹层也都是"根壳 none + 本体 auto"，这里给出统一兜底（挂 body 的菜单本就是 auto，无副作用）。 */
  pointer-events: auto;
}
/* ── 开始菜单右列「分组贴出面板」（2026-09-18 用户："贴出的样式要和开始菜单自己的样式一样。
   边缘相贴距离，离开 1px，不要重叠。"）────────────────────────────────────
   ① 外观＝**和 .ld-settings-float 同一套玻璃**（底色 78% / 模糊 9px / 边框 var(--line) / 圆角 7px /
      内边距 10px / 行间距 3px＝右列的行距）。这组参数若改动，`.ld-settings-float` 那处要同步。
      ⚠ 行间距例外：「选择项目」那张项目选择浮层是三处共用的一张单例面板（开始菜单 / Alt+Q 弹窗 /
      管理工作左上角），用户要求它一律 6px → 见本块下面单独写的 `.ld-ppick-panel` 两条。
   ② 容器同时带 .smbg-menu（桌面那套"点别处自动收"按它判定，不能少）→ 这里逐项盖掉它的视觉：
      min-width 212 → 自适应内容、padding 6→10、gap 5→3、圆角 12→7、投影 none → 同卡片。
      2026-09-18 追加：开始菜单里贴出的「选择项目」浮层（`#ldPpickPanel`，锚点在卡片里时 JS 会加
      `.ld-sm-pick` 标记）也并列进这一组 —— 用户要求它和显示与亮度等分组贴出面板长得一样。
      （它的固定高 300px / 定位 / 开关由 ld-ppick 自己管，这里只统一外观。）
   ③ 1px 相贴由 JS 定位保证（`_ldShowSubmenuAt` / `pop3At` / ld-ppick 的 `placePanel` 都锚外缘 +1px）。
   ④ 面板内不铺分隔线（与右列一致）；行数最多 14（主题 11 + 3），超高时由定位夹进视口 + 自身滚动。 */
.smbg-menu.ld-sm-pop,
.ld-ppick-panel.ld-sm-pick {
  min-width: 0;
  width: auto;
  max-height: calc(100vh - 36px);
  padding: 10px;
  border-radius: 7px;
  /* 颜色：与开始菜单卡片一致（深色主题＝站点默认深青那套；浅色主题见下方「浅色主题套」） */
  --panel: rgba(7, 34, 43, .88);
  --bg-deep: #031116;
  --line: rgba(113, 232, 238, .18);
  --accent-2: #2dd4ff;
  --text: #e9fdff;
  --muted: #8fc7d0;
  --primary: #10e7df;
  --primary-soft: rgba(16, 231, 223, .16);
  background: var(--panel);   /* 兜底：不支持 color-mix 的浏览器退回主题面板色 */
  background-color: color-mix(in srgb, var(--panel) 78%, transparent);
  -webkit-backdrop-filter: blur(9px) saturate(128%);
  backdrop-filter: blur(9px) saturate(128%);
  border: 1px solid var(--line);
  box-shadow:
    0 14px 34px rgba(0, 0, 0, .28),
    0 2px 6px rgba(0, 0, 0, .14),
    inset 0 -1px 0 rgba(0, 0, 0, .10);
  font-size: 16px;
  color: var(--text);
  overflow-y: auto;
  overflow-x: hidden;
}
/* 行间距（分开写，因为两类面板要求不同）：
   · 开始菜单右列的分组贴出面板 = 3px（＝右列的行距）
   · 「选择项目」那张项目选择浮层 = **6px**（2026-09-18 用户："每个项目标签上下的距离，包括和
     '搜索项目'搜索框的上下距离，统一 6px —— 开始菜单里的、Alt+Q 弹窗里的、管理工作左上角那个，
     都统一 6px"）。它是**三处共用的一张单例面板**（`#ldPpickPanel`），所以这里写通用选择器，
     三处一起生效，不做成"只有开始菜单那份 6px"。 */
.smbg-menu.ld-sm-pop { gap: 3px; }
.ld-ppick-panel { gap: 6px; }                      /* 搜索框 ↔ 第一项 */
.ld-ppick-panel .ld-ppick-list {                   /* 项 ↔ 项 */
  display: flex;
  flex-direction: column;
  gap: 6px;
  /* 左右各留 6px（2026-09-18 用户追加："管理工作和弹窗里面的这个高亮条，它的左右不是 6px"）——
     这两份面板本身没有内边距（搜索框顶到边、列表满宽），不给列表补左右留白的话，
     "当前项目"那块蓝玻璃会左右贴死面板边框；上下仍为 0，靠上面的 gap 6px 撑出间距。 */
  padding: 0 6px;
}
/* 开始菜单里那一份例外：面板自带 10px 内边距（与卡片一致），列表不再补，否则左右会变成 16px */
.ld-ppick-panel.ld-sm-pick .ld-ppick-list { padding: 0; }

/* ══ 多选模式的底栏（全选 / 清空 / 确定）＋ 框选矩形（2026-09-19 新增）══
   只有 select 带 data-ppick-multi="1" 时才出现：JS 在 open() 里把底栏切 display:flex，
   其余入口（管理工作·选择项目 / 4 个弹窗 / 开始菜单）一直是 display:none —— 那些入口外观一行未变。
   版式与「施工预算 · 行9表头下拉」的 .cb-filter-actions 同款：一条上边线 + 三个等宽文字按钮；
   字号取 16px，与「量差&对比」浮层"内部统一 16px"的口径一致。 */
.ld-ppick-panel .ld-ppick-foot {
  flex-shrink: 0;
  align-items: center;
  gap: 4px;
  border-top: 1px solid var(--line);
  padding: 6px;
}
.ld-ppick-panel .ld-ppick-foot button {
  flex: 1 1 0;
  min-width: 0;
  background: none;
  border: none;
  color: var(--primary);
  font-family: inherit;
  font-size: 16px;
  cursor: pointer;
  padding: 6px 0;
  border-radius: 6px;
  text-align: center;
}
.ld-ppick-panel .ld-ppick-foot button:hover { background: var(--primary-soft); }
/* 框选矩形：多选模式下在列表里左键拖动时画出的半透明主色框（外观同 行9 的 .cbfd-marquee） */
.ld-ppick-marquee {
  position: fixed;
  z-index: 30001;              /* 面板是 30000 → 框必须盖在面板之上 */
  background: color-mix(in srgb, var(--primary) 18%, transparent);
  border: 1px solid var(--primary);
  pointer-events: none;
  display: none;
}
/* 背景设置对话框整体加宽 30px（212→242，2026-09-06 用户） */
.smbg-wall-menu {
  min-width: 242px;
}
/* 2026-09-16 用户："透明度下来之后 里面标签也参照壁纸设置的分组标签的透明度，
   不然造成 外体透明 里面颜色深  很不协调"
   → 弹窗**内层**的标签 / 分段按钮 / 条目统一改成**透明底**（口径同壁纸分组标签 `.smbg-wall-menu .smbg-cat`：
   只留边框与文字，选中态才用 `--primary` 填色）——以后弹窗体一律这样，别再给内层块加深色底。 */
.font-settings-dialog .smbg-item,
.font-settings-dialog .smbg-fit-seg,
.font-settings-dialog .smbg-fit-btn,
.font-settings-dialog .smbg-cat,
.font-settings-dialog .ai-voice-row,          /* 语音助手设置：行块（原 --panel-soft，套在已半透明的窗体上会叠深） */
.font-settings-dialog .ai-voice-row select,   /* 行内下拉（原 --panel，同上） */
.font-settings-dialog .cache-toggle-btn,      /* 全员设置 / AI API 的「开启·关闭 / 私有·公用」标签（原 --panel，同上） */
.engineer-assign-dialog .ai-voice-row,
.engineer-assign-dialog .cache-toggle-btn,
.smbg-wall-menu .smbg-item,
.smbg-wall-menu .smbg-fit-btn,
.smbg-desk-menu .smbg-item {
  background: transparent;
}
/* 桌面右键菜单（含它贴出的二级面板 —— 二级是 body 直下的 fixed 层，其家族类由 `_ldShowSubmenuAt` 继承）：
   **选中态（.active = 当前档位/当前状态那一行）与鼠标悬停同一套配色** ——
   2026-09-20 用户："右键菜单选中的文字和高亮条的颜色，需要同鼠标悬停的保持一致"。
   原来走通用 `.smbg-item.active`（主色实底 + 白字），和悬停（--primary-soft 底 + --primary 字）像两套东西；
   这里改成完全等于 hover 的那两个值（hover 规则见下方 `.smbg-item:hover`，两处要一起改才叫"一致"）。
   特异性 (0,3,0) > 通用那条 (0,2,0)，不需要 !important。 */
.smbg-desk-menu .smbg-item.active {
  background: var(--primary-soft);
  color: var(--primary);
}
/* 「设置桌面图标」弹窗（2026-09-20 用户）：行是**拆开后的状态行**（显隐 / 锁定 / 后缀名 / 打开方式 /
   图标大小 / 对齐模式…），**当前生效的那一行**要"蓝色玻璃亮起" —— 用桌面那套蓝玻璃
   （同 `.sm-desk-icon.sel`：rgba(74,158,255,.15) 底 + rgba(120,190,255,.9) 亮蓝描边、文字保持正常色），
   而不是通用的 `.smbg-item.active`（主色实底 + 白字）。
   ⚠ 必须带 `.ldg-deskicon-dialog` 限定：`.smbg-item.active` 是菜单/其它弹窗通用的，不能跟着改。
   特异性 (0,3,0) > 通用那条 (0,2,0)，无需 !important。 */
.ldg-deskicon-dialog .smbg-item.active {
  background: rgba(74, 158, 255, .15);
  outline: 1.5px solid rgba(120, 190, 255, .9);
  outline-offset: -1px;
  color: var(--text);
}
/* 弹窗内行的悬停：与"当前态"同一套玻璃（照开始菜单贴出面板 `.ld-sm-pop .smbg-item:hover` 的口径，
   免得"悬停是主色辅底、当前态是蓝玻璃"两种蓝混在一起看不出区别） */
.ldg-deskicon-dialog .smbg-item:hover {
  background: rgba(74, 158, 255, .15);
  outline: 1.5px solid rgba(120, 190, 255, .9);
  outline-offset: -1px;
  color: var(--text);
}
/* 上面被清底的「分段标签」靠外框成形（口径同壁纸分组标签 .smbg-cat：只留边框与文字）——
   .cache-toggle-btn 自身 border:none、原来靠底色成块，故由父级 .cache-toggle-group 的边框承担（已有）。 */
/* 2026-09-17 用户："很多弹窗中的输入框选择框 颜色也去掉，我看出来了 壁纸设置的分组 是利用一体背景 然后自身 外框线"
   → 弹窗体里的**输入框 / 选择框 / 多行文本**也照这个口径：**底色清空（透出窗体那一体背景）+ 只留自己一圈外框线**。
   ⚠ 面板里这些控件很多是**行内 style** 写死 `background:var(--panel)/var(--bg)` 的（AI API 三个输入框、选择项目下拉、
     全员设置的设备数、消息标题/正文/有效期、通用输入弹框、设置桌面名称、目标用户搜索…），行内样式只能靠
     `!important` 压下来，所以本组必须带它。
   ⚠ 排除项：`range`（滑块靠轨道颜色表达进度）/ `checkbox`·`radio`（原生选中态）/ `file`·`color`（原生外观）——
     它们不是"颜色深"的方块。范围只圈**弹窗体**：桌面上的就地改名框（.sm-desk-icon-input）、
     总览里的改名框（.ldg-deskall-name-input）与桌面搜索框（.sm-desk-websearch-inp）**不动**（它们是桌面元素，不是弹窗）。 */
.font-settings-dialog input:not([type="range"]):not([type="checkbox"]):not([type="radio"]):not([type="file"]):not([type="color"]):not([type="button"]):not([type="submit"]):not([type="reset"]),
.font-settings-dialog select,
.font-settings-dialog textarea,
.engineer-assign-dialog input:not([type="range"]):not([type="checkbox"]):not([type="radio"]):not([type="file"]):not([type="color"]),
.engineer-assign-dialog select,
.engineer-assign-dialog textarea,
.eng-add-modal input:not([type="range"]):not([type="checkbox"]):not([type="radio"]):not([type="file"]):not([type="color"]),
.eng-add-modal select,
.eng-add-modal textarea,
.smbg-menu input:not([type="range"]):not([type="checkbox"]):not([type="radio"]):not([type="file"]):not([type="color"]),
.smbg-menu select,
.smbg-menu textarea,
.ldg-icon-panel input:not([type="range"]):not([type="checkbox"]):not([type="radio"]):not([type="file"]):not([type="color"]),
.ldg-icon-panel select,
.ld-zoom-picker input:not([type="range"]):not([type="checkbox"]):not([type="radio"]),
.ld-zoom-picker select,
.modal input:not([type="range"]):not([type="checkbox"]):not([type="radio"]):not([type="file"]):not([type="color"]):not([type="button"]):not([type="submit"]),
.modal select,
.modal textarea,
.mouse-confirm input:not([type="range"]):not([type="checkbox"]):not([type="radio"]):not([type="file"]):not([type="color"]),
.mouse-confirm select,
.mouse-confirm textarea,
.ai-avatar-submenu input:not([type="range"]):not([type="checkbox"]):not([type="radio"]):not([type="file"]):not([type="color"]),
.ai-avatar-submenu select,
.ai-avatar-submenu textarea,
.ai-float-panel input:not([type="range"]):not([type="checkbox"]):not([type="radio"]):not([type="file"]):not([type="color"]),
.ai-float-panel select,
.ai-float-panel textarea,
.ld-settings-float input:not([type="range"]):not([type="checkbox"]):not([type="radio"]):not([type="file"]):not([type="color"]),
.ld-settings-float select,
.ld-settings-float textarea {
  background: transparent !important;
}
/* 下拉「展开后的选项」是原生弹层，仍要实底才看得清（透明会让它和背后的页面糊在一起）——保持原样。 */
/* 引擎选择**面板**（2026-09-16 用户 H 方案：桌面搜索框上点「系统 logo」/右键「选择搜索引擎」）——
   窗体固定 **760×280、不带标题**，深色玻璃（描边/高光同搜索框；**浓度与模糊单独一档**：
   搜索框 2026-09-16 被要求"再透 30%"→ 0.41、"有点糊"→ 模糊降到 8px；面板用户明确说"别动"
   → 底色保持 0.58、模糊保持 12px，内容多、字小，太透太清会晃）；
   6 列：每格 = 引擎**彩色 logo + 名称**（logo 在格内**放大 30%** = 62px；名称 16px **不加粗**），
   当前引擎高亮；末格「＋ 添加」（8 个内置 + 自定义 + 添加 → 每行 6 格，刚好铺两行）。
   内边距 5px（+1px 边框 = 图标距窗体四周边缘正好 6px）→ 网格可用区 748×268，每格 ≈121×132。
   ⚠ 面板恒为深色玻璃 → 文字色必须写死浅色（`--text` 随主题变，浅色主题下会看不见）。
   ⚠ **高度不再写死**（2026-09-30 用户："搜索引擎下拉框的高度是固定写死的，需要能根据图标的行自动向下增加"）：
     窗体高 = 网格内容高 + 内边距/边框 ⇒ **加一行就自己长一行**；行数多到超出屏幕时才由网格滚
     （上限 `max-height` 由 JS 按**布局像素**算好写进 `.ldg-eng-grid` 的行内样式，见 `_ldShowEngineGrid` ——
      写 CSS `vh` 在 `html zoom` 下量纲对不上，会算高/算矮）。 */
.ldg-eng-menu {
  width: 760px;
  padding: 5px;                    /* + 1px 边框 = 图标距窗体边缘 6px */
  background: rgba(12, 20, 34, 0.58);
  border: 1px solid rgba(120, 190, 255, 0.30);
  box-shadow: 0 8px 22px rgba(0, 0, 0, 0.38), inset 0 1px 0 rgba(255, 255, 255, 0.09);
  backdrop-filter: blur(12px) saturate(1.25);
  -webkit-backdrop-filter: blur(12px) saturate(1.25);
}
.ldg-eng-grid {
  display: grid;
  grid-template-columns: repeat(6, minmax(0, 1fr));
  grid-auto-rows: 132px;
  gap: 4px;
  width: 100%;
  /* 高度跟着行数走（不再 `height:100%` 去填那个写死的 280）；超屏上限由 JS 写行内 `max-height` */
  height: auto;
  overflow-y: auto;
}
.ldg-eng-item {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 10px;
  height: 100%;
  padding: 8px 4px;
  border: 1px solid transparent;
  border-radius: 10px;
  background: transparent;
  color: rgba(238, 244, 255, 0.88);
  font-size: 16px;
  line-height: 1;
  cursor: pointer;
}
/* 名称单行省略（格宽固定，长名宁可省略号也不要撑破网格） */
.ldg-eng-name {
  align-self: stretch;
  max-width: 100%;
  text-align: center;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  font-size: 16px;
  font-weight: 400;                /* 2026-09-16 用户：文字 16px 不加粗 */
}
/* 引擎彩色 logo 方块：品牌色底 + 首字母/首字（--c1/--c2 由 JS 按引擎写入）。
   48 → 62 = 在格内放大 30%（2026-09-16 用户）。
   `position: relative` 是给下面那层「网站真图标」绝对定位用的（2026-09-30）。 */
.ldg-eng-logo {
  flex: none;
  position: relative;
  width: 62px;
  height: 62px;
  border-radius: 18px;
  display: grid;
  place-items: center;
  font-size: 29px;
  font-weight: 700;
  color: #fff;
  background: linear-gradient(150deg, var(--c1, #3b82f6), var(--c2, #1e40af));
}
/* 自定义引擎（以及标了 fav 的）挂**该站点的真图标**（2026-09-30 用户："图标要走我们前端网络图标逻辑"）——
   图没到 / 打不开：img 不显示 → 就是上面那枚品牌/首字方块（老样子，绝不留空白格）；
   图到了：JS 摘掉字母并加 `.has-fav` → 白底 + 48px contain（深浅底色的站点图标都看得清）。 */
.ldg-eng-logo > img.ldg-eng-fav {
  display: none;
  position: absolute;
  left: 7px;
  top: 7px;
  width: 48px;
  height: 48px;
  object-fit: contain;
}
.ldg-eng-logo.has-fav {
  background: #fff;
}
.ldg-eng-logo.has-fav > img.ldg-eng-fav {
  display: block;
}
/* 末格「＋ 添加」：虚线方块 + 灰字，与引擎格同尺寸（两行才齐） */
.ldg-eng-item.ldg-eng-add {
  border-style: dashed;
  border-color: rgba(255, 255, 255, 0.22);
}
.ldg-eng-item.ldg-eng-add .ldg-eng-logo.plus {
  background: transparent;
  border: 1px dashed rgba(255, 255, 255, 0.28);
  color: rgba(255, 255, 255, 0.50);
  font-size: 30px;
  font-weight: 400;
}
.ldg-eng-item:hover {
  background: rgba(47, 125, 246, 0.18);
  color: #4a9eff;
}
.ldg-eng-item.active {
  background: rgba(47, 125, 246, 0.18);
  color: #4a9eff;
  border-color: #4a9eff;
}
/* 引擎面板**拖动排序**的落点高亮（2026-09-30 用户：引擎列表能拖动排序，逻辑同「展开组·更多」）——
   与组浮层 `.ldg-grp-cell.ldg-grp-drop` 同一套视觉：浅蓝底 + 虚线蓝框。
   ⚠ 必须排在 `.ldg-eng-item.active` **之后**（两者同特异性，靠先后定胜负）：拖到"当前引擎"那格时，
     虚线框不该被 active 的底色/边框吃掉。`:hover` 一起写死，免得被悬停样式盖掉。 */
.ldg-eng-item.ldg-eng-drop,
.ldg-eng-item.ldg-eng-drop:hover {
  background: rgba(74, 158, 255, .12);
  outline: 2px dashed rgba(90, 170, 255, .9);
  outline-offset: -2px;
}
/* 2026-09-07 用户：背景设置菜单仍显拥挤 → 整体宽松化：
   外宽再 +30（242→272）；纵向通过加大菜单内边距/行距/条目内边距约 +80，
   行内按钮(上一张/下一张/换一张 等)点击区更大、更透气。仅作用于本菜单，不影响桌面其它右键菜单。 */
.smbg-wall-menu {
  min-width: 272px;   /* 原 242 → +30 */
  padding: 11px;      /* 原 6px（四周 +5，视觉透气） */
  gap: 10px;          /* 原 5px（行间距翻倍 → 高度明显增加） */
}
.smbg-wall-menu .smbg-title {
  padding: 10px 14px 12px;   /* 原 6px 12px 8px */
}
.smbg-wall-menu .smbg-item {
  padding: 12px 16px;        /* 原 7px 12px：条目更高更宽 */
}
.smbg-wall-menu .smbg-row .smbg-item {
  padding: 12px 4px;         /* 原 7px 0：三连按钮行更高 */
}
.smbg-wall-menu .smbg-sep {
  margin: 2px 12px;          /* 分隔线上下稍让位，不贴行 */
}
/* 壁纸设置里的"选中项"（2026-09-20 用户："我们的壁纸设置里面的选项，选中的也要这样"= 与鼠标悬停一致）。
   这几处原本走通用 `.smbg-item.active`（主色实底 + 白字）—— 与上方 `.smbg-item:hover`
   （--primary-soft 底 + --primary 字）两套观感；这里改成与悬停完全一致。
   覆盖的是内容构造里 `item(label, fn, mark)` 打上 active 的那几行：关闭自动壁纸 / 每 30·60·90 秒
   （见 buildWallpaperContent）。特异性 (0,3,0) > 通用那条 (0,2,0)，不用 !important。 */
.smbg-wall-menu .smbg-item.active {
  background: var(--primary-soft);
  color: var(--primary);
}
/* 2026-09-10 用户：「壁纸设置的分组一排太宽」→ 菜单改左右两栏：左栏竖排分类列表、右栏操作项。
   菜单整体加宽（272→404）以容纳两栏；窄屏用 max-width 兜底不溢出视口。 */
.smbg-wall-menu {
  min-width: 404px;
  max-width: calc(100vw - 16px);
}
.smbg-wall-menu .smbg-wall-cols {
  display: flex;
  align-items: stretch;
  gap: 10px;
  min-height: 0;
}
.smbg-wall-menu .smbg-wall-col {
  display: flex;
  flex-direction: column;
  gap: 10px;
  min-width: 0;
}
.smbg-wall-menu .smbg-wall-col-left {
  flex: 0 0 142px;   /* 2026-09-10 用户：分组列加宽 30px（112→142） */
  width: 142px;
  /* 2026-09-10 用户：左栏高度必须**跟着右栏**——右栏项数随角色/权限变化（系统管理员比普通
     用户多两项），两栏底边要对齐。既不能用固定 max-height（右栏更高时左栏底部留白），
     也不能让左栏自身内容把整块撑高（分类很多时会把菜单顶得老高）。
     做法：本栏不排流式内容、只当定位基准 → 不贡献高度；分类列表绝对定位填满，
     高度即右栏高度，分类放不下时在列内滚动。 */
  position: relative;
  min-height: 0;
}
.smbg-wall-menu .smbg-wall-col-right {
  flex: 1 1 auto;
}
/* 分类筛选（2026-09-10 用户：池子按源站官方分类分目录）——左栏内改为竖排、纵向滚动 */
.smbg-wall-menu .smbg-cats {
  display: flex;
  flex-wrap: nowrap;
  gap: 6px;
  overflow-x: auto;
  overflow-y: hidden;
  padding: 0 2px 2px;
  scrollbar-width: thin;
}
.smbg-wall-menu .smbg-wall-col-left .smbg-cats {
  /* 绝对定位填满左栏（左栏高度＝右栏高度）→ 分类多时在列内滚动，不把整块撑高 */
  position: absolute;
  left: 0;
  top: 0;
  right: 0;
  bottom: 0;
  flex-direction: column;
  overflow-x: hidden;
  overflow-y: auto;
  gap: 5px;
  padding: 0 3px 0 0;
  scrollbar-width: none;      /* 2026-09-10 用户：分组列不要滚动条（仍可滚动） */
}
.smbg-wall-menu .smbg-wall-col-left .smbg-cats::-webkit-scrollbar {
  width: 0;                   /* Chrome/Safari：隐藏滚动条 */
  height: 0;
}
.smbg-wall-menu .smbg-wall-col-left .smbg-cat {
  width: 100%;
  box-sizing: border-box;
  text-align: center;
}
.smbg-wall-menu .smbg-cat {
  flex: 0 0 auto;
  padding: 5px 11px;
  font-size: 16px;      /* 2026-09-10 用户：与右侧操作项一致（原 13px 偏小） */
  color: var(--text);   /* 2026-09-10 用户：颜色同右侧操作项（原 --muted 偏灰） */
  border: 1px solid var(--line);
  border-radius: 999px;
  white-space: nowrap;
  cursor: pointer;
  user-select: none;
  transition: color .15s, border-color .15s, background .15s;
}
.smbg-wall-menu .smbg-cat:hover {
  color: var(--primary);
  border-color: var(--primary);
}
/* 分类胶囊的"当前分组"（2026-09-20 用户："壁纸设置里面的选项，选中的也要这样"）：
   原来是**主色实底 + 白字**，改成与上面 `:hover` 那一套完全一致（透明底 + 主色字 + 主色描边）。 */
.smbg-wall-menu .smbg-cat.active {
  color: var(--primary);
  background: transparent;
  border-color: var(--primary);
}
/* 2026-09-13 用户：分组按钮里「标签 + 数字」做成两列对齐 —— 标签列定宽（min-width 由 JS 按"最长标签"
   写入，这批标签都是中文、1 字≈1em）、**数字左对齐**；标签与数字之间固定 **2 个空格**
   （空格已写进数字那段的文本里：\u00A0×2，nbsp 不会被折叠）。
   ⚠「完美世界」加的是 .smbg-cat-plain，不套这套规则（用户要求除外，保持原来的居中单串文字）。 */
.smbg-wall-menu .smbg-cat.smbg-cat-cols {
  text-align: left;
}
.smbg-wall-menu .smbg-cat-cols .smbg-cat-name,
.smbg-wall-menu .smbg-cat-cols .smbg-cat-num {
  display: inline-block;   /* 标签列要能吃 min-width（inline 不生效） */
  vertical-align: baseline;
}
.smbg-title {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  padding: 6px 12px 8px;
  font-size: 18px;      /* 2026-09-06 用户：菜单大字 14→18 */
  font-weight: 700;
  color: var(--muted);
}
.smbg-title-label {
  flex: 0 1 auto;
}
/* 2026-09-11 用户：壁纸设置标题左侧组合（「壁纸设置」+「填充 / 拉伸」两钮；关闭钮仍在最右） */
.smbg-title-left {
  display: flex;
  align-items: center;
  gap: 10px;
  min-width: 0;
}
.smbg-fit-seg {
  display: flex;
  gap: 6px;
  flex: none;
}
.smbg-fit-btn.active {
  color: var(--primary);
  border-color: var(--primary);
  background: var(--primary-soft);
}
/* 标题右侧按钮（2026-09-10 用户：桌面设置标题右侧「锁屏」；字号定稿 16px） */
.smbg-title-btn {
  flex: none;
  padding: 3px 12px;
  font-size: 16px;
  font-weight: 600;
  line-height: 1.4;
  color: var(--muted);
  background: transparent;
  border: 1px solid var(--line);
  border-radius: 6px;
  cursor: pointer;
  transition: color .15s, border-color .15s, background .15s;
}
.smbg-title-btn:hover {
  color: var(--accent, #4a9dff);
  border-color: var(--accent, #4a9dff);
}
/* 壁纸设置标题左那对「填充 / 拉伸」（2026-09-20 用户："壁纸设置里面的选项，选中的也要这样"）：
   它的**选中态**本来就是"主色辅底 + 主色字 + 主色描边"（见上方 `.smbg-fit-btn.active`），而悬停走的是
   上面那条 `.smbg-title-btn:hover`（--accent 描边、无底色）→ 两种观感。这里把**悬停对齐成选中的那一套**：
   这样"选中 ≡ 悬停同一套配色"，而且当前档位在静止时依旧看得出来（不会像纯悬停那样移开就没了）。
   ⚠ 必须写在这条之后（同特异性，靠顺序压过 `.smbg-title-btn:hover`）。 */
.smbg-fit-btn:hover {
  color: var(--primary);
  border-color: var(--primary);
  background: var(--primary-soft);
}
/* 2026-09-10 用户：标题右上「关闭」按钮（X，30×30 方形）——壁纸设置 / 图标维护面板共用；
   覆盖 .smbg-title-btn 的文字内边距 */
.smbg-title-close {
  width: 30px;
  height: 30px;
  min-width: 30px;
  padding: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 8px;
}
.smbg-title-close svg { display: block; }
/* 「图标维护」面板（2026-09-10 用户：Ctrl+右键 呼出；常驻不自动关、可拖动、右上角 X 关闭） */
.ldg-icon-panel {
  /* 2026-09-13 用户：整体加宽 60px（236 → 296），并且**定宽** ——
     「目标：<网址/域名>」这类长文本过去会把面板一路撑宽（`.smbg-menu` 是 fixed + shrink-to-fit、
     没有宽度上限，长网址直接把面板拉成超宽的一条）；固定 296px 后，长网址改在行内换行
     （`.ldg-icon-panel-target` 已有 word-break: break-all），面板尺寸稳定、拖到哪都不跳。 */
  width: 296px;
  z-index: 6200;   /* 高于普通右键菜单(6000)，避免被盖住 */
}
.ldg-icon-panel .ldg-icon-panel-target {
  padding: 2px 12px 6px;
  font-size: 13px;
  color: var(--muted);
  word-break: break-all;
}
/* 「将存入」回显（2026-09-12 用户）：图标维护面板里直接摆出"点存入缓存会存进去的那张图 + 图源地址" */
.ldg-icon-panel .ldg-icon-panel-preview {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 0 12px 8px;
  font-size: 12px;
  line-height: 1.4;
  color: var(--muted);
  word-break: break-all;
  /* 2026-09-13 用户：**这一行才是会一闪一闪的地方**（"将存入：<图源地址>"）——它的内容会随
     重抓/换目标实时变（图源有↔无、网址长↔短），高度跟着变 → 整个面板高度一闪一闪。
     这里把高度**定死**：2 行文字高（2×1.4×12=33.6）+ 底部 8px 内边距 = 42（也大于 28px 缩略图），
     文字超过 2 行由下面的 clamp 收成省略号，不再把面板撑高/收敛。 */
  height: 42px;              /* 含 padding（全局 *{box-sizing:border-box}）→ 内容区 34px，够 2 行 + 缩略图 */
  overflow: hidden;
}
/* 回显文字最多 2 行，超出省略号（配合上面的定高，保证高度恒定、不会半行硬切） */
.ldg-icon-panel .ldg-icon-panel-preview > span {
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  overflow: hidden;
  min-width: 0;
}
.ldg-icon-panel .ldg-icon-panel-preview img {
  width: 28px;
  height: 28px;
  flex: 0 0 auto;
  object-fit: contain;
  border-radius: 6px;
  background: rgba(255, 255, 255, .06);
}
/* 面板第一位：自定义图标来源的**内嵌输入框**（2026-09-10 用户：直接输入回车应用，不弹窗） */
.ldg-icon-panel .ldg-icon-panel-input {
  width: 100%;
  box-sizing: border-box;
  padding: 7px 10px;
  font-size: 14px;
  color: var(--text);
  background: var(--panel-soft, #f7f7f7);
  border: 1px solid var(--line);
  border-radius: 8px;
  outline: none;
  transition: border-color .15s;
}
.ldg-icon-panel .ldg-icon-panel-input:focus { border-color: var(--primary); }
.ldg-icon-panel .ldg-icon-panel-input::placeholder { color: var(--muted); opacity: .9; }
/* 输入行：输入框 + 右侧「确定」（2026-09-10 用户：除回车外也能点按钮应用） */
.ldg-icon-panel .ldg-icon-panel-inputrow {
  display: flex;
  align-items: center;
  gap: 6px;
}
.ldg-icon-panel .ldg-icon-panel-inputrow .ldg-icon-panel-input {
  flex: 1 1 auto;
  width: auto;   /* 覆盖上面的 width:100%（flex 布局下由 flex 撑开，给按钮留位） */
  min-width: 0;
}
.ldg-icon-panel .ldg-icon-panel-okbtn {
  flex: 0 0 auto;
  padding: 7px 14px;
  font-size: 16px;
  line-height: 1.4;
  color: #fff;
  background: var(--primary);
  border: 0;
  border-radius: 8px;
  cursor: pointer;
  transition: opacity .15s;
}
.ldg-icon-panel .ldg-icon-panel-okbtn:hover { opacity: .88; }
/* 壁纸清晰度切换 1K/2K/4K（2026-09-05）已于 2026-09-10 移除：图源改本地壁纸池，无"按尺寸下载" */
.smbg-subtitle {
  padding: 2px 12px 4px;
  font-size: 16px;   /* 2026-09-06 用户：菜单小字 12→16 */
  color: var(--muted);
  opacity: .9;
}
.smbg-item {
  padding: 7px 12px;
  font-size: 16px;   /* 2026-09-06 用户：菜单小字 13→16 */
  color: var(--text);
  border-radius: 8px;
  cursor: pointer;
  white-space: nowrap;
}
.smbg-item:hover {
  background: var(--primary-soft);
  color: var(--primary);
}
.smbg-item.active {
  background: var(--primary);
  color: #fff;
}
/* 点击反馈动画：文字弹一下（2026-09-05） */
.smbg-item.pop {
  animation: smbg-pop 0.18s ease;
}
@keyframes smbg-pop {
  0% { transform: scale(1); }
  50% { transform: scale(1.12); }
  100% { transform: scale(1); }
}
/* 一行三按钮：上一张 / 下一张 / 换一张（2026-09-05） */
.smbg-row {
  display: flex;
  align-items: stretch;
  gap: 6px;
}
.smbg-row .smbg-item {
  flex: 1;
  padding: 7px 0;
  text-align: center;
}
.smbg-sep {
  height: 1px;
  margin: 0 8px;   /* 纵距交给 .smbg-menu gap:5px 统一，避免叠加空隙（2026-09-06） */
  background: var(--line);
}
/* 子菜单触发项（含右箭头，2026-09-05） */
.smbg-submenu-trigger {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
}
.smbg-submenu-label {
  flex: 1;
}
.smbg-submenu-arrow {
  font-size: 14px;
  color: var(--muted);
  opacity: .7;
}
/* 子菜单面板（贴主菜单右侧，2026-09-05） */
.smbg-submenu {
  position: fixed;
  z-index: 6001;
}

/* ══ 桌面图标组（2026-09-07 用户：手机文件夹式）══ */
/* 组图标：文件夹瓦片视觉（成员数角标已按用户要求取消，2026-09-07） */
.sm-desk-icon-img-grp {
  position: relative;
  display: inline-block;
  box-sizing: border-box;
  border-radius: 10px;
  background: linear-gradient(180deg, rgba(255,255,255,.22), rgba(0,0,0,.05)), #f0a63a;
  box-shadow: inset 0 -7px 9px rgba(150, 90, 0, .35), 0 3px 8px rgba(0, 0, 0, .4);
  overflow: hidden;
  filter: none;
}
/* 文件夹"上夹片" */
.sm-desk-icon-img-grp::before {
  content: '';
  position: absolute;
  left: 0;
  top: 0;
  width: 46%;
  height: 24%;
  background: #ffc966;
  border-radius: 6px 6px 0 0;
  box-shadow: 0 1px 2px rgba(0, 0, 0, .25);
}
/* 折叠处颜色加深，模拟层叠 */
.sm-desk-icon-img-grp::after {
  content: '';
  position: absolute;
  left: 0;
  right: 0;
  top: 24%;
  height: 9%;
  background: rgba(150, 90, 0, .28);
}
/* 拖动时落在可成组目标上的高亮（2026-09-07） */
.sm-desk-icon.sm-desk-icon-drop {
  outline: 3px dashed rgba(90, 170, 255, .95);
  outline-offset: 3px;
  border-radius: 10px;
}
/* 组浮层（2026-09-07）：面板外观与现有主题弹窗一致（参照 .font-settings-dialog：
   背景 var(--bg)/边框 var(--line)/圆角16px），遮罩透明、点面板外关闭（2026-09-08）
   2026-09-17 用户："图标组的样式透明度 也按照我们的标准" → 补上 #147 的统一外观：
   底色改 `var(--panel)`（半透明，同 .smbg-menu）、圆角 16→12px、去掉外圈发光影子。 */
.ldg-grp-ov {
  position: fixed;
  inset: 0;
  z-index: 9500;
  background: transparent; /* 不要遮罩压暗/淡入（2026-09-08 用户），仅作点击外部关闭的拦截层 */
}
/* 组浮层面板出现动画：0.15s 纯淡入（2026-09-08 用户：不要遮罩，面板淡入即可） */
@keyframes ldgPanelIn {
  from { opacity: 0; }
  to { opacity: 1; }
}
.ldg-grp-panel {
  position: fixed;
  z-index: 9501;
  min-width: 330px;
  max-width: calc(100vw - 24px);
  box-sizing: border-box;
  padding: 18px 20px 14px;
  background: var(--panel, #161d2b);
  border: 1px solid var(--line, rgba(255,255,255,.12));
  border-radius: 12px;
  box-shadow: none;
  display: flex;
  flex-direction: column;
  max-height: calc(100vh - 24px);
  color: var(--text, #e8ecf4);
  animation: ldgPanelIn .15s ease-out;
}
/* 桌面图标拖到"已展开的组浮层"上 → 整块面板高亮（2026-09-17 用户："图标组展开的时候，我拖图标到展开的
   （面板）也要能拖进去，不限制非要拖到未展开的组上才算"）。高亮口径同桌面"可成组目标"那款虚线。 */
.ldg-grp-panel.ldg-grp-panel-drop {
  outline: 3px dashed rgba(90, 170, 255, .95);
  outline-offset: 3px;
}
/* 组浮层**皮肤**（2026-09-18 用户）：右键浮层标题可对**本组**切换，没单独设过的组用全局默认值
   （默认「透明玻璃」，注册给「全局默认设置」复位）。两档只差"底色 + 是否背景模糊"，尺寸/圆角/边框
   与布局一律沿用 `.ldg-grp-panel` 本体，保证切换时面板不跳。
   ① `.grp-skin-glass`「透明玻璃」（默认）：半透明 + 背景模糊，浓度定在 22%、模糊 6px（见下）。
      （模糊口径原取自开始菜单那套毛玻璃 `.ld-settings-float` 的 blur 9px，后按用户要求降为 6px。）
   ② `.grp-skin-card`「主题卡片」：现行外观 —— 主题面板底色 `var(--panel)`，不模糊（保留原样）。 */
.ldg-grp-panel.grp-skin-glass {
  background: var(--panel, #161d2b);   /* 兜底：不支持 color-mix 的浏览器退回主题面板色，仍可读 */
  /* 2026-09-18 用户逐轮调透（78 → 31 → 24 → 26 → 22，均为"浓度"）：
       ① "不够透明，再透 60%" → 78% 先降到 31%（口径同项目里「再透 30%」那两次，见
          .sm-desk-websearch 的 0.58→0.41→0.29：按比例降浓度，×0.4）；
       ② "透明度再透 7%" → 透明度加 7 个点：31% → 24%；
       ③ "继续微调到 26%" → 26%；
       ④ "22%" → 定在 **22%**。
     实测（Chrome 解析）：`color(srgb 1 1 1 / 0.202)`（= --panel 的 .92 × 22%，RGB 恒为纯白、
     不会被"往黑里拉"）。视觉上"糊不糊"主要取决于下面的 blur，不是浓度。
     2026-09-18 ④ 之后用户继续调模糊：**blur 9px → 6px**（模糊是"看着透不透"的主因，
     降它比降浓度有效；saturate 保持 128%）。 */
  background-color: color-mix(in srgb, var(--panel, #161d2b) 22%, transparent);
  -webkit-backdrop-filter: blur(6px) saturate(128%);
  backdrop-filter: blur(6px) saturate(128%);
}
.ldg-grp-panel.grp-skin-card {
  background: var(--panel, #161d2b);
}
/* 2026-09-18 用户："大图标组展开后的 —— 轻雅蓝、暖色纸、金秋色、樱花粉，统一用活力橙的"
   → 这 4 个主题下，把展开面板上用到的面层变量**整组钉成「活力橙」**（themes.css 的
     `html[data-theme="huolicheng"]` 原值），使它们的展开面板与活力橙下一模一样。
   ⚠ 只钉面板子树实际用到的变量（--panel 底色 / --line 边框与分隔线 / --text 文字 /
     --primary 改名框边线 / --muted 空态文字）——别的一律不动，避免牵连面板外的样式。
   ⚠ 板子上的 .grp-skin-glass 用的是 `color-mix(var(--panel) …)`，所以底色会自动跟着这套走。 */
html[data-theme="lightblue"] .ldg-grp-panel,
html[data-theme="shuimo"] .ldg-grp-panel,
html[data-theme="jinqiu"] .ldg-grp-panel,
html[data-theme="yinghuafen"] .ldg-grp-panel {
  --panel: rgba(255, 255, 255, .92);
  --line: rgba(255, 83, 31, .16);
  --text: #0F0F0F;
  --muted: #78716c;
  --primary: #FF531F;
}
.ldg-grp-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  padding: 0 0 10px;
  border-bottom: 1px solid var(--line, rgba(255,255,255,.1));
  margin-bottom: 12px;
}
.ldg-grp-title {
  font-size: 20px;
  font-weight: 700;
  /* 2026-09-18 用户："标题/关闭按钮也一起改白"（成员名已改白）→ 头部文字一律固定白字 + 同款投影，
     不再用 var(--text)：浅色主题下 var(--text) 是深色，压在很透的玻璃/壁纸上会看不清。 */
  color: #fff;
  text-shadow: 0 1px 3px rgba(0, 0, 0, 0.9);
  cursor: text;
  padding: 2px 4px;
  border-radius: 6px;
  user-select: none;
}
.ldg-grp-title:hover {
  outline: 1px dashed var(--line, rgba(255,255,255,.3));
}
.ldg-grp-rename {
  font-size: 18px;
  font-weight: 700;
  color: #fff;               /* 同标题：改名时就地输入，颜色不能跳（2026-09-18） */
  background: transparent;   /* 2026-09-17：内层输入框不填色（同 #151），只留外框线 */
  border: 1px solid var(--primary, #4a9eff);
  border-radius: 6px;
  outline: none;
  padding: 2px 6px;
  width: 220px;
  box-sizing: border-box;
}
.ldg-grp-acts {
  display: flex;
  align-items: center;
  gap: 8px;
}
.ldg-grp-btn {
  border: 1px solid var(--line, rgba(255,255,255,.16));
  /* 2026-09-17：内层标签一律不填色（同 #149/#151：窗体一体背景 + 自身外框线），悬停才亮 */
  background: transparent;
  color: #fff;   /* 2026-09-18：同标题固定白字（原 var(--text)，浅色主题下会变深色看不清） */
  border-radius: 8px;
  padding: 5px 12px;
  cursor: pointer;
  font-size: 13px;
  line-height: 1.4;
  transition: background .12s;
}
.ldg-grp-btn:hover {
  background: var(--line, rgba(255,255,255,.16));
}
.ldg-grp-close {
  padding: 5px 10px;
}
/* 组内成员网格：格子的宽/高与间距全部由 JS 按桌面档位写入（与桌面同网格算法） */
.ldg-grp-body {
  display: grid;
  flex: 1 1 auto;
  min-height: 0;
  overflow: auto;   /* 窄视口下 3 列放不下时可横向滚动（桌面正常 3 列放满，2026-09-07） */
  /* 2026-09-17 用户："放大后图标的蓝色玻璃在边缘的会被底部背景切掉，应该图标层要高于容器层才对" ——
     本质是**滚动容器把放大溢出那 1~2px 裁掉了**（overflow:auto 一定会裁，z-index 也顶不出去）。
     ⇒ 四内边距留 4px（> 格子放大 5% 向外溢出的 ~2.5px），放大后的外框/玻璃就完整落在容器内；
     配套把面板宽度 +8px（见 lingdu-core-monitor.js 建面板处），保证 3 列仍刚好放满、不出现滚动条。 */
  padding: 4px;
}
.ldg-grp-cell {
  position: relative;
  border-radius: 10px;
  cursor: pointer;
  user-select: none;
  /* 2026-09-17 用户："展开后的里面的这个图标 放大效果要和桌面图标的一样啊，图标+文字"
     → 缩放放在**整格**上（图标+文字一起放大），与桌面图标 `.sm-desk-icon:hover` 同一口径。 */
  transform-origin: center;
  transition: transform .12s ease;
}
.ldg-grp-cell:hover {
  transform: scale(1.05);
  z-index: 5;   /* 抬到兄弟格之上：放大后与相邻格重叠的那部分才不会被后画的格压住 */
}
/* 组浮层里的成员格（"展开后"的内部图标）：
   2026-09-17 用户："**双击模式下，大图标内部的图标不要有鼠标经过的蓝色玻璃**"
   ⇒ 悬停高亮**按成员自己的档位**分流（与未展开的预览格同一口径）：
     单击档 → 悬停蓝玻璃（挂 `.ldg-cell-single`）；双击档 → 悬停**无色**；
     双击档"点一下选中"（`.sel`）仍亮蓝玻璃（#160 用户要求，鼠标移开还亮着）。
   ⚠ 顺序：`.sel` / `.ldg-cell-single:hover` 排在 `:hover` 之后（同为 (0,2,0) 时靠先后定胜负）。
   ⚠ 拖动落点高亮 `.ldg-grp-drop` 特异性更高（(0,3,0)），仍按它自己的虚线样式。 */
.ldg-grp-cell:hover {
  background: transparent;
  outline: none;
}
.ldg-grp-cell.ldg-cell-single:hover,
.ldg-grp-cell.sel {
  background: rgba(74, 158, 255, .15);
  outline: 1.5px solid rgba(120, 190, 255, .9);
  outline-offset: -1px;
}
/* 组内拖动排序的落点高亮（2026-09-08 用户：浮层内拖成员到其它成员上调整顺序） */
.ldg-grp-cell.ldg-grp-drop,
.ldg-grp-cell.ldg-grp-drop:hover {
  background: rgba(74, 158, 255, .12);
  outline: 2px dashed rgba(90, 170, 255, .9);
  outline-offset: -2px;
}
.ldg-grp-cell-img {
  display: flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
  filter: drop-shadow(0 2px 4px rgba(0, 0, 0, .4));
  font-size: 34px;
  line-height: 1;
}
.ldg-grp-cell-img.url {
  background-size: contain;
  background-repeat: no-repeat;
  background-position: center;
}
.ldg-grp-cell-label {
  font-size: 12px;
  /* 2026-09-18 用户："展开面板上的图标名字字体始终用白色，和桌面图标的一样"
     → 写死白字 + 同款投影（口径照 .sm-desk-icon-label / .sm-grp-prevname），
       不再用 var(--text)：浅色主题（如轻雅蓝/暖色纸…）下 var(--text) 是深色，
       展开后成员名会变黑、与桌面图标不一致，而且压在壁纸上不好读。 */
  color: #fff;
  text-shadow: 0 1px 3px rgba(0, 0, 0, 0.9);
  text-align: center;
  overflow: hidden;
  word-break: break-all;
}
.ldg-grp-empty {
  color: var(--muted, rgba(255,255,255,.5));
  font-size: 14px;
  padding: 22px 0;
  text-align: center;
}
/* 拖出组：跟随鼠标的占位克隆 */
/* 组内拖动排序的"跟随体"（2026-09-16 用户：原来是个 62×62 的空方块，现在显示**成员图标本身**）：
   外壳只负责定位 / 层级 / 穿透，尺寸跟着里面的克隆成员格走。 */
.ldg-grp-dragclone {
  position: fixed;
  z-index: 9600;
  pointer-events: none;
  transform: translate(-50%, -50%);
  opacity: .9;
  filter: drop-shadow(0 8px 18px rgba(0, 0, 0, .45));
}
.ldg-grp-dragclone > .ldg-grp-cell { pointer-events: none; }

/* 组内拖动排序的**占位符**（2026-09-16：照搬「管理工作 → 项目资料卡片」那套 —— 占位符实时跟着落点走，
   本体浮起跟手，松手把本体放进占位符；尺寸由 JS 按被拖格设成同尺寸）。
   ⚠ 2026-09-16 用户："搬完之后对了，但图标又是克隆了，不是本体移动" —— 占位符**不要任何可见外观**
   （原来给了灰底+虚线框，看着像"多出来一个方块/克隆"）；只保留尺寸，视觉上就是"本体被拎走、那格空着"。 */
.ldg-grp-ph {
  border-radius: 10px;
  background: transparent;
  outline: none;
}

/* 平铺预览组（2026-09-07 用户）：透明圆角矩形内平铺成员图标；
   小图标组(.grp-small)=与普通图标同尺寸同布局（图位内嵌 3×3 微缩，组名=普通图标文字样式）；
   大图标组(.grp-big)按形态 列×行（3×1/3×2/3×3/1×3/2×3） */
.sm-desk-icon.sm-grp-prev {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
  padding: 4px;
  box-sizing: border-box;
}
/* 小图标组：外层布局与普通图标完全一致（2026-09-07 用户：参照固定导航图标/数据看板——
   图与名字间距 11px、内边距 8px 4px，与 .sm-desk-icon 相同），成员 3×3 微缩铺满图位 */
.sm-desk-icon.sm-grp-prev.grp-small {
  gap: 11px;
  padding: 8px 4px;
}
/* ⚠ 2026-09-17 用户（第二次更正）："**要和桌面图标一样放大**，放大 1.03 还是 1.05 我忘记了，一样就行"
   —— 组瓦片的**悬停放大**回到桌面图标那套（`.sm-desk-icon:hover → scale(1.05)`、`:active → 1.1`），
   不再压制。组瓦片与桌面图标的差别只剩"外面多一圈 `.sm-grp-prevbox` 边框（+ 拉伸把柄）"。
   （"悬停不放大"是 2026-09-07 的老要求，已被此次更正取代。） */
/* ⚠ 2026-09-17 用户（第三次更正）："**大图标组 外框不要放大 1.05，里面的图标放大就行**；
   大图标组的外框蓝色玻璃逻辑你不要改"。⇒ 只对 `.grp-big` 压掉**外框**缩放（小图标组仍按桌面图标 1.05），
   改成**格内那个图标本身**放大；外框的玻璃规则（双击档不亮 / 单击档亮）保持原样、这次不动。 */
.sm-desk-icon.sm-grp-prev.grp-big:hover,
.sm-desk-icon.sm-grp-prev.grp-big:active {
  transform: none !important;
}
.sm-desk-icon.sm-grp-prev.grp-big .sm-grp-prevcell:hover .sm-grp-previc {
  transform: scale(1.05);   /* 里面的图标放大（外框不放大） */
}
/* 2026-09-08 用户记录：实测点选大图标组（无高亮背景时）比未选中更通透，且喜欢该通透度。 */
.sm-desk-icon.sm-grp-prev.grp-big .sm-grp-prevbox {
  background: transparent;
}
/* 平铺组选中/框选高亮只框 3×3 矩形本身（不含下方组名文字，2026-09-07 用户）；
   2026-09-08 用户：点击选中大图标组不要高亮背景（.grp-big.sel 且非框选来源）；
   框选（.mq-hit 预览中）才显示高亮背景；小图标组(.grp-small)保持原状 */
.sm-desk-icon.sm-grp-prev.sel,
.sm-desk-icon.sm-grp-prev.mq-hit {
  background: transparent !important;
  outline: none !important;
}
.sm-desk-icon.sm-grp-prev.sel .sm-grp-prevbox,
.sm-desk-icon.sm-grp-prev.mq-hit .sm-grp-prevbox {
  background: rgba(74, 158, 255, .16);
  outline: 1.5px solid rgba(120, 190, 255, .95);
  outline-offset: 0;
}
/* 大图标组·点击选中（无框选标记）：去掉蓝色高亮背景，仅保留把柄提示 */
.sm-desk-icon.sm-grp-prev.grp-big.sel:not(.mq-sel):not(.mq-hit) .sm-grp-prevbox {
  background: transparent;
  outline: none;
}
/* 小图标组·**框选**：玻璃要落在**整块瓦片外体**上（与它的悬停口径完全一致，2026-09-17 用户：
   "小图标组悬停是外框蓝色玻璃，框选的时候也要是这个外框蓝色玻璃，现在是旧的逻辑；注意不要误伤大图标组"）。
   旧的逻辑是"瓦片透明 + 内箱 3×3 亮"（上面 .sm-grp-prev.mq-hit .sm-grp-prevbox 那条），这里对小图标组反掉：
   - 框选进行中 → `.mq-hit`；框选提交后 → `.sel.mq-sel`（`mq-sel` = 该选中来自框选，见 JS `_mqCommit`）。
   ⚠ 必须 `!important`：上面 `.sm-desk-icon.sm-grp-prev.sel/.mq-hit` 那条用 `!important` 把瓦片压成了透明；
     此处特异性更高（多一个 `.grp-small`）且同样 `!important`，才盖得住。
   ⚠ 一律带 `.grp-small`：大图标组（`.grp-big`）的框选口径保持原样（内箱亮），绝不误伤。 */
.sm-desk-icon.sm-grp-prev.grp-small.mq-hit,
.sm-desk-icon.sm-grp-prev.grp-small.sel.mq-sel {
  background: rgba(74, 158, 255, .15) !important;
  outline: 1.5px solid rgba(120, 190, 255, .9) !important;
  outline-offset: -1px !important;
}
.sm-desk-icon.sm-grp-prev.grp-small.mq-hit .sm-grp-prevbox,
.sm-desk-icon.sm-grp-prev.grp-small.sel.mq-sel .sm-grp-prevbox {
  background: transparent;
  outline: none;
}
/* 小图标组·**拖动中**：玻璃同样落在**整块瓦片外体**上（2026-09-20 用户："小图标组拖动的时候，
   自身外边缘的蓝色玻璃要像普通图标一样也显示（现状是只有点选上，或者鼠标悬停，或者多个一起选中，
   才显示）"）。
   —— 普通图标拖动时靠选中态 `.sel` 亮着外框玻璃；而小图标组上面那条 `.sm-grp-prev.sel`
      把瓦片压成了透明、玻璃只在内箱 3×3 上 → 一拖起来就"没有外框玻璃"了。
   `.ldg-dragging` 由 JS 在拖动期间挂在**被拖动的那几个**元素上（见 `_ldDeskDragLift` /
   `_ldDeskDragUnlift`；拖动时它们被搬到 body 下，所以选择器**不能**带 #smHomeBlank 前缀）。
   ⚠ 与框选口径一致：外框亮 ⇒ 内箱不亮（同上面 mq-hit 那两条的理由）。 */
.sm-desk-icon.sm-grp-prev.grp-small.ldg-dragging {
  background: rgba(74, 158, 255, .15) !important;
  outline: 1.5px solid rgba(120, 190, 255, .9) !important;
  outline-offset: -1px !important;
}
.sm-desk-icon.sm-grp-prev.grp-small.ldg-dragging .sm-grp-prevbox {
  background: transparent;
  outline: none;
}

.sm-grp-prevbox {
  position: relative; /* 组内成员/溢出提示格 .sm-grp-prevcell 的定位基准 */
  display: grid;
  align-content: start;
  justify-content: start;
  border-radius: 14px;
  /* 2026-09-18 用户："大图标组/小图标组 自己的边框，需要固定用轻雅蓝的，不要随主题变"
     → 写死为「轻雅蓝」（lightblue 主题）的 --line 原值 #d7e8fa，不再用 var(--line)
     （var(--line) 会随主题变：深色主题偏青、暗影黑偏灰，用户要的是这圈淡雅浅蓝恒定）。 */
  border: 1px solid #d7e8fa;
  /* 2026-09-17 用户："图标组的样式透明度 也按照我们的标准" —— 桌面上的组瓦片同样
     "一体背景（透出壁纸）+ 自身外框线"：去掉灰底与投影，只留上面那圈边框。
     （大图标组早在 2026-09-08 就已全透明，这里把小图标组也统一。） */
  background: transparent;
  box-shadow: none;
}
.sm-grp-prevcell {
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 8px;
  cursor: pointer;
  user-select: none;
  overflow: hidden;
}
/* 组内成员图标（预览格）的高亮：
   2026-09-17 用户第 4 次定稿："**内部图标**在双击打开模式下，鼠标经过原来是灰色、后来改的蓝色玻璃，
   现在要**改无色**；**但是展开更多**由于一直是单击打开，所以要有鼠标经过蓝色玻璃"。
   ⇒ 大图标组的成员格按**成员自己的档位**分流：单击档 → 悬停玻璃；双击档 → 悬停**无色**（既不灰也不蓝）。
      「展开更多」末格（`.sm-grp-prevmore`，始终单击）→ 悬停玻璃。
      双击档下"点一下选中"（`.sel`）仍是蓝玻璃（#160 用户要求），鼠标移开还亮着。
   小图标组（`.grp-small`）的 3×3 是**装饰性预览**、整块瓦片才是"点它 = 展开更多"的入口
   ⇒ 成员格一律**无色**（玻璃画在整块瓦片外体上，见 JS 给它挂 `ldg-icon-single`）。
   ⚠ 空槽（`.sm-grp-prevempty`）同样无色。 */
/* ① 底：大图标组成员格悬停一律无色（下面的玻璃规则再把它"点亮"回来） */
.sm-desk-icon.sm-grp-prev.grp-big .sm-grp-prevcell:hover {
  background: transparent;
  outline: none;
}
/* ② 该亮的：单击档成员（`.ldg-cell-single`）+「展开更多」末格（始终单击）+ 选中态 */
.sm-desk-icon.sm-grp-prev.grp-big .sm-grp-prevcell.ldg-cell-single:hover,
.sm-desk-icon.sm-grp-prev.grp-big .sm-grp-prevcell.sm-grp-prevmore:hover,
.sm-desk-icon.sm-grp-prev.grp-big .sm-grp-prevcell.sel {
  background: rgba(74, 158, 255, .15);
  outline: 1.5px solid rgba(120, 190, 255, .9);
  outline-offset: -1px;
}
/* ③ 小图标组 —— 成员格一律无色（玻璃归整块瓦片） */
.sm-desk-icon.sm-grp-prev.grp-small .sm-grp-prevcell:hover {
  background: transparent;
  outline: none;
}
/* 大图标组「显示图标名」：格内图标在上、名字在下（2026-09-07）
   2026-09-08 用户：图-文间距与桌面普通图标一致 = 11px（同 .sm-desk-icon 的 gap） */
.sm-grp-prevcell.mn {
  flex-direction: column;
  padding-top: 2px;
  gap: 11px;
}
/* 成员名样式同普通图标文字（.sm-desk-icon-label 同款：白字+投影、居中、最多两行）
   行高/文字区两行高由 JS 内联按当前档字号给出；超两行溢出裁切（与普通图标一致） */
.sm-grp-prevname {
  /* 与普通桌面图标文字同款（.sm-desk-icon-label）：白字+投影、居中、
     不固定宽（由 maxWidth 限宽折行）、两行文字区高度由 JS 内联给出 */
  color: #fff;
  text-align: center;
  text-shadow: 0 1px 3px rgba(0, 0, 0, 0.9);
  word-break: break-all;
  overflow: hidden;
  line-height: 1.25;
  user-select: none;
}
.sm-grp-prevcell.sm-grp-prevempty {
  cursor: default;
}
.sm-grp-prevcell.sm-grp-prevempty:hover {
  background: transparent;
  outline: none;   /* 空槽不参与高亮（上面的玻璃规则会带上 outline，这里一并清掉） */
}
/* 大图标组形态拖拽热区（2026-09-07 用户）：选中或悬停组时，四边各一条透明热区条，
   不再显示边中点小格子；鼠标移到边缘即出现 ew/ns 拉伸光标，按下横向/纵向拖切 5 种形态 */
.sm-grp-rz {
  position: absolute;
  display: none;
  margin: 0;
  background: transparent;
  border: none;
  box-shadow: none;
  z-index: 6;
}
.sm-desk-icon.sm-grp-prev.sel .sm-grp-rz,
.sm-desk-icon.sm-grp-prev:hover .sm-grp-rz {
  display: block;
}
.sm-grp-rz[data-dir="n"],
.sm-grp-rz[data-dir="s"] {
  cursor: ns-resize;
}
.sm-grp-rz[data-dir="e"],
.sm-grp-rz[data-dir="w"] {
  cursor: ew-resize;
}
/* 四角把柄斜向光标（2026-09-07 用户：自由形态后恢复四角，角=横纵同时整格增减） */
.sm-grp-rz[data-dir="nw"],
.sm-grp-rz[data-dir="se"] {
  cursor: nwse-resize;
}
.sm-grp-rz[data-dir="ne"],
.sm-grp-rz[data-dir="sw"] {
  cursor: nesw-resize;
}
.sm-grp-previc {
  display: flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
  line-height: 1;
  font-size: 14px;
  /* 2026-09-17 用户："大图标组外框不放大，里面的图标放大就行" → 格内图标做悬停缩放（见上） */
  transform-origin: center;
  transition: transform .12s ease;
}
.sm-grp-previc.url {
  background-size: contain;
  background-repeat: no-repeat;
  background-position: center;
}

/* ══ 桌面图标滚动层（2026-09-07 用户：电脑窗口缩小、图标行数放不下时同手机/平板内部滚动）══
   图标一律挂在 #smHomeBlank 内的 #smHomeIcons 层；壁纸是 #smHomeBlank 的背景。
   图标超出桌面可视区时由本层内部滚动查看（电脑/移动端一致），
   图标滑动时壁纸原地不动、不顶动整页（#smHomeBlank overflow:hidden 兜底，防溢出顶出页面滚动条）。 */
#smHomeIcons {
  position: absolute;
  left: 0;
  top: 0;
  right: 0;
  bottom: 0;
  overflow: auto;
  -webkit-overflow-scrolling: touch;
  overscroll-behavior: contain;
  scrollbar-width: thin;
}
/* 桌面「工具层」（2026-09-21 用户：记事本要挂靠在新建它的那个桌面）：
   #smHomeBlank 的直接子层（**不在 #smHomeIcons 里** → 不随图标层滚动），铺满桌面、不吃指针
   （里面的面板各自 pointer-events:auto）；z-index 压过图标层、但在桌面切换条(900)/菜单(6000)/总览(9490)之下。 */
#ldgDeskToolLayer {
  position: absolute;
  left: 0;
  top: 0;
  right: 0;
  bottom: 0;
  z-index: 30;
  pointer-events: none;
}
/* 大图标组拖动对齐参考线（2026-09-07 用户：PPT 式水平/垂直/中线对齐；随图标层滚动） */
.ldg-guide-line {
  position: absolute;
  pointer-events: none;
  z-index: 40;
  background: rgba(255, 80, 100, .92);
  box-shadow: 0 0 3px rgba(255, 0, 60, .5);
}
.ldg-guide-line.v { width: 1px; }
.ldg-guide-line.h { height: 1px; }

/* 2026-09-19 用户："去掉这个淡网格线的逻辑，换一个思路" → 上一版那层**其它图标的实体投影线**
   （`.ldg-solid-layer` / `.ldg-solid-line`）已整体删除：满屏淡线太多太吵，反而看不清谁跟谁齐。
   现在"会吸谁"靠**邻近判定**（只有"在我边上"的图标才参与吸附，见 `_ldgBigGuide`）+ 吸上时的红线。 */

/* 确认弹窗键盘左右选择高亮（2026-09-08 用户：Enter 确认、默认停在确定/删除） */
.ldg-kbd-focus {
  outline: 2px solid #4a9dff !important;
  outline-offset: 1px;
  box-shadow: 0 0 0 3px rgba(74, 157, 255, .32);
}

/* 浮层「光条」（2026-09-21 用户：菜单/弹窗里 ↑↓←→ 走光条、回车 = 执行光条所在项）
   外观对齐菜单行的 :hover（--primary-soft 底 + --primary 字），再套一圈内描边让它"看得见"——
   不能只用 hover 那套：`.smbg-item.active`（当前生效行，如「设置桌面图标」的蓝玻璃）优先级更高，
   不加 !important 光条会被它盖住、看不出光标停在哪一行。 */
.ldg-bar-focus {
  background: var(--primary-soft) !important;
  color: var(--primary) !important;
  box-shadow: inset 0 0 0 2px var(--accent-2, #ff9f2e) !important;
}

/* ══ 文字型可点击元素统一约定：data-ld-tap（2026-09-15 用户）══════════════════════════
   "有文字的、点了有事发生的"元素（不是 <button>，而是一个格/一段文字）统一打 data-ld-tap：
     ① 悬停文字变色（与日期格同一提示色 #1e6fd9）——本规则全局兜底，各表不用再各写一遍；
     ② 表格选中处理遇 data-ld-tap 不改选中（它本身就是"文字按钮"，见各表 click 处理里的
        closest('button, a, input, ..., [role="button"], [data-ld-tap]') 判断）。
   标记位置（改行为时顺手补标记）：各表过滤格/明细表头行1格（绑定处 setAttribute）、
   行号快捷格 *-rh-quick、列标边缘格 *-col-head-edge、公共日期面板 年/月（lingdu-dp-range.js）、
   施工预算 H1/统计汇总 D1「规格型号」、B5 与 B2/B3 日期格（静态 HTML 上写死）。
   注意：本规则在模块 CSS 之前加载，故加 !important 保证不被各表同权重规则盖掉（只改 hover 色，无副作用）。 */
[data-ld-tap] { cursor: pointer; }
[data-ld-tap]:hover { color: #1e6fd9 !important; }

/* ══ 表格多选 / Shift 连选 / 鼠标框选 / 求和读数（2026-09-15 用户）══════════════════════
   逻辑在 static/js/lingdu-cell-select.js（五张表共用一份组件），本处只管样式：
     ① .ldg-cell-sel：选中格淡主题色底；多选高亮的格**不再叠各表自己的"单选线"**
        （同一格上两条 2px 主题色框会错开 1px 叠成双线 —— Ctrl 点选的那格、Shift 连选最后点的那格都会中招）；
     ② .ldg-cell-ring：选区外框覆盖层，**按几何连通性**（不是按操作方式）**散点各自一圈、连成一片只留最外圈**
        （类似 WPS/Excel）。组件把选区合并成若干矩形块，每块一个 fixed 覆盖层画 2px 内描边：
        单点 / Ctrl 点的互不相邻格各成一块 → 视觉上"每格各自 2px 蓝框"；
        Shift 连选 / 框选 / 相连着的散点并成一块 → 只画大外框，格与格之间不画线；
     ③ .ldg-cell-sum 和值读数：绝对定位在「二级导航 ↔ 表」之间的夹缝里（top:100%）、右对齐、12px、
        行高=夹缝高 16px；不参与布局 → 严禁撑高该夹缝上下距离；pointer-events:none 不挡点击。 */
.ldg-cell-sel {
  background: color-mix(in srgb, var(--primary) 14%, transparent) !important;
}
/* 多选高亮的格"吃掉"各表自己的单选线（2026-09-15 用户反馈：Ctrl 点选的那格 / Shift 连选最后点的那格
   会同时出现它的 2px 单选线和我们的外框，错开 1px 看着就是重叠的双框）。
   选择器写成 `.view table tr td|th …` 是**刻意堆特异性**：
     · `td` / `th` 这个元素选择器**不能省** —— 各表十字线/聚光灯那条
       `body.X-cross-on .X-budget-table td.X-cell-selected { background: transparent !important }` 是 (0,3,2)，
       与本条不带元素时打平；模块 CSS 在 lingdu.css **之后**加载，平局由它胜 → 最后点的那格底色被抹掉
       （2026-09-15 用户二次反馈："Shift 连选 / Ctrl 多点选时最后一个点的格子背景不亮"）。带上元素后本条 (0,3,3)，稳压。
     · 各表聚光灯中心格那条 `.X-budget-table td.X-spot-center.X-cell-selected{…!important}` 是 (0,3,1)，同样被压过。
   背景必须一并给足：各表单选规则里带 `background: transparent !important`（Excel 风格"只亮框不亮底"），
   多选却要"底也亮"，所以这里用同款多选底色把它盖回来。 */
.view table tr td[class*="cell-selected"].ldg-cell-sel,
.view table tr th[class*="cell-selected"].ldg-cell-sel {
  background: color-mix(in srgb, var(--primary) 14%, transparent) !important;
  box-shadow: none !important;
}
.ldg-cell-ring {
  position: fixed;
  pointer-events: none;
  z-index: 99997;
  box-shadow: inset 0 0 0 2px var(--primary);
}
body.ldg-cells-dragging,
body.ldg-cells-dragging * {
  user-select: none !important;
  -webkit-user-select: none !important;
}
/* 「按住左键满 0.3 秒 → 可以拖动表格了」+「拖动中」的光标提示（2026-09-15 用户：鼠标变小抓手）。
   组件到点时给 body 加 ldg-pan-ready；真开始拖动时各表把它摘掉、换成自己的 X-drag-scrolling。
   ⚠ 十字线跟随模式（body.X-cross-on.X-cross-follow .X-main-table *）是 `cursor: none !important`（5 表各有一条，
     特异性 (0,3,1) + !important）—— 它会把小手整个吃掉，表现为"十字线时拖动看不到小手"
     （2026-09-15 用户反馈），所以这里：
     ① `.ldg-pan-ready.ldg-pan-ready` / `[class*="-drag-scrolling"][class*="-drag-scrolling"]`
        —— **同样的类名/属性选择器故意写两遍**，把特异性抬到 (0,3,3) 才压得住 (0,3,1)+!important；
     ② 两条分开写（互斥）：按住期 = grab（可拖），真拖动中 = grabbing（正在拖）。
        各表自己的 `body.X-drag-scrolling { cursor: grabbing }` 是普通声明，同样会被十字线那条吃掉，故一并补。 */
body.ldg-pan-ready.ldg-pan-ready .view table td,
body.ldg-pan-ready.ldg-pan-ready .view table th {
  cursor: grab !important;
}
body[class*="-drag-scrolling"][class*="-drag-scrolling"] .view table td,
body[class*="-drag-scrolling"][class*="-drag-scrolling"] .view table th {
  cursor: grabbing !important;
}
.ldg-cell-sum {
  position: absolute;
  top: 100%;
  right: 0;
  height: 16px;
  line-height: 16px;
  font-size: 12px;
  /* 2026-09-15 用户："框选求和右上角的字体颜色有点淡，有的主题下直接看不见" →
     改成与右上二级标题（`.X-top-summary`，如"累计进场:… 已浇筑完:…"）**同一个色** `var(--text)`；
     两者都挂在 `.mat-tabs` 里，同一色变量、同一主题下取值一致（原先 --muted 在部分主题太淡）。 */
  color: var(--text);
  white-space: nowrap;
  pointer-events: none;
  user-select: none;
  -webkit-user-select: none;
  z-index: 9;
}

/* ══════════════════════════════════════════════════════════════════════════
   服务状态（原「服务器压力表」，2026-09-27 用户："服务器压力表，名字改为 服务状态"）—— **独立页面版**
   入口 = 开始菜单 →「服务状态」→ switchView('stress')（viewId 仍是 stress）；容器 #sysStressContainer
   版式与字号**照抄标准字段页（#stdfields）**：左上角标题 22px / 卡片头 20px / 正文 16px；
   卡片外壳（1px 边线 + 10px 圆角 + 8px 30px 卡片头 + var(--sidebar-card-bg)）由 JS 内联给，
   这里只补"行 / KPI / 占用条 / 胶囊 / 异常条目"这些内部零件的排版。
   状态色（**固定不随主题走**）：告警 #e2564a / 提醒 #e8a33d / 正常=主题色。
   ══════════════════════════════════════════════════════════════════════════ */
#sysStressBody .is-bad { color: #e2564a; }
#sysStressBody .is-warn { color: #e8a33d; }
#sysStressBody .is-ok { color: var(--muted); }

/* 标签 / 值 一行（正文 16px） */
#sysStressBody .ldg-st-row {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: 12px; padding: 3px 0; line-height: 1.7;
}
#sysStressBody .ldg-st-row > .k { color: var(--muted); flex: 0 0 auto; }
#sysStressBody .ldg-st-row > .v { text-align: right; word-break: break-all; }
#sysStressBody .ldg-st-row.wrap { flex-wrap: wrap; }
#sysStressBody .ldg-st-row.wrap > .v { text-align: left; flex: 1 1 100%; }

/* KPI（CPU / 内存 / 磁盘）—— 2026-09-27 起这张卡只占左栏一半宽 ⇒ 由"三列横排"改**竖排 + 分隔线** */
#sysStressBody .ldg-st-kpi {
  display: grid; grid-template-columns: 1fr;
  gap: 0; margin-bottom: 4px;
}
#sysStressBody .ldg-st-kpi > .c {
  min-width: 0; padding: 7px 0; border-bottom: 1px solid var(--line);
}
#sysStressBody .ldg-st-kpi > .c:last-child { border-bottom: none; }
#sysStressBody .ldg-st-kpi .h {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: 8px; font-size: 16px; color: var(--muted); margin-bottom: 5px;
}
#sysStressBody .ldg-st-kpi .h > b { font-size: 20px; font-weight: 700; color: var(--text); }
#sysStressBody .ldg-st-kpi .s { margin-top: 6px; font-size: 16px; color: var(--muted); line-height: 1.5; }
#sysStressBody .ldg-st-bar { height: 8px; border-radius: 4px; overflow: hidden; background: rgba(127, 127, 127, .22); }
#sysStressBody .ldg-st-bar > i { display: block; height: 100%; background: var(--primary); transition: width .4s ease; }
#sysStressBody .ldg-st-bar > i.is-warn { background: #e8a33d; }
#sysStressBody .ldg-st-bar > i.is-bad { background: #e2564a; }

/* 网卡（每块两行）：上行 = "eth0　中文说明是什么"；下行 = "▲速率 ▼速率 …… 累计" */
#sysStressBody .ldg-st-net {
  padding: 7px 0; border-bottom: 1px solid var(--line); line-height: 1.7;
}
#sysStressBody .ldg-st-net > .nm { color: var(--text); font-weight: 600; }
#sysStressBody .ldg-st-net > .nm > .ds { font-weight: 400; color: var(--muted); }
#sysStressBody .ldg-st-net > .rt { display: flex; align-items: baseline; gap: 16px; flex-wrap: wrap; }
#sysStressBody .ldg-st-net > .rt > .up { color: #e8a33d; }
#sysStressBody .ldg-st-net > .rt > .dn { color: #3aa0e8; }
#sysStressBody .ldg-st-net > .rt > .total { margin-left: auto; color: var(--muted); }

/* ── 流量柱状条（2026-09-27 用户："网络流量按月统计，并且在监听端口下面放一个月柱状条"）──
   两种粒度都渲染进 DOM，切换只翻 .mode-month（见 lingdu-server-stress.js 的 _trafStrip / ldgStressTrafMode）；
   一根柱子 = 上行(橙) + 下行(蓝) 堆叠，柱高 = 该天/该月的**合计**占"最大那一根"的比例；
   柱高与配色口径和后端 net.traffic 的字段一一对应（rx=下行=服务器收到 / tx=上行=服务器发出）。
   2026-09-27 用户："柱状条下面留了很多空白，高度要利用起来呢，图形现在挤压的很矮"
   ⇒ 本块是**网络卡的最后一个 flex 子项且 `flex:1`**（卡片体由 JS 给 `flex-direction:column`），
     把卡片里剩下的高度全吃掉；`.bars` 再 `flex:1` → 柱子有多高用多高（只给 min-height 兜底）。
     ⚠ 这里**故意不写 `min-height:0`**：留默认的 `min-height:auto` ⇒ 卡片不够高时本块不被压扁，
       由卡片体的 `overflow:auto` 出滚动条（同理上面的网卡行/端口行也压不扁）。 */
#sysStressBody .ldg-st-traf {
  flex: 1 1 auto; display: flex; flex-direction: column;
  margin-top: 8px; border-top: 1px solid var(--line); padding-top: 8px;
}
#sysStressBody .ldg-st-traf > .hd { flex: none; display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap; margin-bottom: 8px; }
#sysStressBody .ldg-st-traf > .hd > .t { font-weight: 600; color: var(--text); }
#sysStressBody .ldg-st-traf > .hd > .sm { color: var(--muted); }
#sysStressBody .ldg-st-traf > .hd > .seg { margin-left: auto; display: flex; gap: 4px; }
#sysStressBody .ldg-st-traf > .hd > .seg > button {
  font-size: 14px; line-height: 1.6; padding: 1px 10px; border-radius: 999px; cursor: pointer;
  border: 1px solid var(--line); background: transparent; color: var(--muted); font-family: inherit;
}
/* ⚠ 选中态文字色**不能写死**（2026-10-10 用户："有些主题下文字看不见，比如暖色纸主题是个黑的，
   那字也是黑的"）—— 原写死 `#062a27` 只在"亮主色"主题下可见；水墨主题 `--primary: #2c2c2c`（近黑）
   就变成黑底黑字。改为与项目其它主色填充处一致的白字（见 lingdu-budget.css 的 `.cb-dp-sel` 等）。 */
#sysStressBody .ldg-st-traf > .hd > .seg > button.on { background: var(--primary); border-color: var(--primary); color: #fff; font-weight: 600; }
/* ── 2026-09-28（用户："上行 下行 分开 / 点击左下的上下切换 / 默认 上行 / 左边加上刻度线 / 柱图上面加上数字"）──
   柱区包一层 `.bars-wrap`：左 ＝ Y 轴刻度列，右 ＝ 柱区；刻度横线用柱区背景渐变画（零额外 DOM）。 */
#sysStressBody .ldg-st-traf > .bars-wrap { flex: 1 1 auto; min-height: 0; display: flex; gap: 8px; }
#sysStressBody .ldg-st-traf > .bars-wrap > .ax {
  flex: none; width: 62px; display: flex; flex-direction: column; justify-content: space-between;
  text-align: right; color: var(--muted); font-size: 13px; line-height: 1;
  padding: 16px 0 18px;     /* 上 16 = 给柱顶数字留空；下 18 = 与 x 轴标签行对齐 */
}
#sysStressBody .ldg-st-traf > .bars-wrap > .bars {
  display: flex; gap: 2px; flex: 1 1 auto; min-height: 88px; margin-bottom: 6px;
  /* ⚠ `padding-bottom` 必须留够：`.lb`（底部日期）是绝对定位在 `.b` 之外（top:100%）的，
     而柱区 `overflow-x:auto` 会让 `overflow-y` **被强制成 auto** ⇒ 不留空间就会被**裁掉**
     （2026-09-28 用户："日期没显示 天 / 1 2 3 4 5 6 7 8…" 就是这个原因）。 */
  padding: 16px 0 18px;
  /* 三条刻度横线：0% / 50% / 100%（只画在 padding 之后的那块柱区里） */
  background-image:
    linear-gradient(to top, var(--line) 0, var(--line) 1px, transparent 1px),
    linear-gradient(to top, transparent calc(50% - .5px), var(--line) calc(50% - .5px), var(--line) calc(50% + .5px), transparent calc(50% + .5px)),
    linear-gradient(to top, transparent calc(100% - 1px), var(--line) calc(100% - 1px), var(--line) 100%, transparent 100%);
  background-repeat: no-repeat;
  background-position: 0 16px;
  background-size: 100% calc(100% - 34px);
}
/* 柱顶数值：**每根柱上面各一个**（2026-09-28 用户："下行柱条上面没有数值" —— 原来是"一组一个合计数"，
   只落在较高的那根上面 ⇒ 另一根看着就没数字）。所以数值挂在 `i`（柱体）里、定位在柱顶上方。
   ⚠ 字号 10px：比正文小一档，按天 7 组 / 按月 12 组的密度下刚好放得下。 */
#sysStressBody .ldg-st-traf > .bars-wrap > .bars > .b > .pair > i {
  position: relative;     /* 数值的定位基准 = 各自那根柱 */
}
#sysStressBody .ldg-st-traf > .bars-wrap > .bars > .b > .pair > i > .v {
  position: absolute; bottom: 100%; margin-bottom: 2px;
  font-size: 10px; line-height: 1; color: var(--muted); white-space: nowrap; pointer-events: none;
}
/* 对齐（2026-09-28 用户："数值一个右对齐 一个左对齐"）：左（上行）柱的数字**右对齐** ⇒ 文字往左伸；
   右（下行）柱的数字**左对齐** ⇒ 文字往右伸 ⇒ **两个数字各朝外**，在 6px 的组内间隔处不会叠在一起。 */
#sysStressBody .ldg-st-traf > .bars-wrap > .bars > .b > .pair > i.up > .v { right: 0; }
#sysStressBody .ldg-st-traf > .bars-wrap > .bars > .b > .pair > i.dn > .v { left: 0; }
/* 图例（2026-09-28 用户："现有的宽度间距下 可以 上下行柱条并列放 离开6px 一组"
   ⇒ 上下行同屏并列，原来的"▲上行/▼下行"切换按钮已撤，改成静态色块图例） */
#sysStressBody .ldg-st-traf .dirs { display: inline-flex; align-items: center; gap: 12px; margin-left: 6px; font-size: 14px; color: var(--muted); }
#sysStressBody .ldg-st-traf .dirs > .lgd { display: inline-flex; align-items: center; gap: 5px; }
#sysStressBody .ldg-st-traf .dirs > .lgd::before { content: ''; width: 10px; height: 10px; border-radius: 2px; display: inline-block; }
#sysStressBody .ldg-st-traf .dirs > .lgd.up::before { background: #e8a33d; }
#sysStressBody .ldg-st-traf .dirs > .lgd.dn::before { background: #3aa0e8; }
/* 每组 = 上行(橙) + 下行(蓝) **并列**：组内 gap 6px；组两侧 5px 留白 = 组与组的间距 */
#sysStressBody .ldg-st-traf > .bars-wrap > .bars > .b { padding: 0 5px; }
#sysStressBody .ldg-st-traf > .bars-wrap > .bars > .b > .pair {
  flex: 1 1 auto; min-height: 0; width: 100%;
  display: flex; align-items: flex-end; justify-content: center; gap: 6px;
}
#sysStressBody .ldg-st-traf > .bars-wrap > .bars > .b > .pair > i {
  flex: 1 1 0; min-width: 0; max-width: 22px; width: auto;
  position: relative;    /* 柱顶数值的定位基准 = 各自那根柱（见下面 `i > .v`） */
}
/* ⚠ 整块 `.bars-wrap`（含 Y 轴刻度列）随模式一起隐藏 —— 否则"按天/按月"两套刻度会叠出**两组数字**
   （2026-09-28 用户："左边刻度线数字 重复了 出现了两组"）。 */
#sysStressBody .ldg-st-traf > .bars-wrap.wrap-month { display: none; }
#sysStressBody .ldg-st-traf.mode-month > .bars-wrap.wrap-day { display: none; }
#sysStressBody .ldg-st-traf.mode-month > .bars-wrap.wrap-month { display: flex; }
/* ── 按天：**一屏严格 7 天、等分卡片宽度**，其余靠第 2 行独立滑轨翻看
   （2026-09-28 用户："滚动条放在第二行，流量按月统计标题下面 / 每页7天柱条等分，不是按照30/31天排"）。
   ⚠ 列宽 = 可视宽 ÷ 7 ⇒ 31 天必然溢出 ⇒ 可横向滚动；**原生滚动条隐藏**，改由 `.sbar` 承担。 */
#sysStressBody .ldg-st-traf > .bars-wrap > .bars.bars-day {
  overflow-x: auto; overflow-y: hidden;
  scrollbar-width: none; -ms-overflow-style: none;
}
#sysStressBody .ldg-st-traf > .bars-wrap > .bars.bars-day::-webkit-scrollbar { display: none; }
#sysStressBody .ldg-st-traf > .bars-wrap > .bars.bars-day > .b {
  flex: 0 0 calc(100% / 7); max-width: none;
}
/* 第 2 行独立滑轨（只在"按天"显示）。2026-09-28 用户："滚动条减小一半，靠左放"
   ⇒ 宽度取一半、贴左（不再与左侧刻度列对齐），高度也收窄一点更精致。 */
#sysStressBody .ldg-st-traf > .sbar {
  flex: none; width: 50%; height: 6px; margin: 2px auto 8px 0; border-radius: 999px; position: relative;
  background: color-mix(in srgb, var(--line) 70%, transparent); cursor: pointer; display: none;
}
#sysStressBody .ldg-st-traf:not(.mode-month) > .sbar { display: block; }
#sysStressBody .ldg-st-traf > .sbar > .th {
  position: absolute; top: 0; height: 100%; border-radius: 999px;
  background: var(--primary); opacity: .55; cursor: grab;
}
#sysStressBody .ldg-st-traf > .bars-wrap > .bars.bars-month { display: none; }
#sysStressBody .ldg-st-traf.mode-month > .bars-wrap > .bars.bars-day { display: none; }
#sysStressBody .ldg-st-traf.mode-month > .bars-wrap > .bars.bars-month { display: flex; }
/* `.b` 靠 align-items 默认的 stretch 撑满 `.bars` 高度（不再用 height:100% —— 那个在
   "高度由 flex 算出来"的容器里百分比解析不稳）；柱内内容靠 column-reverse 贴底堆叠。 */
#sysStressBody .ldg-st-traf > .bars-wrap > .bars > .b {
  /* max-width = 一组两根柱的收纳上限（22 + 6 + 22 = 50，加左右各 5px 内边距 = 60）。
     按月 12 组挤在窄栏里时，列宽不到上限 ⇒ 按 flex 自然收窄（柱子跟着变细但不会被裁）。 */
  position: relative; flex: 1 1 0; min-width: 5px; max-width: 62px;
  display: flex; flex-direction: column-reverse; justify-content: flex-start;
}
/* 柱子宽度**两模式统一**（2026-09-28 用户："柱条宽要和月的一样 柱条与柱条之间的距离就可以拉开了"）：
   每根柱最宽 22px，组内两根 + 6px 间隔「居中」摆在列内 ⇒ 多出来的列宽自然变成**组与组的间距**。 */
/* ⚠ 柱子在 `.pair` 里（不是 `.b` 的直接子）—— 选择器必须带 `.pair`，否则 `display:block` 会丢，
   而 `<i>` 默认是 inline ⇒ `height:%` 无效 ⇒ **柱子整体不显示**（2026-09-28 的 bug）。 */
#sysStressBody .ldg-st-traf > .bars-wrap > .bars > .b > .pair > i {
  display: block; border-radius: 2px;
}
#sysStressBody .ldg-st-traf > .bars-wrap > .bars > .b > .pair > i.up { background: #e8a33d; }
#sysStressBody .ldg-st-traf > .bars-wrap > .bars > .b > .pair > i.dn { background: #3aa0e8; }
#sysStressBody .ldg-st-traf > .bars-wrap > .bars > .b > .lb {
  position: absolute; top: 100%; left: 0; right: 0; text-align: center;
  font-size: 11px; line-height: 1.3; color: var(--muted); white-space: nowrap;
}
#sysStressBody .ldg-st-traf > .lg {
  flex: none; display: flex; align-items: center; gap: 14px; flex-wrap: wrap;
  color: var(--muted); font-size: 14px;
}
#sysStressBody .ldg-st-traf > .lg > span > i {
  display: inline-block; width: 10px; height: 10px; border-radius: 2px; margin-right: 4px; vertical-align: -1px;
}
#sysStressBody .ldg-st-traf > .lg > span > i.up { background: #e8a33d; }
#sysStressBody .ldg-st-traf > .lg > span > i.dn { background: #3aa0e8; }
#sysStressBody .ldg-st-traf > .lg > .rt { margin-left: auto; }

/* 连接状态小胶囊 */
#sysStressBody .ldg-st-chips { display: flex; flex-wrap: wrap; gap: 8px; margin: 2px 0 6px; }
#sysStressBody .ldg-st-chips > .chip {
  font-size: 16px; color: var(--muted);
  background: rgba(127, 127, 127, .14);
  border: 1px solid var(--line);
  border-radius: 999px; padding: 2px 12px;
}
#sysStressBody .ldg-st-chips > .chip > b { color: var(--text); font-weight: 700; margin-left: 2px; }
#sysStressBody .ldg-st-chips > .chip.is-warn { border-color: #e8a33d; color: #e8a33d; }
#sysStressBody .ldg-st-chips > .chip.is-warn > b { color: #e8a33d; }

/* ── 右栏：异常监测 ── */
#sysStressBody .ldg-st-alerts { display: flex; flex-direction: column; gap: 10px; }
#sysStressBody .ldg-st-alert {
  border: 1px solid var(--line); border-left-width: 3px; border-radius: 8px;
  padding: 8px 12px; background: rgba(127, 127, 127, .07);
}
#sysStressBody .ldg-st-alert.is-bad { border-left-color: #e2564a; }
#sysStressBody .ldg-st-alert.is-warn { border-left-color: #e8a33d; }
#sysStressBody .ldg-st-alert.is-ok { border-left-color: var(--line); }
#sysStressBody .ldg-st-alert > .hd { display: flex; align-items: baseline; gap: 8px; font-size: 16px; }
#sysStressBody .ldg-st-alert > .hd > .dot {
  flex: none; width: 9px; height: 9px; border-radius: 50%; background: var(--line);
  position: relative; top: -2px;
}
#sysStressBody .ldg-st-alert.is-bad > .hd > .dot { background: #e2564a; }
#sysStressBody .ldg-st-alert.is-warn > .hd > .dot { background: #e8a33d; }
#sysStressBody .ldg-st-alert > .hd > .nm { font-weight: 600; color: var(--text); }
#sysStressBody .ldg-st-alert > .hd > .lv { font-size: 16px; color: var(--muted); }
#sysStressBody .ldg-st-alert.is-bad > .hd > .lv { color: #e2564a; }
#sysStressBody .ldg-st-alert.is-warn > .hd > .lv { color: #e8a33d; }
#sysStressBody .ldg-st-alert > .hd > .val {
  margin-left: auto; flex: none; font-weight: 700; color: var(--text); font-variant-numeric: tabular-nums;
}
#sysStressBody .ldg-st-alert > .dt { margin-top: 3px; font-size: 16px; color: var(--muted); }
#sysStressBody .ldg-st-alert > .hn {
  margin-top: 3px; font-size: 16px; color: var(--muted); opacity: .85; line-height: 1.6;
}

/* 异常记录（历史）：一行 = 时间 · 项目 · 变化 · 当时的值
   （2026-09-28 新增"如果我不在看 就没有统计"那条需求；数据 = 后端落盘的越档事件，见 system_stats.py） */
#sysStressBody .ldg-st-evt {
  display: flex; align-items: baseline; gap: 10px; padding: 5px 10px;
  border-left: 3px solid var(--line); border-radius: 6px;
  font-size: 16px; background: rgba(127, 127, 127, .06);
}
#sysStressBody .ldg-st-evt + .ldg-st-evt { margin-top: 4px; }
#sysStressBody .ldg-st-evt.is-bad { border-left-color: #e2564a; }
#sysStressBody .ldg-st-evt.is-warn { border-left-color: #e8a33d; }
#sysStressBody .ldg-st-evt > .tm { flex: none; color: var(--muted); font-variant-numeric: tabular-nums; }
#sysStressBody .ldg-st-evt > .nm { flex: none; font-weight: 600; color: var(--text); }
#sysStressBody .ldg-st-evt > .k { flex: none; color: var(--muted); }
#sysStressBody .ldg-st-evt.is-bad > .k { color: #e2564a; }
#sysStressBody .ldg-st-evt.is-warn > .k { color: #e8a33d; }
#sysStressBody .ldg-st-evt > .vl {
  margin-left: auto; min-width: 0; flex: 0 1 auto; color: var(--text);
  font-variant-numeric: tabular-nums;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

@media (max-width: 1100px) {
  /* 网卡的"累计"在窄屏换行显示（2026-09-27：左栏改 2×2、右栏加宽后，窄屏易挤） */
  #sysStressBody .ldg-st-net > .rt > .total { margin-left: 0; flex-basis: 100%; }
}

/* ══════════════════════════════════════════════════════════════════════════
   全员设置页（#syssettings，2026-09-27 由弹窗改**独立页面**）
   入口 = 侧栏「全员设置」/ 开始菜单·「全员设置」→ switchView('syssettings')；容器 #sysSettingsContainer
   版式照抄标准字段页：页面标题 22px / 卡片头 20px / 正文 16px（卡片外壳由 JS 内联给）。
   ★ 2026-10-06 用户："开关按钮开启关闭在右边，给它改为放在左边，也就是放在文字的左边
     （比如夜班模式大文件，左边）" ⇒ 本行排版改为：**左＝控件（开启/关闭 分段按钮、KB/s 输入框），
     右＝标题(16px/600)+说明(16px 灰)**。`.ss-row-t` 必须给 `flex:1` 才能吃掉剩余宽度。
   ══════════════════════════════════════════════════════════════════════════ */
#sysSettingsContainer .ss-row {
  display: flex; align-items: flex-start; gap: 16px;
  padding: 10px 0; border-bottom: 1px solid var(--line); line-height: 1.7;
}
#sysSettingsContainer .ss-row:last-child { border-bottom: none; }
#sysSettingsContainer .ss-row-t { min-width: 0; flex: 1 1 auto; }
#sysSettingsContainer .ss-row-t > .t { font-size: 16px; font-weight: 600; color: var(--text); }
#sysSettingsContainer .ss-row-t > .d { font-size: 16px; color: var(--muted); margin-top: 2px; }
/* ★★ 2026-10-10 用户：①"输入框的单位放到输入框里面，不要放到外面占宽、造成文字上下不对齐"；
   ②"输入框整个宽度改成和开启/关闭一样宽"；③"下面 PDF 渲染倍率那个也一样宽" ──
   做法：左列控件**统一钉同一宽度**（开启/关闭 分段按钮 与 输入框/下拉 都是 140px）⇒ 逐行左对齐；
   单位不再单占一列，改为**绝对定位叠在输入框右内侧**（pointer-events:none，不挡点击）；
   并去掉开关原来那 4px 的额外下移，让开关与输入框**上边缘齐平**。 */
#sysSettingsContainer .ss-row > .cache-toggle-group,
#sysSettingsContainer .ss-row > .ss-field { width: 140px; flex: none; }
#sysSettingsContainer .ss-row > .cache-toggle-group { margin-top: 0; }
#sysSettingsContainer .ss-row > .cache-toggle-group > .cache-toggle-btn { flex: 1 1 0; }
#sysSettingsContainer .ss-field { position: relative; display: block; }
#sysSettingsContainer .ss-field > input,
#sysSettingsContainer .ss-field > select { width: 100%; }
#sysSettingsContainer .ss-field > .u {
  position: absolute; right: 10px; top: 50%; transform: translateY(-50%);
  font-size: 14px; color: var(--muted); pointer-events: none;
}
@media (max-width: 900px) {
  #sysSettingsContainer .ss-row { flex-wrap: wrap; }
}

/* ══════════════════════════════════════════════════════════════════════════
   四个工具页**共用标题栏**：指令训练 / 标准字段 / 服务状态 / 全员设置
   （2026-09-27 用户："指令训练，标准字段，服务器压力表，三个标题在左上角写，点击可以原地切换，
     意思是三个表内联起来"；当天追加"全员设置也内联上"；「服务器压力表」后改名「服务状态」）
   四个页面各自在左上角渲染同一个栏：当前页高亮不可点，其余点一下原地切页；
   字号仍按页面标题口径 **22px**（与 20px 卡片头、16px 正文区分）。
   ══════════════════════════════════════════════════════════════════════════ */
/* ══════════════════════════════════════════════════════════════════════════
   工具页顶部行**统一高度**：让「卡片顶部」距右上悬浮箭头组（↑ ↓ 主页）的**底边**恒为 **15px**
   （2026-09-28 用户："顶部标题 让每个页面的卡片顶部 距离右上上下箭头主页那三个按钮的夹缝要有15px"）
   —— 全部按**布局坐标**推导（页面有 html zoom 时，fixed 的 top 与 static 的 padding 同比例，
      可直接相减，不用管 zoom 档位）：
     · 悬浮组：position:fixed; top:18px（见 lingdu-core-monitor.js 的 hostTopY()=18）
       按钮 .ldg-topstep-btn 高 41px ⇒ 组底边 = 18 + 41 = **59px**
     · 目标：卡片顶部 = 59 + 15 = **74px**
     · 页面侧：.main 的 padding-top(22px) + 顶部行高(H) + 顶部行 margin-bottom(14px) = 卡片顶部
       ⇒ H = 74 − 22 − 14 = **38px**
   故把这五个内联工具页的顶部行 min-height 设为 38px。行本来就是 display:flex;align-items:center，
   只会被撑高、内容居中，不会挪动任何控件的位置。
   ⚠ 五个 root 的**第一个子元素就是那行顶部行**（各页 renderXxxPanel 的首个 div，`<style>` 之类都在 root 之外），
     所以用 `:first-child` 命中，**不改各页 JS 的内联样式**。
   ⚠ 窄屏（≤1100px）标题栏会换行、行高自然超过 38px，此时间隙大于 15px —— 属预期，不额外压。 */
#trainingPanelRoot > div:first-child,
#stdFieldsPanelRoot > div:first-child,
#sysStressPanelRoot > div:first-child,
#sysSettingsPanelRoot > div:first-child,
#permPanelRoot > div:first-child {
  min-height: 38px;
}

.ldg-tool-tabs { display: flex; align-items: center; gap: 24px; min-width: 0; flex-wrap: wrap; }
.ldg-tool-tabs > .ldg-tool-tab {
  font-size: 22px; font-weight: 500; color: var(--muted); white-space: nowrap;
  cursor: pointer; padding-bottom: 2px; border-bottom: 2px solid transparent;
  transition: color .15s ease;
}
.ldg-tool-tabs > .ldg-tool-tab > .ic { font-size: 22px; margin-right: 6px; }
.ldg-tool-tabs > .ldg-tool-tab:hover { color: var(--text); }
.ldg-tool-tabs > .ldg-tool-tab.is-cur {
  color: var(--text); font-weight: 700; cursor: default; border-bottom-color: var(--primary);
}
@media (max-width: 1100px) {
  .ldg-tool-tabs { gap: 14px; }
  .ldg-tool-tabs > .ldg-tool-tab { font-size: 18px; }
  .ldg-tool-tabs > .ldg-tool-tab > .ic { font-size: 18px; margin-right: 4px; }
}

/* ★ 2026-10-15 字墨垂直居中补偿（全站铺开）
   —— 由 `lingdu-core.js` 的 `ldgInkMark()` 在运行时给**纯文字叶子节点**自动挂上 `.ld-ink`
      （入选条件 / 安全考量见 core 里那段注释：无子元素、非 inline、原无 transform、无背景无阴影…）；
      这里只负责**视觉平移**，不动布局、不改盒子尺寸。
   ⚠ 用 `--ld-inkfix`（em）⇒ 随字号 / `html{zoom}` 缩放档位**自动等比** ⇒ 各档位通吃；
   ⚠ 该变量**只有平板 / 手机**会写入（PC 一律不写，因为 PC 墨迹本来就居中、补了反而推高）
      ⇒ PC 下回退 `0em`、`translateY(0)` ⇒ **PC 完全无影响**。 */
.ld-ink { transform: translateY(var(--ld-inkfix, 0em)); }





