/* ==========================================================================
   智乾 IP · 0921 版升级 —— 增量样式
   --------------------------------------------------------------------------
   只放新功能用到的类，不覆盖 app.css 里的任何既有规则：
   存量页面（index/tools/booking/...）的观感完全不变，出问题也只可能出在新页面上。
   所有颜色都引用 app.css 的 --zb-* 变量，因此浅色/深色主题自动跟随。
   ========================================================================== */

/* ------------------------------------------------------------ 通用小件 */
.zb-table-wrap { overflow-x: auto; -webkit-overflow-scrolling: touch; }
.zb-table-wrap::-webkit-scrollbar { height: 8px; }

.wb-mini { font-size: 12px; color: var(--zb-text-muted); line-height: 1.5; }
.wb-basis { font-size: 12px; color: var(--zb-text-soft); max-width: 460px; white-space: normal; word-break: break-word; }

.wb-toolbar { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
/* 2026-11-06 修复：app.css 的 `.zb-select { width:100% }` 会在 flex 容器内把下拉框撑满整行，
   导致「我的/全员 / 未来60天 / 刷新数据」三段被挤成竖向三行。工具栏内改为自适应宽度。 */
.wb-toolbar .zb-select { width: auto; min-width: 120px; flex: 0 0 auto; }
.wb-scroll { max-height: 620px; overflow: auto; }
/* ⚠️ 留档（v2.4.79 踩过的坑）：CSS 变量**不能与 fr 单位拼接**。
   曾写成 `grid-template-columns: minmax(0, var(--wb-2col-main)fr) minmax(0, 1fr)`，
   Chrome 实测整条声明失效 → 两列塌成一列（会连累同样用 .wb-2col 的 workbench.html）。
   变量只可用于 calc()；此处栅格比例改回字面量 1.55fr。
   （v2.4.82 起「子案 / 同案件编号」两卡改为满宽左栏，--wb-2col-main 已无使用方。） */
.wb-2col { grid-template-columns: minmax(0, 1.55fr) minmax(0, 1fr); }
/* v2.4.113（邓老师 2026-11-02）：案件详情页两列更均衡（左主信息、右关联），
   右栏不再过于逼仄，5 列表格也能从容铺开。仅作用于 case_detail（不影响 workbench）。 */
.cd-grid { grid-template-columns: minmax(0, 1.4fr) minmax(0, 1fr); }
/* ⚠️ 塌成单列时必须写 minmax(0, 1fr)，**不能**只写 1fr。
   1fr 等价于 minmax(auto, 1fr)，auto 最小值 = 该列内容的 min-content ——
   待办清单卡的 min-content 约 353px，在 360px 视口下（可用宽仅 320px）列宽被撑到
   353px，整个文档横向溢出 13px（2026-09-29 实测：scrollW 373 / clientW 360）。
   加 minmax(0, …) 把最小轨道尺寸钉成 0，列宽才会老老实实等于容器宽。 */
@media (max-width: 1080px) { .wb-2col { grid-template-columns: minmax(0, 1fr); } }

/* 2026-11-06 邓老师：工作台指标卡（逾期 / 极急 / 紧迫 / 关注 / 窗口内合计 /
   未定级 / 我名在办，共 7 张）强制排成单行；窄屏依次降为 4 列 / 2 列。 */
.wb-metrics-row { grid-template-columns: repeat(7, minmax(0, 1fr)); }
@media (max-width: 1240px) { .wb-metrics-row { grid-template-columns: repeat(4, minmax(0, 1fr)); } }
@media (max-width: 760px)  { .wb-metrics-row { grid-template-columns: repeat(2, minmax(0, 1fr)); } }

/* 2026-11-06 邓老师：待办清单卡作为弹性列，滚动区填满；
   其高度与内部滚动上限由 workbench.js 对齐右侧栏（底部对齐"未分配代理师"卡顶）。 */
#wbTodoCard { display: flex; flex-direction: column; }
#wbTodoCard .wb-scroll { flex: 1 1 auto; min-height: 0; }

/* 分段控件（我的 / 全员） */
.zb-seg {
    display: inline-flex; padding: 3px; gap: 2px;
    background: var(--zb-bg-sunken); border: 1px solid var(--zb-border);
    border-radius: var(--zb-radius-pill);
}
.zb-seg > button {
    border: 0; background: transparent; color: var(--zb-text-soft);
    padding: 5px 14px; border-radius: var(--zb-radius-pill);
    font-size: 13px; font-weight: 600; cursor: pointer;
    box-shadow: none !important; filter: none !important;
}
.zb-seg > button:hover { color: var(--zb-text); background: transparent; }
.zb-seg > button.is-on { background: var(--zb-bg-elev); color: var(--zb-primary); box-shadow: var(--zb-shadow-1) !important; }

/* ------------------------------------------------------------ 工作台 */
.wb-todo { display: flex; align-items: flex-start; gap: 12px; padding: 12px 20px; border-bottom: 1px solid var(--zb-border); }
.wb-todo:last-child { border-bottom: 0; }
.wb-todo:hover { background: var(--zb-bg-hover); }
.wb-todo .wb-days {
    min-width: 62px; text-align: center; font-variant-numeric: tabular-nums;
    font-weight: 700; font-size: 19px; line-height: 1.1; padding-top: 2px;
}
.wb-todo .wb-days small { display: block; font-size: 11px; font-weight: 500; color: var(--zb-text-muted); }
.wb-todo .wb-main { flex: 1; min-width: 0; }
.wb-todo .wb-title { font-weight: 600; color: var(--zb-text); word-break: break-word; }
.wb-todo .wb-title a { color: inherit; }
.wb-todo .wb-title a:hover { color: var(--zb-primary); text-decoration: underline; }
.wb-todo .wb-meta { display: flex; flex-wrap: wrap; gap: 6px 10px; margin-top: 6px; align-items: center; }
.wb-todo .wb-score { font-variant-numeric: tabular-nums; font-weight: 700; min-width: 34px; text-align: right; }

/* 截止日期语气色。
 *
 * ⚠️ 2026-09-23 修：原来用亮色 token 当**文字色**，而它们正是压在白/卡片底上：
 *      .tone-warn   #c98a00 on #ffffff = 2.95:1   ← 不合格
 *      .tone-ok     #1f9d55 on #ffffff = 3.49:1   ← 仅够大字
 *      .tone-danger #d0453f on #f4f6fa = 4.21:1   ← 卡片底上仅够大字
 *    这些是 workbench 数字格里的日期/件数，属正常字号，门槛 4.5:1。
 *    换 ink 后分别 6.92 / 7.02 / 6.65。
 *
 *    另外 .cal-cell.tone-* 会给单元格铺 --zb-*-soft 底，文字色由这两个类提供 ——
 *    所以同一条 .tone-* 同时决定"压白底"和"压软底"两种情况，
 *    ink 在两种底上都达 AA（软底 6.2~6.3），不用拆成两套规则。
 */
.tone-overdue  { color: var(--zb-danger-ink); }
.tone-critical { color: var(--zb-danger-ink); }
.tone-urgent   { color: var(--zb-warn-ink); }
.tone-soon     { color: var(--zb-info-ink); }
.tone-normal   { color: var(--zb-ok-ink); }
.tone-muted    { color: var(--zb-text-muted); }

.wb-rail { width: 4px; align-self: stretch; border-radius: 3px; min-height: 34px; }
.wb-rail.tone-overdue, .wb-rail.tone-critical { background: var(--zb-danger); }
.wb-rail.tone-urgent { background: var(--zb-warn); }
.wb-rail.tone-soon { background: var(--zb-info); }
.wb-rail.tone-normal { background: var(--zb-ok); }
.wb-rail.tone-muted { background: var(--zb-border-strong); }

.wb-activity li { list-style: none; padding: 9px 0; border-bottom: 1px dashed var(--zb-border); }
.wb-activity li:last-child { border-bottom: 0; }
.wb-activity .who { font-weight: 600; font-size: 13px; }
.wb-activity .when { float: right; font-size: 12px; color: var(--zb-text-muted); }
.wb-activity .what { font-size: 13px; color: var(--zb-text-soft); margin-top: 3px; word-break: break-word; }

/* ------------------------------------------------------------ 期限日历 */
.cal-grid { display: grid; grid-template-columns: repeat(7, minmax(0, 1fr)); gap: 6px; margin-top: 8px; }
.cal-head { font-size: 12px; font-weight: 700; color: var(--zb-text-muted); text-align: center; padding: 4px 0; }
.cal-cell {
    min-height: 84px; border: 1px solid var(--zb-border); border-radius: var(--zb-radius-sm);
    background: var(--zb-bg-elev); padding: 6px 8px; cursor: default; position: relative;
    display: flex; flex-direction: column; gap: 4px; transition: box-shadow var(--zb-speed);
}
.cal-cell.is-empty { background: transparent; border-color: transparent; }
.cal-cell.has-items { cursor: pointer; }
.cal-cell.has-items:hover { box-shadow: var(--zb-shadow-2); }
.cal-cell.is-today { outline: 2px solid var(--zb-primary); outline-offset: -1px; }
.cal-cell .cal-day { font-size: 13px; font-weight: 700; color: var(--zb-text-soft); }
.cal-cell .cal-count { font-size: 20px; font-weight: 700; font-variant-numeric: tabular-nums; }
.cal-cell .cal-bar { height: 4px; border-radius: 2px; margin-top: auto; }
.cal-cell.tone-overdue, .cal-cell.tone-critical { border-color: var(--zb-danger); background: var(--zb-danger-soft); }
.cal-cell.tone-urgent { border-color: var(--zb-warn); background: var(--zb-warn-soft); }
.cal-cell.tone-soon { border-color: var(--zb-info); background: var(--zb-info-soft); }
.cal-cell.tone-normal { border-color: var(--zb-ok); background: var(--zb-ok-soft); }
.cal-bar.tone-overdue, .cal-bar.tone-critical { background: var(--zb-danger); }
.cal-bar.tone-urgent { background: var(--zb-warn); }
.cal-bar.tone-soon { background: var(--zb-info); }
.cal-bar.tone-normal { background: var(--zb-ok); }

.cal-legend { display: flex; align-items: center; gap: 16px; flex-wrap: wrap; margin-top: 14px; font-size: 12px; color: var(--zb-text-soft); }
.cal-legend .cal-dot { display: inline-block; width: 10px; height: 10px; border-radius: 3px; margin-right: 5px; vertical-align: -1px; }
.cal-dot.overdue, .cal-dot.critical { background: var(--zb-danger); }
.cal-dot.urgent { background: var(--zb-warn); }
.cal-dot.soon { background: var(--zb-info); }
.cal-dot.normal { background: var(--zb-ok); }
.cal-detail { margin-top: 10px; }
@media (max-width: 760px) {
    .cal-cell { min-height: 62px; padding: 5px; }
    .cal-cell .cal-count { font-size: 16px; }
    .cal-cell .cal-day { font-size: 12px; }
}

/* ------------------------------------------------------------ 案件详情 */
.cd-deadline { border-left: 5px solid var(--zb-border-strong); }
.cd-deadline.tone-overdue, .cd-deadline.tone-critical { border-left-color: var(--zb-danger); }
.cd-deadline.tone-urgent { border-left-color: var(--zb-warn); }
.cd-deadline.tone-soon { border-left-color: var(--zb-info); }
.cd-deadline.tone-normal { border-left-color: var(--zb-ok); }
.cd-dl-left { display: flex; align-items: center; gap: 22px; flex-wrap: wrap; }
.cd-dl-days { display: flex; align-items: baseline; gap: 6px; }
.cd-dl-days .v { font-size: 40px; font-weight: 800; line-height: 1; font-variant-numeric: tabular-nums; }
.cd-dl-days .u { font-size: 14px; color: var(--zb-text-muted); }
.cd-dl-meta { display: flex; flex-wrap: wrap; gap: 8px 18px; font-size: 14px; color: var(--zb-text-soft); align-items: center; }
.cd-dl-basis, .cd-dl-note { margin-top: 12px; font-size: 13px; color: var(--zb-text-soft); background: var(--zb-bg-sunken); padding: 9px 12px; border-radius: var(--zb-radius-sm); }
/* 文字用 ink 而非 --zb-warn：亮色下 #c98a00 on #fdf4dd 只有 2.69:1（13px 小字）。 */
.cd-dl-note { background: var(--zb-warn-soft); color: var(--zb-warn-ink); }

.cd-fields th { width: 116px; color: var(--zb-text-muted); font-weight: 600; background: transparent; }
.cd-fields td { word-break: break-word; }
.cd-sub { font-size: 13px; color: var(--zb-text-muted); margin: 16px 0 6px; font-weight: 700; text-transform: none; }
/* v2.4.80：「同一申请人」标题超链接（跳主页查该申请人的全部案件）。
   视觉沿用 .preview-idlink（蓝色可点），但字号跟着 .cd-sub 走。 */
.cd-sublink { color: var(--zb-primary); text-decoration: none; cursor: pointer; }
.cd-sublink:hover { text-decoration: underline; background: var(--zb-primary-soft); }
.cd-sub .wb-mini { font-weight: 400; margin-left: 8px; }

/* v2.4.81：「子案 / 同案件编号」两张卡加了第四列「状态日期」后，
   卡片宽度固定在 543px（右栏参照卡宽度），名称列会被压得很难看。
   处理：名称列给最小宽度（不足时表格横向滚动，而不是把文字挤成竖排一列）。 */
.cd-cases-table { table-layout: auto; width: 100%; }
.cd-cases-table th:nth-child(2), .cd-cases-table td:nth-child(2) { min-width: 150px; }
/* 状态 / 状态日期两列不参与压缩（徽章+日期是定宽内容） */
.cd-cases-table th:nth-child(3), .cd-cases-table td:nth-child(3),
.cd-cases-table th:nth-child(4), .cd-cases-table td:nth-child(4) { white-space: nowrap; }
/* 整表可横向滚动：宽度不够时出滚动条，而不是压扁列宽。
   ⚠️ table 要 width:100% 铺满容器 —— 只写 min-width:100% 时表格会按内容宽度
   收缩（实测卡片 543px、表格只占 62%，右侧留一大块空白）。 */
.cd-subcard, .cd-family { overflow-x: auto; }

/* v2.4.113（邓老师 2026-11-02）：关联信息卡（合同/客户/项目）表格改为固定布局 + 自动换行。
   根因：这些表用的是基础 .zb-table（table-layout:auto 且表头 white-space:nowrap），
   多列时表格被内容撑宽、溢出窄右栏，最右列的值被挤出卡片背景
   （即"字段明明有值却显示不出来 / 卡片内容超出背景色"）。
   现固定布局铺满卡片、内容可换行，各表视觉等宽、整齐；overflow-x 作安全网。 */
.cd-relcard { overflow-x: auto; }
.cd-relcard > .zb-table { table-layout: fixed; }
.cd-relcard > .zb-table th,
.cd-relcard > .zb-table td { white-space: normal; word-break: break-word; overflow-wrap: anywhere; }
/* 编号/号类列与名称/摘要列给足宽度，其余均分 */
.cd-relcard > .zb-table th:nth-child(1),
.cd-relcard > .zb-table td:nth-child(1) { width: 20%; }
.cd-relcard > .zb-table th:nth-child(2),
.cd-relcard > .zb-table td:nth-child(2) { width: 32%; }

/* v2.4.80：子案详情页的「同案件编号」族谱卡（紧跟"其它字段"折叠区下方）。
   主案行给「主案」徽章、本案行给「当前」徽章并高亮，便于一眼分清自己是谁。
   v2.4.82（邓老师 2026-10-27）：**取消限宽**，与上方「案件信息」卡同宽占满左栏 ——
   原来的 calc(100% / 1.55)（= 右栏「同一申请人」卡宽度）在加了「状态日期」列后
   显得局促：表格挤在 516px 里、右侧留白，与上方 842px 的案件信息卡不协调。
   现在两张卡统一满宽左栏，视觉成一块。 */
.cd-family { margin-top: 14px; padding-top: 4px; border-top: 1px dashed var(--zb-border);
             box-sizing: border-box; }
.cd-family .cd-sub { margin-top: 12px; }
.cd-family .zb-badge { margin-left: 6px; vertical-align: middle; }
.cd-family tr.is-current { background: var(--zb-primary-soft); }
.cd-family tr.is-current td { font-weight: 600; }
/* 窄屏塌成单列时没有"右栏"可参照，恢复满宽。 */
.cd-details { margin-top: 12px; }
.cd-details summary { cursor: pointer; font-size: 13px; color: var(--zb-primary); }
.cd-list { list-style: none; padding: 0; margin: 0; }
.cd-list li { padding: 7px 0; border-bottom: 1px dashed var(--zb-border); font-size: 13px; display: flex; gap: 10px; align-items: center; flex-wrap: wrap; }
.cd-list li:last-child { border-bottom: 0; }
.cd-list li span { color: var(--zb-text-soft); flex: 1; min-width: 120px; }

/* v2.4.79：主案详情页的「子案」卡。
   位置 —— 跟着左栏「案件信息」卡（含"其它字段"折叠区）往下走，占的是
   左栏原先被网格拉伸留出的那块空白，不再掉到整页页尾。
   v2.4.82（邓老师 2026-10-27）：**取消限宽**，与上方「案件信息」卡同宽占满左栏。
   原先按 calc(100% / 1.55) 限成右栏「同一申请人」卡的宽度（543px），
   加上「状态日期」列后表格挤在 543px 里，与上方 842px 的案件信息卡不协调；
   现在两张卡统一满宽左栏，视觉成一块。 */
.cd-left { min-width: 0; }
.cd-subcard { box-sizing: border-box; }

.cd-composer textarea { width: 100%; resize: vertical; font-family: inherit; }
.cd-composer-bar { display: flex; align-items: center; justify-content: space-between; gap: 10px; margin-top: 8px; }

/* 阶段 1（2.3.13）编辑面板：字段按两列铺开，窄屏自动单列。
   ⚠️ auto-fill/auto-fit 的最小轨道尺寸**必须写真实值**（这里是 260px），
   写 minmax(0,1fr) 会让列数计算退化、塌成上千条窄轨（见 .bulk-form 的注释）。
   "防长文本撑破列"要靠字段自身的 min-width:0，不是把最小轨道钉成 0。 */
.dt-edit-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); gap: 10px 14px; }
.dt-edit-item { display: flex; flex-direction: column; gap: 4px; min-width: 0; }
.dt-edit-item > span { font-size: 12px; color: var(--zb-text-3, #6b7280); }
.dt-edit-item > .zb-input { width: 100%; box-sizing: border-box; }
.cd-composer-actions { display: flex; align-items: center; gap: 8px; }

/* 2.3.19：输入框外面多包一层 .dt-edit-row —— 日期列要在右边挂一个「× 清空」
   （绝限日期等**允许留空**：库里 14531 条里有 6556 条为空）。
   flex 下按钮固定不伸缩，输入框吃掉剩余宽度；min-width:0 防长内容撑破栅格。 */
.dt-edit-row { display: flex; align-items: center; gap: 6px; min-width: 0; }
.dt-edit-row > .zb-input { flex: 1 1 auto; min-width: 0; width: 100%; box-sizing: border-box; }
/* v2.4.16 曾在此处按硬编码名单放大长文本框（名单见 detail.js BIG_TEXT_COLS），
   v2.4.21 已删除该名单 —— 名单漏字段就是前两次没改成的原因。 */
/* v2.4.21：文本列一律 textarea，按内容长度分两档起始高度，
   之后由 detail.js 的 zbInitAutoGrow 随输入自适应撑高。
   .dt-sm 短字段（编号/状态/日期类文本）占一行不浪费版面；
   .dt-big 长字段（≥40 字：申请名称/申请人/发明人/合同摘要/备注/开票信息…）
   独占整行，起始 120px。 */
.dt-edit-item > textarea.zb-input,
.dt-edit-row > textarea.zb-input { min-height: 34px; max-height: 360px; resize: vertical; overflow-y: auto; }
.dt-edit-item > textarea.zb-input.dt-big,
.dt-edit-row > textarea.zb-input.dt-big { min-height: 120px; max-height: 560px; resize: vertical; overflow-y: auto; }
.dt-edit-item:has(> .dt-edit-row > textarea.dt-big),
.dt-edit-item:has(> textarea.dt-big) { grid-column: 1 / -1; }
.dt-clear {
    flex: 0 0 auto; width: 26px; height: 26px; padding: 0; line-height: 1;
    font-size: 15px; cursor: pointer; border-radius: 4px;
    border: 1px solid var(--zb-border); background: var(--zb-bg-sunken);
    color: var(--zb-text-3, #6b7280);
}
.dt-clear:hover { color: var(--zb-danger-ink); border-color: var(--zb-danger-ink); }

/* 2.3.17 编辑态：被 config.ini 锁死的列（默认主键 + 案件编号）置灰显示，
   让用户一眼看出"这一列就是不能改"，而不是点了没反应。 */
.dt-edit-item.is-locked > .zb-input {
    background: var(--zb-bg-sunken);
    color: var(--zb-text-3, #6b7280);
    cursor: not-allowed;
}

/* 2.3.17 操作确认弹窗（改 / 增 / 删 各弹一次，讲清后果再提交）。
   z-index 必须高过最大化层(4000) / 浮动按钮(4001) / 留言遮罩(4100)。 */
.dt-confirm-mask {
    position: fixed; inset: 0; z-index: 5200;
    display: flex; align-items: center; justify-content: center;
    background: rgba(17, 24, 39, 0.45); padding: 24px;
}
.dt-confirm-card {
    width: min(560px, 100%); max-height: 80vh; overflow: auto;
    box-shadow: 0 12px 32px rgba(17, 24, 39, 0.28);
}
.dt-confirm-card h2 { margin: 0 0 10px; font-size: 16px; }
.dt-confirm-card .zb-table { margin: 8px 0; }
.dt-confirm-card .zb-table th { width: 40%; }
.dt-confirm-card .zb-input { width: 100%; box-sizing: border-box; margin-top: 6px; }
/* 随"新出现的案件"一起新建的合同记录输入区（2.3.16）：
   与 .dt-edit-grid 同款栅格，只是默认 display:none（只有判定为 new 时才展开）。
   虚线框是刻意区别于上面的案件字段 —— 这一块写进的是**合同记录表**。 */
.dt-contract-box {
    grid-column: 1 / -1;
    display: grid; grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
    gap: 10px 14px; padding: 10px 12px; margin: 4px 0;
    border: 1px dashed var(--zb-border); border-radius: var(--zb-radius-sm);
    background: var(--zb-bg-sunken);
}
.dt-contract-box > .wb-mini { grid-column: 1 / -1; }
/* 案件编号判定提示：占整行，颜色由 JS 按判定结果设（重复=红 / 新案件=橙） */
.dt-case-hint { grid-column: 1 / -1; min-height: 18px; margin: 2px 0; }
/* 2.3.19 建议编号提示条：新增案件时系统给出本年下一个流水号，
   并提醒"案件类型 / 业务类型要人工确认"。与判定提示分开，免得被重绘冲掉。 */
.dt-case-suggest {
    grid-column: 1 / -1; margin: 2px 0; padding: 5px 8px;
    border-radius: 4px; color: var(--zb-primary);
    background: var(--zb-primary-soft); line-height: 1.6;
}
/* 2.3.20 派生字段预览：展示"提交后系统自动重算"的内容
   （状态日期 / 绝限日期 / 是否授权 / 授权日期 等），仅预览、提交时才真正落库。 */
.dt-case-derive {
    grid-column: 1 / -1; margin: 2px 0; padding: 6px 8px;
    border-radius: 4px; line-height: 1.7; font-size: 13px;
    color: var(--zb-text-soft); background: var(--zb-bg-sunken);
    border: 1px solid var(--zb-border);
}
/* 2.3.20 客户代码前缀切换（CB 公司 / CP 个人）：与上方字段栅格同宽，虚线框区分。 */
.dt-custcode-box {
    grid-column: 1 / -1; display: flex; align-items: center; flex-wrap: wrap;
    gap: 8px; padding: 6px 8px; margin: 2px 0;
    border-radius: 4px; background: var(--zb-bg-sunken); border: 1px dashed var(--zb-border);
}
.dt-custcode-box .zb-btn { margin: 0; }
.dt-custcode-hint { color: var(--zb-text-3, #6b7280); }
/* 2.3.20 超小按钮：客户代码前缀 CB/CP 切换等紧凑操作。 */
.zb-btn-xs { padding: 2px 9px; font-size: 12px; line-height: 1.5; }
.cd-comment { padding: 12px 0; border-bottom: 1px solid var(--zb-border); }
.cd-comment:last-child { border-bottom: 0; }
.cd-comment .cd-c-head { display: flex; align-items: center; gap: 8px; font-size: 13px; }
.cd-comment .cd-c-head b { color: var(--zb-text); }
.cd-comment .cd-c-head .when { margin-left: auto; color: var(--zb-text-muted); font-size: 12px; }
.cd-comment .cd-c-body { margin-top: 6px; font-size: 14px; color: var(--zb-text-soft); line-height: 1.65; word-break: break-word; }
.cd-comment .cd-c-del { border: 0; background: transparent; color: var(--zb-text-muted); cursor: pointer; font-size: 12px; box-shadow: none !important; }
.cd-comment .cd-c-del:hover { color: var(--zb-danger-ink); }
.zb-mention { color: var(--zb-primary); background: var(--zb-primary-soft); border-radius: 4px; padding: 0 4px; font-weight: 600; }

/* 时间线 */
.zb-timeline { list-style: none; margin: 0; padding: 0 0 0 18px; border-left: 2px solid var(--zb-border); }
.zb-timeline li { position: relative; padding: 8px 0 8px 14px; font-size: 13px; }
.zb-timeline li::before {
    content: ''; position: absolute; left: -25px; top: 14px;
    width: 9px; height: 9px; border-radius: 50%;
    background: var(--zb-border-strong); border: 2px solid var(--zb-bg-elev);
}
.zb-timeline li.tl-deadline::before { background: var(--zb-danger); }
.zb-timeline li.tl-grant::before { background: var(--zb-ok); }
.zb-timeline li.tl-comment::before { background: var(--zb-info); }
.zb-timeline li.tl-start::before { background: var(--zb-primary); }
.zb-timeline .tl-date { font-family: var(--zb-mono); color: var(--zb-text-muted); margin-right: 10px; }
.zb-timeline .tl-label { font-weight: 600; color: var(--zb-text); }
.zb-timeline .tl-detail { display: block; color: var(--zb-text-soft); margin-top: 3px; }

/* ------------------------------------------------------------ 数据质量 */
.qa-verdict { font-size: 15px; }
.qa-delta { color: var(--zb-danger-ink); font-weight: 700; }
.qa-bar { height: 8px; background: var(--zb-bg-sunken); border-radius: var(--zb-radius-pill); overflow: hidden; }
.qa-bar.big { height: 12px; margin: 10px 0; }
.qa-bar > i { display: block; height: 100%; background: var(--zb-ok); border-radius: inherit; }
.qa-status { display: grid; grid-template-columns: repeat(auto-fit, minmax(210px, 1fr)); gap: 14px; }
.qa-status-item .qa-status-head { display: flex; justify-content: space-between; font-size: 13px; margin-bottom: 5px; }
.qa-status-item .qa-status-head b { font-variant-numeric: tabular-nums; }

/* ------------------------------------------------------------ 控制台 */
.cs-net { border: 1px solid var(--zb-border); border-radius: var(--zb-radius-sm); padding: 12px; background: var(--zb-bg-elev); }
.cs-net.is-ok { border-color: var(--zb-ok); }
.cs-net.is-bad { border-color: var(--zb-danger); }
/* 「不可判定」= 解析正常但本机探测超时，疑似 NAT 回环（hairpin）所致。
   用虚线 + 警告色，刻意区别于「不通」的实线红色 —— 免得白翻一遍路由器配置。 */
.cs-net.is-unknown { border-style: dashed; border-color: var(--zb-warn); }
.cs-net.is-unset { border-style: dashed; }
.cs-net-head { display: flex; align-items: center; gap: 8px; margin-bottom: 8px; }
.cs-net-url { display: flex; align-items: center; gap: 8px; margin-bottom: 6px; flex-wrap: wrap; }
.cs-net-url code { font-size: 12px; word-break: break-all; color: var(--zb-text-soft); }

/* 状态徽章配色（历史上这些类名被模板写了出来但没定义样式，等于只有文字）
 *
 * ⚠️ 2026-09-23 修：这里原本把**文字色**写成 var(--zb-ok/warn/danger)，
 *    也就是"同一色系的亮色"压在它自己的软底上 —— 亮色主题实测：
 *      .zb-badge.ok     #1f9d55 on #e4f5eb = 3.09:1
 *      .zb-badge.warn   #c98a00 on #fdf4dd = 2.69:1   ← 比修前的 3.77 还差
 *      .zb-badge.danger #d0453f on #fdeceb = 3.99:1
 *    徽章是 12px 小字，AA 门槛是 4.5:1，三个都不达标。
 *
 *    更隐蔽的是：本文件**后加载**，所以它把 app.css 里已经改好的
 *    --zb-*-ink 配色又覆盖回去了 —— 而测试只验了"ink 令牌本身够不够黑"，
 *    没验"实际渲染的规则用的是哪个令牌"，于是 96 项全绿而页面照旧低对比。
 *    （这就是"测了令牌、没测级联"的坑，已补 B19 按加载顺序解析实际生效值。）
 *
 *    修法：文字用 ink（浅底深字），边框保留亮色（细描边不需要高对比）。
 */
.zb-badge.ok { color: var(--zb-ok-ink); background: var(--zb-ok-soft); border-color: var(--zb-ok); }
.zb-badge.danger { color: var(--zb-danger-ink); background: var(--zb-danger-soft); border-color: var(--zb-danger); }
.zb-badge.warn { color: var(--zb-warn-ink); background: var(--zb-warn-soft); border-color: var(--zb-warn); }
.zb-badge.muted { color: var(--zb-text-soft); background: var(--zb-bg-sunken); border-color: var(--zb-border); }

.cs-logbar { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin-bottom: 10px; }
.cs-log {
    max-height: 420px; overflow: auto; margin: 0;
    background: var(--zb-bg-sunken); border: 1px solid var(--zb-border);
    border-radius: var(--zb-radius-sm); padding: 12px;
    font-family: var(--zb-mono); font-size: 12px; line-height: 1.6;
    white-space: pre-wrap; word-break: break-all; color: var(--zb-text-soft);
}
.cs-danger-zone { border-color: var(--zb-danger); }
.cs-danger-zone h2 { color: var(--zb-danger-ink); }

/* ------------------------------------------------------------ 搜索 */
.se-bar { display: flex; gap: 10px; }
.se-bar .zb-input { flex: 1; font-size: 15px; }
.se-filters { display: flex; align-items: center; gap: 14px; flex-wrap: wrap; margin-top: 12px; }
.se-chip { display: inline-flex; align-items: center; gap: 6px; font-size: 13px; color: var(--zb-text-soft); cursor: pointer; }
.se-group { margin-bottom: 18px; }
.se-group h3 { display: flex; align-items: center; gap: 8px; font-size: 15px; margin: 0 0 10px; }
/* 搜索命中高亮。
 * 原来是 color:var(--zb-accent) 压在 var(--zb-accent-soft) 上 —— 实测 2.22:1，
 * 是本次审计里最差的一处。搜索页最该看清的就是命中词，等于把功能做没了。
 * 换 accent-ink 后 5.37:1（--zb-accent-ink 同时由 #a06a00 调深到 #8a5a00）。 */
.se-hit { font-weight: 600; background: var(--zb-accent-soft); color: var(--zb-accent-ink); border-radius: 3px; padding: 0 3px; }
.se-row-exact td { background: var(--zb-primary-soft) !important; }

/* 全局悬浮搜索（Ctrl+K）/ 检索历史 / 团队留言 共用的遮罩。
   ⚠️ 这里的 z-index 必须**高于「结果区最大化」那一层**：
   .q-scroll.is-max / #wbTodoCard.is-max / #calListCard.is-max 都是 z-index 4000，
   浮动恢复钮 #maxFloatBtn 是 4001。原值 3000 比它们低，于是"最大化后再点案件编号"
   弹出的团队留言框被最大化面板整块盖住（用户 2026-09-29 反馈：案件详情/客户/项目
   最大化后点案件编号，留言框显示不出来）。改 4100 后统一压在最上层。 */
.zp-mask {
    position: fixed; inset: 0; background: rgba(10, 16, 26, .48);
    backdrop-filter: blur(3px); z-index: 4100; display: flex; align-items: flex-start;
    justify-content: center; padding: 8vh 16px 16px;
}
.zp-box {
    width: min(760px, 100%); background: var(--zb-bg-elev); border: 1px solid var(--zb-border);
    border-radius: var(--zb-radius); box-shadow: var(--zb-shadow-3); overflow: hidden;
    display: flex; flex-direction: column; max-height: 76vh;
}
.zp-head { display: flex; align-items: center; gap: 10px; padding: 14px 16px; border-bottom: 1px solid var(--zb-border); }
.zp-head input { flex: 1; border: 0; outline: 0; background: transparent; color: var(--zb-text); font-size: 16px; }
.zp-head kbd {
    font-family: var(--zb-mono); font-size: 11px; color: var(--zb-text-muted);
    border: 1px solid var(--zb-border); border-radius: 5px; padding: 2px 6px;
}
.zp-body { overflow: auto; padding: 6px 0 14px; }
.zp-sec { padding: 8px 16px 4px; font-size: 12px; font-weight: 700; color: var(--zb-text-muted); letter-spacing: .4px; }
.zp-item { padding: 9px 16px; cursor: pointer; display: flex; gap: 12px; align-items: baseline; font-size: 14px; }
.zp-item:hover, .zp-item.is-on { background: var(--zb-primary-soft); }
.zp-item .zp-t { font-weight: 600; flex: 1; min-width: 0; word-break: break-word; }
.zp-item .zp-s { font-size: 12px; color: var(--zb-text-muted); }
.zp-foot { padding: 9px 16px; border-top: 1px solid var(--zb-border); font-size: 12px; color: var(--zb-text-muted); display: flex; gap: 16px; flex-wrap: wrap; }
.zp-empty { padding: 26px 16px; text-align: center; color: var(--zb-text-muted); font-size: 14px; }

/* 团队留言弹框（主页点标识列 / 全站复用，复用 .zp-mask/.zp-box 布局） */
.tn-box { width: min(560px, 100%); }
.tn-head { gap: 10px; }
.tn-title { font-weight: 700; font-size: 15px; }
.tn-sub { color: var(--zb-text-muted); font-size: 13px; flex: 1; min-width: 0;
          overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.tn-head kbd { cursor: pointer; font-family: var(--zb-mono); font-size: 11px;
               color: var(--zb-text-muted); border: 1px solid var(--zb-border);
               border-radius: 5px; padding: 2px 6px; }
.tn-list { padding: 6px 16px 12px; display: flex; flex-direction: column; gap: 10px;
           max-height: 46vh; overflow: auto; }
.tn-comment { border: 1px solid var(--zb-border); border-radius: var(--zb-radius-sm);
              padding: 8px 10px; background: var(--zb-bg); }
.tn-c-head { display: flex; align-items: center; gap: 8px; font-size: 13px; margin-bottom: 4px; }
.tn-c-head .when { color: var(--zb-text-muted); font-size: 12px; }
.tn-c-head .tn-c-del { margin-left: auto; border: 0; background: transparent; color: var(--zb-text-muted);
                       cursor: pointer; font-size: 12px; }
.tn-c-head .tn-c-del:hover { color: var(--zb-danger); }
.tn-c-body { font-size: 14px; line-height: 1.5; word-break: break-word; }
.tn-compose { border-top: 1px solid var(--zb-border); padding: 10px 16px 14px; }
.tn-compose textarea { width: 100%; box-sizing: border-box; resize: vertical;
                       border: 1px solid var(--zb-border); border-radius: var(--zb-radius-sm);
                       background: var(--zb-bg); color: var(--zb-text);
                       padding: 8px 10px; font: inherit; font-size: 14px; }
.tn-compose-foot { display: flex; align-items: center; justify-content: space-between; margin-top: 8px; }
.tn-hint { color: var(--zb-text-muted); font-size: 12px; }
/* 主页结果表：标识列做成可点击的链接（触发团队留言） */
.preview-idlink { color: var(--zb-primary); cursor: pointer; text-decoration: none;
                  border-bottom: 1px dashed var(--zb-primary); }
.preview-idlink:hover { background: var(--zb-primary-soft); }

/* 案件编号列 → 跳案件详情页。与"留言目标"列的虚线区分开：这里是实线 + 加粗，
   一眼能看出"点进去是另一个页面"，而不是弹一个小框。
   ⚠️ 选择器必须带上 .zb-page：app.css 的 `.zb-page a` 是 (0,1,1)，压得过
   单独的 `.preview-caselink`(0,1,0)。同优先级比的是先后顺序，跨文件不可靠，
   索性自己提到 (0,2,1)。（同款坑见 app.css 里 `a.zb-btn` 那段说明。） */
.zb-page a.preview-caselink {
    color: var(--zb-primary); font-weight: 600;
    text-decoration: none; border-bottom: 1px solid var(--zb-primary);
}
.zb-page a.preview-caselink:hover {
    background: var(--zb-primary-soft); color: var(--zb-primary-hover);
}

/* 导航条上的「← 返回」（见 _nav.html）。
   显隐用 class 而不是 [hidden]：.zb-btn 是 display:inline-flex（author 样式），
   压得过 UA 的 [hidden]{display:none}，用 hidden 属性会一直显示出来。
   !important 是为了不被别处的 display 覆盖 —— 两条规则同权重，靠 .is-on 的
   更高优先级决出胜负。 */
.zp-back { display: none !important; white-space: nowrap; gap: 0; }
.zp-back.is-on { display: inline-flex !important; }
@media (max-width: 760px) {
    /* 窄屏只留"← 返回"：导航条在 360px 下已经排满，多出的页名会把整行撑溢。 */
    .zp-back .zp-back-to { display: none; }
}

/* 导航红点 */
.zb-nav-link .zb-badge { margin-left: 6px; }

/* 「管理中心」下拉（v2.4.62，_nav.html）。5 个管理员入口收进一个 tab。
   开启方式：hover 或焦点进入（键盘可达），点击按钮则钉住/收起（app0921.js）。
   激活态对齐 app.css 的 .zb-nav-link.is-active（primary-soft 底 + primary 字）。 */
.zb-nav-drop { position: relative; display: inline-flex; }
.zb-nav-drop .zb-drop-btn {
    font: inherit; cursor: pointer; background: none; border: 0;
    color: inherit; align-items: center; gap: 2px;
}
.zb-drop-caret { font-size: 10px; margin-left: 2px; opacity: .7; }
.zb-nav-drop.is-active .zb-drop-btn {
    background: var(--zb-primary-soft); color: var(--zb-primary); font-weight: 600;
}
.zb-nav-drop .zb-drop-menu {
    display: none; position: absolute; top: 100%; left: 0; z-index: 1500;
    min-width: 148px; flex-direction: column; gap: 2px; padding: 6px;
    background: var(--zb-bg-elev); border: 1px solid var(--zb-border);
    border-radius: var(--zb-radius); box-shadow: var(--zb-shadow-3);
}
.zb-nav-drop.is-open .zb-drop-menu,
.zb-nav-drop:hover .zb-drop-menu,
.zb-nav-drop:focus-within .zb-drop-menu { display: flex; }
.zb-nav-drop .zb-drop-menu a {
    padding: 8px 10px; border-radius: var(--zb-radius-sm); font-size: 13px;
    color: var(--zb-text-soft); white-space: nowrap;
}
.zb-nav-drop .zb-drop-menu a:hover {
    background: var(--zb-bg-hover); color: var(--zb-text); text-decoration: none;
}
/* 窄屏（≤860px）：.zb-nav-links 是 overflow-x:auto 的横向滚动条，
   绝对定位的下拉会被裁掉 —— 改为 display:contents 内联展开，
   5 个入口与其它导航项并排出现在滚动行里（点击按钮切换显隐）。 */
@media (max-width: 860px) {
    .zb-nav-drop { display: contents; }
    .zb-nav-drop .zb-drop-menu { position: static; }
    .zb-nav-drop.is-open .zb-drop-menu { display: contents; }
    .zb-nav-drop .zb-drop-menu a { background: none; box-shadow: none; }
}

/* 浮动入口（给未继承 base.html 的存量页面用） */
.zp-fab {
    position: fixed; right: 18px; bottom: 18px; z-index: 2000;
    display: flex; flex-direction: column; gap: 8px; align-items: flex-end;
}
.zp-fab > button {
    width: 52px; height: 52px; border-radius: 50%; font-size: 22px;
    background: var(--zb-primary); color: #fff; border: 0; cursor: pointer;
    box-shadow: var(--zb-shadow-3);
}
.zp-fab-menu {
    display: none; flex-direction: column; gap: 6px; background: var(--zb-bg-elev);
    border: 1px solid var(--zb-border); border-radius: var(--zb-radius);
    box-shadow: var(--zb-shadow-3); padding: 8px; min-width: 176px;
}
.zp-fab-menu.is-open { display: flex; }
.zp-fab-menu a { padding: 9px 12px; border-radius: var(--zb-radius-sm); font-size: 14px; color: var(--zb-text-soft); }
.zp-fab-menu a:hover { background: var(--zb-bg-hover); color: var(--zb-text); text-decoration: none; }

/* ------------------------------------------------- 中等宽度（861~1200px）*/
/* v2.3.43 新增。这一段原先没有任何规则，落在 app.css 的"单行 nowrap"里，
   而 .zb-nav-links 是 flex-wrap:wrap —— 15~17 个导航项在 1000px 宽下会折成
   5~6 行，把左侧的品牌和右侧的用户区挤在中间，导航条高达 200px。
   仅靠 app.css 的 min-height 修法能保证"不被裁掉"，但一屏导航占掉 1/5 高度。
   这里把布局改成移动端同款：品牌 + 右侧用户区占第一行，导航项独立占满整行。
   1000px 下由 6 行降到 3 行（实测截图 _docs/_navshot_1000_mid.png）。 */
@media (min-width: 861px) and (max-width: 1200px) {
    .zb-nav { flex-wrap: wrap; padding: 7px 14px; gap: 6px; }
    .zb-brand { order: 1; margin-right: 6px; }
    .zb-nav-right { order: 2; margin-left: auto; }
    .zb-nav-links { order: 3; flex: 0 0 100%; width: 100%; gap: 2px; }
    .zb-nav-link { padding: 6px 10px; font-size: 13px; }
}

/* ------------------------------------------------------------ 移动端 */
@media (max-width: 860px) {
    /* ⚠️ 断点必须与 app.css 的移动端块对齐。
       app.css 的“响应式”块是 @media (max-width: 760px)，本文件是 860。
       761~860px（正好包含 iPad 竖屏 768）落在两者的间隙里：
       下面把 .zb-nav-links 强制成 flex:0 0 100% 想让它独占一行，
       但 .zb-nav 在那一段仍是 app.css 的 nowrap 单行 ——
       一整行塞不下就整体横着拱出去，**整页横向溢出 356px**（2026-09-23 实测）。
       所以这里必须同时把 .zb-nav 也切成换行模式，只改一半等于没改。 */
    .zb-nav { height: auto; padding: 10px 12px; flex-wrap: wrap; gap: 8px; }
    .zb-nav-links {
        order: 3; width: 100%; flex: 0 0 100%;
        overflow-x: auto; flex-wrap: nowrap; gap: 4px;
        padding: 6px 0 8px; -webkit-overflow-scrolling: touch;
    }
    .zb-nav-links::-webkit-scrollbar { display: none; }
    .zb-nav-link { white-space: nowrap; padding: 7px 11px; font-size: 13px; }
    .zb-brand small { display: none; }
    .zb-wrap { padding: 14px 12px 72px; }
    .zb-page-head h1 { font-size: 20px; }
    .zb-grid-4 { grid-template-columns: repeat(auto-fit, minmax(132px, 1fr)); }
    .zb-card { padding: 14px; border-radius: 12px; }
    .zb-table th, .zb-table td { padding: 8px 10px; font-size: 13px; }
    .wb-todo { padding: 10px 14px; }
    .wb-todo .wb-days { min-width: 48px; font-size: 16px; }
    .cd-dl-days .v { font-size: 30px; }
    .zb-timeline { padding-left: 12px; }
    .cs-log { font-size: 11px; max-height: 300px; }
    .zp-mask { padding: 12px; align-items: stretch; }
    .zp-box { max-height: 88vh; }
}

/* ==========================================================================
   查询页（index.html）
   --------------------------------------------------------------------------
   主页原先自带一段内联 <style>，布局与配色一半和设计系统重叠、一半互相打架
   （卡片化由 app.css 生效，控件却还是裸样式）。2026-09-23 把结构改成
   base.html + 设计系统组件后，这里只补 app.css 里没有的"查询页专属布局"，
   配色一律引用 --zb-* 变量，深浅主题自动跟随。
   ========================================================================== */

/* ------------------------------------------------------------ 页头右侧 */
.q-head-right { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }

/* ------------------------------------------------------------ 小标题 */
.q-sub { font-size: 13px; font-weight: 700; color: var(--zb-text-muted); margin: 16px 0 6px; }
.q-row-between { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
.q-scroll { max-height: 420px; overflow: auto; }

/* ------------------------------------------------------------ 数据表选择 */
.q-toolbar { display: flex; align-items: flex-end; gap: 12px; flex-wrap: wrap; }
.q-toolbar-item { display: flex; flex-direction: column; }
.q-toolbar-item > label { font-size: 13px; font-weight: 600; color: var(--zb-text-soft); margin-bottom: 6px; }
.q-toolbar-item .zb-select { min-width: 240px; }

/* ------------------------------------------------------------ 筛选条件 */
.q-cond-head { display: flex; align-items: baseline; gap: 10px; margin-bottom: 10px; }
.q-cond-title { font-size: 13px; font-weight: 700; color: var(--zb-text-soft); }
.q-cond-hint { font-size: 12px; color: var(--zb-text-muted); }

/* 条件行 = 字段 / 值 / 逻辑 / 删除 四列。
   删除按钮做成 32px 幽灵图标、默认低调悬停才变红：原先 8 行条件各跟一个
   蓝色实心「删除」按钮，视觉噪音比内容本身还抢眼，也看不出哪一行在说什么。 */
#conditions .condition-row {
    display: grid;
    grid-template-columns: minmax(170px, 230px) minmax(200px, 1fr) 84px 32px;
    align-items: center;
    gap: 8px;
    margin: 8px 0;
}
#conditions .condition-row .zb-select,
#conditions .condition-row .zb-input { width: 100%; box-sizing: border-box; }
#conditions .condition-row .cond-op { text-align: center; }
#conditions .condition-row .cond-del {
    width: 32px; height: 32px; font-size: 13px;
    color: var(--zb-text-muted); box-shadow: none !important;
}
#conditions .condition-row .cond-del:hover {
    color: var(--zb-danger-ink); border-color: var(--zb-danger); background: var(--zb-danger-soft);
}
.q-cond-actions { display: flex; gap: 8px; flex-wrap: wrap; margin-top: 12px; }

@media (max-width: 720px) {
    #conditions .condition-row {
        grid-template-columns: 1fr 1fr;
        gap: 6px;
        padding: 10px;
        border: 1px solid var(--zb-border);
        border-radius: var(--zb-radius-sm);
        background: var(--zb-bg-sunken);
    }
    #conditions .condition-row .cond-value { grid-column: 1 / -1; }
    #conditions .condition-row .cond-del { justify-self: end; }
}

/* ------------------------------------------------------------ 提交 */
/* 2026-09-23 紧凑化：原先"添加条件 / 重置为默认"占一行、引擎分段控件占一行、
   "开始查询"按钮还落在卡片外面再占一行 —— 三行控件堆起来比条件本身还高。
   现在收进同一条 .q-actionbar：左起条件操作组，提交按钮（margin-left:auto）
   顶到最右。窄屏自动折行，不需要额外的媒体查询。
   2.3.36：引擎分段控件已移除（引擎固定为新版 · SQLite），相关样式一并删除。 */
.q-actionbar {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 10px 14px;
    margin-top: 14px;
}
.q-actionbar .q-cond-actions { margin-top: 0; }
.q-submit-btn { font-size: 15px; padding: 11px 26px; margin-left: auto; }
.q-submit-btn.is-busy { cursor: progress; opacity: .8; }

/* ------------------------------------------------------------ 结果区 */
.q-actions { display: flex; gap: 8px; flex-wrap: wrap; margin: 4px 0 14px; }
.q-inline { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; margin-top: 6px; }
.q-inline .zb-input { flex: 1; min-width: 200px; max-width: 460px; }
.q-status { display: inline-block; margin-top: 8px; font-size: 13px; color: var(--zb-text-soft); }

/* 结果操作条（2026-09-30 统一）：
     [下载 Excel][下载 HTML]  [📧 发送到邮箱 …]  [邮件状态] ……………… [⛶ 最大化]
   以前「最大化」单独占一行，而那一行只有合同表才有"已自动发送"文案，
   案件信息表 / 客户信息表 / 项目表就凭空多出一行空行 —— 各表观感不统一。
   现在所有表共用这一条：动作区在左、「⋯最大化」在右（margin-left:auto 顶到最右），
   紧凑但不局促；窄屏整体折行，也不会把输入框挤成一条线。
   注意 #normalOptions / .email-send-area 的显隐由 index.html 用 style.display
   控制，值必须是 flex —— 给 block 会把这行的横向排布直接打断。 */
.q-resultbar {
    display: flex; align-items: center; flex-wrap: wrap;
    gap: 10px 14px; margin-top: 4px;
}
.q-resultbar .q-status { margin-top: 0; min-width: 0; }
.q-resultbar .q-max-btn { margin-left: auto; white-space: nowrap; }
/* 动作分组自己吃掉"最大化"以外的全部宽度。
   flex-basis 必须是 0 而不是 auto：flex 的换行是按**假设主轴尺寸**（=flex-basis）
   决定行断点的，用 auto 时分组按 max-content（含输入框上限 360px）占位，
   在 768px 这种中等宽度下会把「最大化」顶到第二行，条子凭空变成两行。
   改成 0 之后：先给「最大化」留位，剩余宽度全归分组，由分组内部的
   flex-wrap 自己决定怎么折 —— 组内不折行（见 .email-send-area），
   所以 1440/768 都是一行，只有手机宽度才整组折到下一行。 */
.q-bar-group {
    display: flex; align-items: center; flex-wrap: wrap;
    gap: 10px 14px;
    flex-grow: 1; flex-shrink: 1; flex-basis: 0%;
    min-width: 0;
}
.q-resultbar .q-actions { margin: 0; }
.email-send-area {
    display: flex; align-items: center; gap: 8px;
    /* 关键：内部**不折行**。 [标签][输入框][发送] 是一组，要折就整组折到下一行，
       绝不能把「发送」按钮单独甩到下一行（那正是改版前 82px 高的难看之处）。 */
    flex-wrap: nowrap;
    flex: 1 1 auto; min-width: 0; margin-top: 0;
}
.email-send-area > label {
    display: block; font-size: 13px; font-weight: 600;
    color: var(--zb-text-soft); margin-bottom: 0; white-space: nowrap;
}
/* .zb-input 的基础规则带 width:100%，在弹性行里会被 flex-basis 盖掉；
   这里显式给一个能伸缩的宽度区间，既不至于撑满整行，也不会挤成一条线。
   min-width 压到 110px：窄屏下先让输入框变窄，而不是把「发送」挤走。 */
.email-send-area .zb-input { flex: 1 1 140px; width: auto; min-width: 110px; max-width: 360px; }
.q-apply { margin-top: 12px; }
.q-check {
    display: inline-flex; align-items: center; gap: 8px;
    font-size: 13px; color: var(--zb-text-soft); margin: 10px 0; cursor: pointer;
}

/* --------------------------------------- 绝限提醒 / 专利动态的既有布局 */
/* 2026-09-23 紧凑化：三个统计块原先自成一行（.deadline-stats 的 flex 行），
   下面四个分类计数又各自占一行（.category-detail），合起来两行高度、信息却很稀。
   现在两者放进同一个 .deadline-overview 里统一流式排布：宽屏一行放下，
   窄屏自动折行；标签加 white-space:nowrap，避免被挤成两行更难读。 */
.deadline-overview {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 10px 12px;
    margin-bottom: 14px;
}
.deadline-overview .stat-item { flex: 0 0 auto; min-width: 104px; padding: 9px 14px; text-align: center; }
.deadline-overview .stat-number { font-size: 24px; font-weight: 700; line-height: 1.15; }
.deadline-overview .stat-label { font-size: 12.5px; margin-top: 2px; white-space: nowrap; }
.deadline-overview .category-detail { flex: 1 1 auto; margin: 0; }

.category-detail { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin: 10px 0; font-size: 13px; }
.category-item { padding: 5px 12px; border-radius: var(--zb-radius-pill); cursor: pointer; }

.agent-list { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 8px; }
.agent-tag { padding: 4px 12px; border-radius: var(--zb-radius-pill); font-size: 13px; cursor: pointer; }

/* 首页绝限提醒：四个统计块可点击展开明细（与分类项/代理师标签一致的交互） */
.deadline-overview .stat-item[data-bucket] {
    cursor: pointer;
    border: 1px solid transparent;
    border-radius: var(--zb-radius, 8px);
    transition: background-color .15s ease, border-color .15s ease, transform .08s ease;
}
.deadline-overview .stat-item[data-bucket]:hover {
    background: var(--zb-hover, rgba(0, 0, 0, .04));
    border-color: var(--zb-border, #e3e8ef);
}
.deadline-overview .stat-item[data-bucket].is-active {
    background: var(--zb-primary-soft, rgba(37, 99, 235, .10));
    border-color: var(--zb-primary, #2563eb);
}
/* 小箭头：默认向右=可展开，选中后向下=已展开，提示用户该块可点击 */
.deadline-overview .stat-item[data-bucket]::after {
    content: "\25B6";
    display: block;
    font-size: 9px;
    line-height: 1;
    margin-top: 4px;
    color: var(--zb-muted, #9aa5b1);
    opacity: .5;
}
.deadline-overview .stat-item[data-bucket].is-active::after {
    content: "\25BC";
    color: var(--zb-primary, #2563eb);
    opacity: 1;
}

.patent-dynamic-list { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 4px; }
.patent-tag { padding: 4px 12px; border-radius: var(--zb-radius-pill); font-size: 13px; }

/* ==========================================================================
   结果表打磨 + 提交按钮忙碌态（2026-09-23 追加）
   ========================================================================== */

/* 预览表最多 50 行、.q-scroll 限高 420px，必然要滚动；表头一旦跟着滚走，
   就没法知道当前这一列到底是什么字段了，所以让表头钉在滚动容器顶部。
   注意：app.css 的 .zb-table 自带 overflow:hidden（为了裁圆角），而 CSS 规定
   非 visible 的 overflow 会自建滚动盒 —— sticky 会改为相对那个盒子定位，于是
   失效；.zb-table-wrap 的 overflow-x:auto 同理。这里在查询页范围内放开这两层，
   让 .q-scroll 成为唯一的滚动盒，横向滚动仍由它承担。 */
.q-scroll .zb-table-wrap { overflow: visible; }
.q-scroll .zb-table { overflow: visible; border-radius: 0; }
.q-scroll .zb-table thead th {
    position: sticky;
    top: 0;
    z-index: 2;
    /* 表头要压住下面滚过去的行，所以需要不透明底色 + 一道自己的分隔线 */
    box-shadow: inset 0 -1px 0 var(--zb-border);
}

/* 可排序表头：默认只留一个很淡的 ⇅，悬停/激活才突出。原先每个表头都挂箭头，
   在一屏 10 来列的情况下视觉噪音比数据还抢眼。 */
.zb-table th.zb-th-sort { cursor: pointer; user-select: none; white-space: nowrap; }
.zb-table th.zb-th-sort:hover { color: var(--zb-primary); background: var(--zb-primary-soft); }
.zb-table th.zb-th-sort .zb-sort { margin-left: 5px; opacity: .3; font-size: 11px; }
.zb-table th.zb-th-sort:hover .zb-sort { opacity: .65; }
.zb-table th.zb-th-sort.is-active { color: var(--zb-primary); }
.zb-table th.zb-th-sort.is-active .zb-sort { opacity: 1; }

/* 发明名称、备注这类长文本原先会把表格撑得很宽、要横向拖着看；限宽 + 断行后
   列宽稳定，长内容靠换行容纳，整表一眼能扫完。 */
.q-scroll .zb-table td { max-width: 340px; word-break: break-word; }

/* 注：提交按钮的忙碌态规则已随按钮一起上移到 .q-actionbar 那一节
   （`.q-submit-btn.is-busy`）。原先这里的 `.q-submit .zb-btn.is-busy`
   在按钮搬进 .q-actionbar 之后就再也匹配不到任何元素了 —— 留着它
   等于忙碌态静默失效，所以删掉而不是并存。 */

@media (max-width: 720px) {
    /* 窄屏下再限宽就没有可读性了，长文本交给横向滚动 */
    .q-scroll .zb-table td { max-width: none; }
}

/* ==========================================================================
   查询页增量 · 2026-09-24（检索历史 / 保存 / 结果区最大化 / 状态门禁说明）
   ========================================================================== */

/* 筛选条件标题行右侧的工具按钮（检索历史 / 保存） */
.q-cond-head { flex-wrap: wrap; }
.q-cond-tools { margin-left: auto; display: flex; gap: 8px; flex-wrap: wrap; }

/* 结果卡片标题行（「📊 查询结果」）。最大化按钮已统一收进下方 .q-resultbar，
   这里不再需要 margin-left:auto 的占位规则。 */
.q-result-head { display: flex; align-items: center; gap: 12px; }
.q-result-head h3 { margin: 0; }

/* 结果表格区最大化：占满视口，自带滚动盒，表头 sticky 仍然生效。
   注意覆盖 .q-scroll 的 max-height:420px，让它在最大化时真正撑满。 */
.q-scroll.is-max {
    position: fixed; inset: 12px; z-index: 4000;
    background: var(--zb-bg); border: 1px solid var(--zb-border);
    border-radius: var(--zb-radius); box-shadow: var(--zb-shadow-3);
    max-height: none; overflow: auto; padding: 16px; margin-top: 0;
}
#maxFloatBtn { position: fixed; top: 18px; right: 18px; z-index: 4001; }

/* 绝限提醒里的"状态门禁"说明，提示用户这是被过滤后的口径 */
.q-gate-note { margin: 4px 0 12px; }

/* 检索历史弹框里的条目：覆盖默认 .zp-item 的横向基线，让载入/删除按钮另起一行 */
.zp-item .zp-t { font-size: 14px; }

/* ==========================================================================
   工作台待办清单增量 · 2026-09-28
   （按天数排序 / 导出 Excel / 最大化；配合案件详情页的「返回上一页」）
   ========================================================================== */

/* 卡片标题行：标题在左、工具钮在右，同一行 */
.wb-card-head {
    display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
    padding: 18px 20px 12px;
}
.wb-card-head h2 { margin: 0; padding: 0; display: flex; align-items: center; gap: 8px; }
.wb-todo-tools { margin-left: auto; display: flex; gap: 8px; flex-wrap: wrap; }
/* 排序按钮处于"已按天数排序"时点亮，避免用户忘了当前排序口径 */
.wb-todo-tools .is-on {
    color: var(--zb-primary); border-color: var(--zb-primary);
    background: var(--zb-bg-hover);
}

/* 待办清单最大化：整张卡片占满视口，工具条常驻、清单区自己滚动 */
#wbTodoCard.is-max {
    position: fixed; inset: 12px; z-index: 4000; margin: 0;
    display: flex; flex-direction: column; overflow: hidden;
    background: var(--zb-bg); border: 1px solid var(--zb-border);
    border-radius: var(--zb-radius); box-shadow: var(--zb-shadow-3);
}
#wbTodoCard.is-max .wb-card-head { flex: 0 0 auto; }
#wbTodoCard.is-max .wb-scroll { flex: 1 1 auto; max-height: none; }
/* 说明：这里**没有**浮动"恢复"钮的规则。主页查询结果区需要它（.is-max 只盖住
   表格容器、头部按钮被压在下层），而待办清单是整张卡片一起最大化、头部按钮
   本来就在视野内 —— 再挂浮动钮会出现两个"恢复"（2026-09-28 已修）。 */

@media (max-width: 720px) {
    .wb-todo-tools { margin-left: 0; width: 100%; }
}

/* ==========================================================================
   工作台增量 · 2026-09-28（指标卡 / 代理师姓名 点击过滤）
   ========================================================================== */

/* 指标卡可点击：只加很轻的边框与悬停反馈，避免 8 张卡一起"闪"成按钮 */
.zb-metric.wb-metric-click { cursor: pointer; transition: border-color .15s ease, box-shadow .15s ease; }
.zb-metric.wb-metric-click:hover { border-color: var(--zb-primary); box-shadow: 0 0 0 1px var(--zb-primary-soft); }
.zb-metric.wb-metric-click.is-on {
    border-color: var(--zb-primary);
    background: var(--zb-primary-soft, rgba(37, 99, 235, .10));
}
/* 卡片下沿的一道细条，提示"这张卡点得动"（不吃掉卡片高度） */
.zb-metric.wb-metric-click::after {
    content: ""; display: block; height: 3px; margin: 8px -12px -12px;
    border-radius: 3px; background: var(--zb-border, #e3e8ef); opacity: .8;
}
.zb-metric.wb-metric-click.is-on::after { background: var(--zb-primary, #2563eb); }

/* 过滤条：让"当前被筛过"这件事一直可见 */
.wb-filter-bar {
    display: flex; align-items: center; flex-wrap: wrap; gap: 8px;
    margin: 0 0 14px; padding: 8px 12px;
    border: 1px dashed var(--zb-primary, #2563eb);
    border-radius: var(--zb-radius, 8px);
    background: var(--zb-primary-soft, rgba(37, 99, 235, .06));
}
.wb-filter-chip {
    display: inline-flex; align-items: center; gap: 6px;
    padding: 3px 6px 3px 10px; border-radius: var(--zb-radius-pill);
    background: var(--zb-bg); border: 1px solid var(--zb-primary, #2563eb);
    color: var(--zb-primary, #2563eb); font-size: 13px;
}
.wb-filter-x {
    border: 0; background: transparent; cursor: pointer; padding: 0 4px;
    color: inherit; font-size: 13px; line-height: 1; border-radius: 50%;
}
.wb-filter-x:hover { background: var(--zb-danger-soft, rgba(220, 38, 38, .12)); color: var(--zb-danger, #dc2626); }

/* 团队负荷里的代理师姓名：可点击，且必须与"选中"态区分得开 */
.wb-agent-link {
    border: 0; background: transparent; padding: 2px 6px; margin: -2px -6px;
    font: inherit; color: var(--zb-primary, #2563eb); cursor: pointer;
    border-radius: var(--zb-radius-sm, 6px); text-decoration: underline dotted;
}
.wb-agent-link:hover { background: var(--zb-primary-soft, rgba(37, 99, 235, .12)); }
.wb-agent-link.is-on {
    background: var(--zb-primary, #2563eb); color: #fff; text-decoration: none;
}

/* ==========================================================================
   期限日历 · 本月到期清单增量 · 2026-09-28
   （排序表头 / 最大化 / 智能返回选中天）
   ========================================================================== */

/* 清单卡片最大化：整张卡片占满视口，工具条常驻、滚动盒自己撑满 */
#calListCard.is-max {
    position: fixed; inset: 12px; z-index: 4000; margin: 0;
    display: flex; flex-direction: column; overflow: hidden;
    background: var(--zb-bg); border: 1px solid var(--zb-border);
    border-radius: var(--zb-radius); box-shadow: var(--zb-shadow-3);
}
#calListCard.is-max .wb-card-head { flex: 0 0 auto; }
#calListCard.is-max .wb-scroll { flex: 1 1 auto; max-height: none; }

/* 可排序表头：点一下按该列升序/降序切换 */
.zb-table.zb-sortable thead th { cursor: pointer; user-select: none; white-space: nowrap; }
.zb-table.zb-sortable thead th:hover { color: var(--zb-primary); }
.zb-table.zb-sortable thead th.is-sorted { color: var(--zb-primary); font-weight: 700; }

/* 选中某一天后，月历格子上沿高亮、清单卡片标题处显示"某天 N 件"徽标 */
.cal-cell.is-selected { outline: 2px solid var(--zb-primary); outline-offset: -2px; }

/* ==========================================================================
   主页：未读 @提及 提醒横幅 · 2026-09-28
   （有未读 @提及 时出现，点击进入通知中心；与导航红点同源同一接口）
   ========================================================================== */
.zb-mention-banner {
    display: flex; align-items: center; gap: 10px;
    margin: 0 0 14px; padding: 10px 14px;
    border: 1px solid var(--zb-warn); border-left: 4px solid var(--zb-warn);
    border-radius: var(--zb-radius-sm); background: var(--zb-warn-soft);
    color: var(--zb-text); cursor: pointer;
}
.zb-mention-banner:hover { filter: brightness(.98); }
.zb-mention-banner .zb-mention-ic { font-size: 18px; line-height: 1; }
.zb-mention-banner .zb-mention-txt { flex: 1; min-width: 0; }
.zb-mention-banner .zb-mention-x {
    border: 0; background: transparent; cursor: pointer;
    color: var(--zb-text-muted); font-size: 15px; line-height: 1; padding: 2px 6px;
}
.zb-mention-banner .zb-mention-x:hover { color: var(--zb-text); }

/* ==========================================================================
   主页：专利动态 Top10 明细 · 2026-09-28
   （一个申请人下最多三张分表：新增 / 删除 / 状态变化）
   ========================================================================== */

/* 分表容器：三张表依次排下来，靠间距与左侧色条分隔 ——
   没有这条的话三张表会黏成一片，看不出"新增"在哪结束、"删除"从哪开始。 */
.pd-sheet { margin: 0 0 18px; }
.pd-sheet:last-child { margin-bottom: 0; }
/* 分表标题：与 .se-group h3 同规格，多一条左侧色条强化分组感 */
.pd-sheet-h {
    display: flex; align-items: center; gap: 8px;
    margin: 0 0 8px; padding: 0 0 0 10px;
    border-left: 3px solid var(--zb-primary, #2563eb);
    font-size: 15px; font-weight: 600; color: var(--zb-text);
}

/* ==========================================================================
   搜索页：收藏夹「我关注了哪些案件」 · 2026-09-28
   （与「我的保存查询」并列；重命名 = 给案件起别名，存 watches.note）
   ========================================================================== */
.se-card-note { margin: 0 0 10px; }
/* 操作列两个按钮并排不换行，避免"重命名/删除"拆成两行把行高顶开 */
.se-ops { white-space: nowrap; }
.se-ops .zb-btn + .zb-btn { margin-left: 6px; }
/* 案件已从案件表消失：关注记录仍在，但名称/状态取不到，要挑明而不是显示空白 */
.se-gone { color: var(--zb-warn-ink, #8a5a00); font-size: 13px; }

/* ==========================================================================
   列表页行内编辑 + 变更审阅 · 2026-10-01（v2.3.14）
   ========================================================================== */
/* 操作列：只放一个 ✏️（编辑中放 保存/取消），窄一点、不换行，避免把表格挤宽 */
.zb-col-op { width: 96px; white-space: nowrap; text-align: center; }
tr.is-editing { background: var(--zb-warn-bg, rgba(234, 179, 8, .10)); }
tr.is-editing .zb-col-op { width: 150px; }
/* 行内输入：撑满单元格，别让"改一个字"的框比原值短一大截 */
.rv-cell { width: 100%; min-width: 90px; padding: 4px 6px; }
.rv-op { display: inline-flex; gap: 6px; align-items: center; }

/* 变更审阅卡片 */
.rv-item { padding: 12px 14px; border-bottom: 1px solid var(--zb-border, #e5e7eb); }
.rv-item:last-child { border-bottom: 0; }
.rv-head { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
/* v2.4.14：卡片标题里的记录号（记录编号 / 项目编号 / 案件编号 / 合同号）做成
   可点直达详情的链接。原来这里是纯文本、且显示的是客户名称/项目名称，
   审批人看不出是哪一条记录、也点不进去核对。 */
.rv-head .rv-idlink, .rv-batch-table .rv-idlink { font-weight: 600; white-space: nowrap; }
.rv-head .rv-idlink:hover, .rv-batch-table .rv-idlink:hover { text-decoration: underline; }
.rv-when { color: var(--zb-text-muted, #6b7280); font-size: 12px; }
.rv-sub { margin: 4px 0 8px; color: var(--zb-text-muted, #6b7280); font-size: 13px; }
.rv-badge { padding: 2px 8px; border-radius: 999px; font-size: 12px; font-weight: 600; }
.rv-badge.ok { background: rgba(16, 185, 129, .14); color: var(--zb-ok-ink, #065f46); }
.rv-badge.warn { background: rgba(234, 179, 8, .16); color: var(--zb-warn-ink, #8a5a00); }
.rv-badge.danger { background: rgba(239, 68, 68, .14); color: var(--zb-danger-ink, #b91c1c); }
.rv-old { color: var(--zb-text-muted, #6b7280); text-decoration: line-through; }
.rv-new { color: var(--zb-ok-ink, #065f46); font-weight: 600; }
.rv-actions { display: flex; align-items: center; gap: 8px; margin-top: 8px; flex-wrap: wrap; }
.rv-note { flex: 1 1 220px; min-width: 180px; }
.rv-msg { margin: 4px 0; font-size: 13px; }
.rv-msg.error { color: var(--zb-danger-ink, #b91c1c); }

/* ===================================================================
   v2.3.24 批量修改 / 查找替换
   =================================================================== */
.zb-col-pick {
    width: 40px;
    text-align: center;
    white-space: nowrap;
}
.zb-col-pick input[type="checkbox"] {
    width: 15px;
    height: 15px;
    cursor: pointer;
    vertical-align: middle;
}

.bulk-bar {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 10px;
    margin-top: 14px;
    padding: 9px 12px;
    background: #f4f8fd;
    border: 1px solid #d6e4f5;
    border-radius: 8px;
}
.bulk-bar[hidden] { display: none; }
.bulk-bar__pick { display: inline-flex; align-items: center; gap: 5px; cursor: pointer; }
.bulk-bar__count { font-size: 13px; color: #1f5c9e; font-weight: 600; }
.bulk-bar__spacer { flex: 1 1 auto; min-width: 0; }

.bulk-box { width: min(920px, 94vw); }
.bulk-form {
    display: grid;
    /* ⚠️ auto-fit 的轨道最小尺寸**绝不能写 0**（v2.3.42 修）。
       auto-fit 的列数是"容器宽 ÷ 最小轨道尺寸"算出来的；写 minmax(0, 1fr)
       时这个除法退化（能塞下无限条），Chrome 实测生成上千条几像素宽的轨道，
       「要改的列 / 改成」各占一条窄轨 → 文字压成竖排、输入框只剩几像素，
       输入内容完全看不见（邓老师 2026-10-06 反馈）。
       这里必须给**真实的最小宽度**，让它按"至少 240px 一列"自动折行。
       而"防长内容撑破列"是另一件事，要写在字段自身的 min-width: 0 上
       （见下面 .bulk-field），两者不能混用。 */
    grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
    gap: 10px 14px;
    padding: 0 16px;
    margin-bottom: 12px;
}
.bulk-field { display: flex; flex-direction: column; gap: 4px; min-width: 0; }
/* 输入框撑满所在轨道；min-width:0 防止 select 的默认最小宽度把轨道顶破 */
.bulk-field .zb-input { width: 100%; min-width: 0; box-sizing: border-box; }
.bulk-field__label { font-size: 12px; color: #5a6b7d; }
.bulk-field__hint { font-size: 11px; color: #8a97a5; line-height: 1.5; }
.bulk-warn {
    grid-column: 1 / -1;
    margin: 2px 0 0;
    color: #a15c00;
    line-height: 1.6;
}

/* 预览区同样要有左右内边距：.zp-body 自身不带横向 padding，
   不加的话清单表格贴着弹框边框（与 .zp-head/.zp-foot 的 16px 不对齐） */
.bulk-result { padding: 0 16px; }

.bulk-stat {
    margin: 4px 0 8px;
    font-size: 13px;
    color: #333;
}
.bulk-stat b { color: #b34a00; font-size: 15px; }
.bulk-list { max-height: 46vh; overflow: auto; border: 1px solid #e2e8f0; border-radius: 6px; }
.bulk-diff { display: inline-block; margin-right: 10px; font-size: 12px; }
.bulk-diff s { color: #98a4b0; }
.bulk-diff b { color: #1f7a3d; }

/* ==========================================================================
   v2.3.25 列表列折叠
   窄屏（≤720px）只显示 [display] core_cols_<表> 点名的列，其余由服务端打上
   col-extra、在这里折叠；右上角「全部列 / 精简」开关切 body.show-all-cols 展开。
   折叠放在 CSS 而不是服务端裁列：转屏 / 换设备不用重新查询，导出的 Excel
   也始终是完整字段（主页看少、拿走齐全）。
   ========================================================================== */
.q-cols-btn { display: none; }

@media (max-width: 720px) {
    .q-cols-btn { display: inline-flex; align-items: center; }
    .preview-table th.col-extra,
    .preview-table td.col-extra { display: none; }
    body.show-all-cols .preview-table th.col-extra,
    body.show-all-cols .preview-table td.col-extra { display: table-cell; }
}

/* ==========================================================================
   v2.3.26 待审超期警示
   变更审阅角标默认是 danger 红；一旦有超过 [cleanup] stale_review_hours
   （默认 24h）仍未处理的待审，改成 warn 琥珀 + 缓慢脉冲 —— 角标本身已经在
   导航里，"越久没人管"要能从余光里看出来，而不是要点进去数时间戳。
   只动背景/边框（浅色），文字沿用 --zb-warn-ink 保持对比度不降级。
   ========================================================================== */
.zb-badge.is-stale {
    color: var(--zb-warn-ink);
    background: var(--zb-warn-soft);
    border-color: var(--zb-warn);
}

@media (prefers-reduced-motion: no-preference) {
    .zb-badge.is-stale { animation: zb-stale-pulse 2.4s ease-in-out infinite; }
}

@keyframes zb-stale-pulse {
    0%, 100% { box-shadow: 0 0 0 0 rgba(201, 138, 0, 0); }
    50%      { box-shadow: 0 0 0 4px rgba(201, 138, 0, 0.18); }
}

/* ===================================================================
   v2.3.31 自然语言查询入口
   -------------------------------------------------------------------
   设计取向：与既有筛选区同一套视觉语言（沿用 .q-cond-* 的间距与配色），
   不做成"另一个功能"，避免用户以为是独立模块。
   移动端（≤720px）改为纵向堆叠，输入框占满宽度。
   =================================================================== */
.nlq-bar {
    display: flex;
    gap: 8px;
    align-items: center;
    margin-bottom: 8px;
}
.nlq-input {
    flex: 1 1 auto;
    min-width: 0;               /* ★ flex 子项默认 min-width:auto，
                                   长内容会把输入框撑破容器，栅格/弹性布局必写 */
    padding: 8px 10px;
    border: 1px solid var(--zb-border, #d8dde5);
    border-radius: 6px;
    font-size: 14px;
    background: var(--zb-bg, #fff);
    color: var(--zb-text, #1f2328);
}
.nlq-input:focus {
    outline: 2px solid rgba(0, 102, 204, 0.35);
    outline-offset: 1px;
}
.nlq-msg {
    margin: 6px 0 10px;
    padding: 8px 10px;
    border-radius: 6px;
    font-size: 13px;
    line-height: 1.6;
    border-left: 3px solid #9aa4b2;
    background: rgba(154, 164, 178, 0.08);
}
.nlq-msg small { font-size: 12px; opacity: 0.85; }
.nlq-ok   { border-left-color: #2f9e44; background: rgba(47, 158, 68, 0.08); }
.nlq-warn { border-left-color: #c98a00; background: rgba(201, 138, 0, 0.10); }

.nlq-help {
    margin: 0 0 10px;
    padding: 10px 12px;
    border: 1px dashed var(--zb-border, #d8dde5);
    border-radius: 6px;
    font-size: 13px;
    line-height: 1.8;
    background: rgba(0, 102, 204, 0.04);
}
.nlq-help ul { margin: 4px 0 6px; padding-left: 20px; }
.nlq-help li { margin: 2px 0; }
.nlq-help b  { color: var(--zb-brand, #0066cc); }
.nlq-help-tip { font-size: 12px; opacity: 0.85; }

@media (max-width: 720px) {
    .nlq-bar { flex-wrap: wrap; }
    .nlq-input { flex: 1 1 100%; }
    .nlq-help { font-size: 12px; line-height: 1.7; }
}

/* ==========================================================================
   留言考评弹窗（v2.4.20）comment-kpi
   ========================================================================== */
.ck-mask {
    position: fixed; inset: 0; z-index: 99990;
    background: rgba(0, 0, 0, .45);
    display: flex; align-items: center; justify-content: center;
    padding: 24px;
}
.ck-box {
    position: relative;
    background: var(--zb-panel, #fff);
    color: var(--zb-text, #222);
    border: 1px solid var(--zb-border, #d8dde5);
    border-radius: 10px;
    box-shadow: 0 12px 40px rgba(0, 0, 0, .25);
    width: min(920px, 100%);
    max-height: 86vh;
    display: flex; flex-direction: column;
    padding: 18px 20px 16px;
}
.ck-box h2 { margin: 0 32px 6px 0; font-size: 17px; line-height: 1.5; }
.ck-sub  { margin: 0 0 12px; font-size: 13px; opacity: .8; line-height: 1.7; }
.ck-x {
    position: absolute; top: 10px; right: 12px;
    width: 30px; height: 30px; line-height: 1;
    font-size: 20px; cursor: pointer;
    color: inherit; background: transparent;
    border: 1px solid var(--zb-border, #d8dde5);
    border-radius: 6px;
}
.ck-x:hover { background: rgba(0, 0, 0, .06); }
.ck-scroll { overflow: auto; flex: 1 1 auto; min-height: 0; }
.ck-table { width: 100%; border-collapse: collapse; font-size: 13px; }
.ck-table th, .ck-table td {
    border-bottom: 1px solid var(--zb-border, #d8dde5);
    padding: 7px 8px; text-align: left; vertical-align: top;
}
.ck-table th { position: sticky; top: 0; background: var(--zb-panel, #fff); z-index: 1; }
.ck-days { white-space: nowrap; color: #c0392b; font-weight: 600; }
.ck-body { max-width: 320px; }
.ck-time { white-space: nowrap; opacity: .75; }
.ck-foot { margin-top: 12px; text-align: right; }
.ck-btn {
    padding: 7px 20px; cursor: pointer; font-size: 13px;
    color: #fff; background: var(--zb-brand, #0066cc);
    border: 0; border-radius: 6px;
}
.ck-btn:hover { filter: brightness(1.08); }
@media (max-width: 720px) {
    .ck-mask { padding: 10px; }
    .ck-box { padding: 14px; max-height: 92vh; }
    .ck-body { max-width: 160px; }
}

/* ==========================================================================
   v2.4.110（2026-11-01）查询结果表头冻结 · 加固
   --------------------------------------------------------------------------
   邓老师反馈：查询结果表滚动时表头不再置顶（绝限提醒明细里却是好的）。
   根因有两条，都在"列宽拖拽"这套功能里：
     ① enableColResizer 给 .zb-table-wrap 写了 inline overflow-x:auto
        → 该层自建滚动盒，th 的 sticky 改为相对它定位，而它不纵向滚 → 失效；
     ② injectColResizerStyle 注入 `.zb-table.zb-resizable th{position:relative}`
        覆盖了 sticky（同特异性 + 后插入）。
   两处已在 JS 里改掉。这里再加一层 CSS 兜底：只要表在 .q-scroll 里，
   表头就一定是 sticky，且不会被任何 overflow 层破坏。
   ========================================================================== */
.q-scroll .zb-table-wrap,
.q-scroll .zb-table-wrap.zb-resizable {
    overflow: visible;
}
.q-scroll .preview-table,
.q-scroll .preview-table.zb-table,
.q-scroll .preview-table.zb-resizable {
    overflow: visible;
    border-radius: 0;
}
.q-scroll .preview-table > thead > tr > th,
.q-scroll .zb-table thead th {
    position: sticky;
    top: 0;
    z-index: 12;
    background: var(--zb-bg-sunken, #f2f4f8) !important;
    box-shadow: inset 0 -1px 0 var(--zb-border, #e3e8ef);
}
/* 最大化时 .q-scroll 自身成为全屏滚动盒，表头同样要钉住 */
.q-scroll.is-max .preview-table > thead > tr > th { z-index: 13; }

/* ==========================================================================
   v2.4.110（2026-11-01）「📑 专利动态」标题改为可点击按钮
   --------------------------------------------------------------------------
   邓老师要求：这 4 个字本身做成按钮，点开看本期**全部**案件状态变化明细。
   视觉上要仍像标题（不能变成一颗普通小按钮抢戏），但必须有明确的"可点击"提示。
   ========================================================================== */
.pd-title-btn {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    background: none;
    border: 1px solid transparent;
    border-radius: var(--zb-radius-sm, 6px);
    padding: 4px 10px 4px 4px;
    margin-left: -4px;
    font: inherit;
    font-size: 1.02em;
    font-weight: 700;
    color: var(--zb-text, #1f2937);
    cursor: pointer;
    transition: background .15s ease, border-color .15s ease, color .15s ease;
}
.pd-title-btn:hover {
    background: var(--zb-primary-soft, #eef4ff);
    border-color: var(--zb-primary, #2f6feb);
    color: var(--zb-primary, #2f6feb);
}
.pd-title-btn:active { transform: translateY(1px); }
.pd-title-btn:focus-visible { outline: 3px solid var(--zb-primary-ring, #b9d2ff); outline-offset: 1px; }
.pd-title-btn.is-open {
    background: var(--zb-primary-soft, #eef4ff);
    color: var(--zb-primary, #2f6feb);
}
.pd-title-hint {
    font-size: 11px;
    font-weight: 500;
    color: var(--zb-text-soft, #6b7280);
    background: var(--zb-bg-sunken, #f2f4f8);
    border-radius: var(--zb-radius-pill, 999px);
    padding: 1px 8px;
    white-space: nowrap;
}
.pd-title-btn:hover .pd-title-hint,
.pd-title-btn.is-open .pd-title-hint {
    color: var(--zb-primary, #2f6feb);
    background: #fff;
}

/* ==========================================================================
   v2.4.110（2026-11-01）「🎛 显示字段」面板
   ========================================================================== */
.col-pick-box { max-width: 620px; width: min(94vw, 620px); }
.col-pick-tools {
    display: flex;
    align-items: center;
    gap: 8px;
    flex-wrap: wrap;
    padding: 4px 16px 10px;
}
.col-pick-tools .zb-input { flex: 1; min-width: 140px; }
.col-pick-list {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 2px 14px;
    padding: 0 16px 10px;
    max-height: 46vh;
    overflow: auto;
}
.col-pick-item {
    display: flex;
    align-items: center;
    gap: 8px;
    font-size: 13px;
    padding: 4px 6px;
    border-radius: var(--zb-radius-sm, 6px);
    cursor: pointer;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.col-pick-item:hover { background: var(--zb-primary-soft, #eef4ff); }
.col-pick-item input { margin: 0; flex: none; }
.col-pick-item span { overflow: hidden; text-overflow: ellipsis; }
@media (max-width: 720px) {
    .col-pick-list { grid-template-columns: 1fr; max-height: 52vh; }
}

/* ==========================================================================
   2026-11-07 修改说明第 2、3 条
   · 导航左上角品牌标识换为新 logo（原图为白底不透明图，套白色圆角底，
     保证深色主题下黑字与绿色图形仍可读）
   · 数据表由下拉框改为同行标签（点击等价于原下拉选择）
   ========================================================================== */
.zb-brand-logo {
    display: block;
    /* v2.4.153（2026-11-07 邓老师）：logo 等比放大 36→48px；width:auto 保证
       「图形 + 中文智乾 + 英文 IP & Legal Services」三者一起按比例变大。 */
    height: 48px;
    width: auto;
    /* v2.4.158：图片本身已是透明底，绝不能再套白底，否则深色主题下又成白补丁。
       padding 与 content-box 刻意保留，维持与 v2.4.153 完全一致的视觉尺寸。 */
    background: transparent;
    border-radius: 0;
    padding: 2px 4px;
    box-sizing: content-box;
}
@media (max-width: 720px) {
    .zb-brand-logo { height: 34px; }
}

/* v2.4.158（2026-11-07 邓老师拍板）：logo 随系统主题自适应。
   两套判据必须与 app.css 的颜色变量逐字对齐，缺一不可：
     ① 系统深色且未手动锁浅色 → @media (prefers-color-scheme: dark)
        :root:not([data-theme="light"])
     ② 手动锁深色（_assets.html 用 localStorage 'zb-theme' / ui_theme 落地）
        → :root[data-theme="dark"]
   系统浅色 + 手动锁深色走 ②；系统深色 + 手动锁浅色两条都不匹配 → 浅色版。
   .zb-brand 是 flex 容器，隐藏的一张必须真正 display:none（不能只降透明度），
   否则两张图会并排占位、把导航撑宽。 */
.zb-brand .zb-brand-logo.logo-dark { display: none; }
@media (prefers-color-scheme: dark) {
    :root:not([data-theme="light"]) .zb-brand .zb-brand-logo.logo-light { display: none; }
    :root:not([data-theme="light"]) .zb-brand .zb-brand-logo.logo-dark  { display: block; }
}
:root[data-theme="dark"] .zb-brand .zb-brand-logo.logo-light { display: none; }
:root[data-theme="dark"] .zb-brand .zb-brand-logo.logo-dark  { display: block; }

.q-table-tabs {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
    margin: 2px 0 6px;
}
.q-table-tab {
    appearance: none;
    -webkit-appearance: none;
    border: 1px solid var(--zb-border, #dde3ed);
    background: var(--zb-bg-elev, #fff);
    color: var(--zb-text, #1c2430);
    border-radius: 999px;
    padding: 6px 16px;
    font-size: 14px;
    line-height: 1.45;
    font-family: inherit;
    cursor: pointer;
    white-space: nowrap;
    transition: background .15s ease, border-color .15s ease, color .15s ease;
}
.q-table-tab:hover {
    border-color: var(--zb-primary, #2f5496);
    color: var(--zb-primary, #2f5496);
    background: var(--zb-primary-soft, #e7edf9);
}
.q-table-tab.is-active {
    background: var(--zb-primary, #2f5496);
    border-color: var(--zb-primary, #2f5496);
    color: #fff;
    font-weight: 600;
}
.q-table-tab.is-active:hover {
    background: var(--zb-primary-hover, #27467e);
    border-color: var(--zb-primary-hover, #27467e);
    color: #fff;
}
.q-table-tab:focus-visible {
    outline: 2px solid var(--zb-primary-ring, rgba(47, 84, 150, .18));
    outline-offset: 2px;
}

/* ==========================================================================
   v2.4.154（2026-11-07 邓老师）：筛选条件折叠 + 结果区客户端分页
   PA / BM 不填条件即可查全部；条件区默认折起，提交条始终可见；
   结果不设数量上限，按每页 200 行翻页展示，分页条吸底方便连续翻阅。
   ========================================================================== */
.q-cond-toggle {
    background: none; border: 0; padding: 0; margin: 0; cursor: pointer;
    font: inherit; color: inherit; line-height: 1.4;
    display: inline-flex; align-items: center; gap: 6px;
}
.q-cond-toggle:hover { color: var(--zb-primary, #2f5496); }
.q-cond-toggle:focus-visible {
    outline: 2px solid var(--zb-primary-ring, rgba(47, 84, 150, .18));
    outline-offset: 2px;
}
.q-cond-toggle #condFoldIcon { display: inline-block; width: 12px; font-size: 12px; }
.zb-pager {
    display: flex; align-items: center; justify-content: center;
    flex-wrap: wrap; gap: 8px 12px; padding: 12px 4px 4px;
    position: sticky; bottom: 0; z-index: 3;
    background: var(--zb-bg, #fff);
    border-top: 1px solid var(--zb-border, #e3e8ef);
}
.zb-pager-info { font-size: 13px; color: var(--zb-text-soft, #5a6678); white-space: nowrap; }
.zb-pager button[disabled] { opacity: .45; cursor: default; }

/* ==========================================================================
   v2.4.158（2026-11-07 邓老师）：手机竖屏「显示字段 / HTML」按钮重叠
   --------------------------------------------------------------------------
   现象：PA 查「我的案件」后，竖屏下「📥 下载 Excel」被挤成「下／载／Excel」
   竖排、「📥 下载 HTML」同样被拉高，并与相邻行的「🎛 显示字段 9/15」叠在一起；
   横屏与桌面完全正常。
   根因：.q-resultbar 是 flex-wrap，而 #normalOptions.q-bar-group 用了
     flex-basis:0% + min-width:0（见本文件 :726-731，原意是让 768px 中等宽度下
     别把「最大化」顶到第二行）。竖屏约 390px 时这一组被压到极窄；组内
     .zb-btn 是 inline-flex（app.css:700）且未设 white-space:nowrap，中文又
     没有空格，于是逐字换行成竖排；按钮被拉高后与相邻 flex 行视觉重叠。
   修法只加 CSS、不动 HTML/JS；>720px 的横屏 / 桌面布局一行不改。
   ========================================================================== */
/* 全局加固：结果区按钮文字永不逐字竖排，也永不被 flex 压扁。
   连同 .q-actions 一起写，是为了覆盖受限提示态 #limitedNotice 里的下载按钮。 */
.q-resultbar .zb-btn,
.q-resultbar .q-actions .zb-btn,
.q-actions .zb-btn {
    white-space: nowrap;
    flex: 0 0 auto;
}
@media (max-width: 720px) {
    /* 让「下载 + 发邮件」整组独占一行，不再被 flex-basis:0% 压成 0 宽 */
    .q-resultbar { align-items: flex-start; gap: 8px 10px; }
    .q-resultbar > .q-bar-group { flex: 1 1 100%; min-width: 0; }
    /* 手填发信组也整组独占一行，内部允许折行，避免输入框被挤成一条线 */
    .q-resultbar .email-send-area { flex: 1 1 100%; flex-wrap: wrap; }
    .q-resultbar .email-send-area .zb-input { flex: 1 1 120px; min-width: 0; max-width: none; }
    /* 竖屏下不再把「最大化」顶到最右，三个次要按钮自然左对齐排成一行 */
    .q-resultbar .q-max-btn { margin-left: 0; }
    .q-resultbar .q-actions .zb-btn { padding: 8px 12px; }
}
