/* ============================================================================
 * wl-mobile.css v1.15（2026-10-03）—— WLIT 自研 Web 应用「安卓竖屏 + 折叠屏」适配基线
 * v1.13 → v1.14：**菜单栏在手机上不再挤压/重叠**。业务方 2026-09-25 报
 *   「网页 UI 界面菜单栏的选项文字过于密集，手机浏览器上直屏/折叠屏都拥挤，而且文字重叠」。
 *   根因（实测）：基线的点按口径给菜单项写了 `min-width:36px`，而应用在窄屏普遍把菜单行设成
 *   `flex-wrap:nowrap`；在 nowrap 的 flex 行里 min-width 取代了内容下限，36px 变成"收缩下限"
 *   → 45px 的文字挤进 36px 盒子、**溢出压到邻项**；整行仍超宽 → 末几项被 body 裁掉。
 *   而页面级 overflow 恒为 0，历次验收全部静默通过（EX-17 15 项里 12 项文字溢出、4 项出屏）。
 *   修法：① 菜单项 `flex:0 0 auto`（不参与伸缩 ⇒ 永不窄于文字，同时保住 `min-width:36px`
 *   的点按下限）；② 菜单容器折行而非横滑；
 *   ③ 折行后行距 6px。用 !important（注入顺序各应用不同，安全网必须赢），
 *   豁免钩子 `.wl-nav-nowrap` / `.wl-nav-scroll`。逐应用几何验收见
 *   web-common\docs\UI优化整改进度与复测记录_20260920.md 第十节。
 * v1.12 → v1.13：`.wl-ver`（36px 点按下限）与 `.wl-ex` 的**文字居中**改为 !important 钉死。
 *   由来：EX-20 实测该徽标盒高 36px 而文字中心比盒中心高 10.5px（应用行内 display:inline-block
 *   压过基线的 inline-flex），用户反馈"文字不居中、偏高"。属"安全网必须赢"一类，与点按下限同口径。
 * 迭代：v1.0 初版 → v1.1 徽标/输入框/栅格补强 → v1.2 无障碍隐藏豁免、.wrap 去内边距
 *       → v1.3 媒体查询加 screen 限定（打印媒体不再命中）、nav/表格链接/小按钮点按口径
 *       → v1.4 网格子项 min-width:0、承载宽表的卡片自身横滚
 *       → v1.5 遮罩式弹窗（.modal-mask>.modal-card）限高+内滚、按钮条 sticky 吸附、遮罩可滚
 *       → v1.6 导航/分页链接的**点按宽度**补到 ≥36px（原来只补了高度）——
 *              2026-09-20 EX-23 六档实测：五个移动档各 9 个小点按目标，逐个查出全是
 *              "高度够、宽度不够"的文本链接（导航 27×36、退出 24×36、分页 27×36，
 *              应用侧 .pager a{min-width:26px}）。属基线口径缺口（.btn-sm 一类小按钮
 *              反而补了宽度），故改基线一次修全舰队，不在各应用重复写。
 *       → v1.8 `.wl-btn` 类纳入点按口径（EX-25 实测：<a class="wl-btn"> 30~31px），
 *              且对 `button.wl-btn` 用 !important —— 应用侧更高特异性的 min-height:30px
 *              会压过基线，而点按下限属"安全网必须赢"（与 .wl-ex/.wl-ver 同一做法）。
 *              口径区别：**密度基线（wl-compact）不用 !important，适配基线（本文件）
 *              对点按下限用 !important**。
 *       → v1.7 共享注入的「📋 操作记录」入口 (#wlAuditEntry) 纳入点按口径 ——
 *              EX-11 实测它在 601–900px 折叠屏展开档只有 87×32px（应用侧修正块
 *              只写到 ≤600px）；它是 §4.24 审计入口脚本注入的**共享组件**，故改基线。
 * 当日修正（2026-09-15，EX-10 实机）：折叠屏上弹窗「保存/取消」按钮落在屏幕外且滑不出来 ——
 *       .modal-card 无 max-height/overflow、遮罩自身不可滚、fixed 相对布局视口不受软键盘影响。
 *       详见下方「遮罩式弹窗底部按钮可达性」注释块。
 * 历史修正（2026-09-12，EX-20 实测）：移除 nav{flex-wrap:wrap} —— 元素级「容器」规则会让应用自带
 *       单行顶栏折成多行（EX-20 顶栏 42→130px），而页面级溢出/布局视口指标全为 0、静默通过；
 *       改为只对链接设点按尺寸 + 豁免类 .wl-nav-nowrap / 横滑类 .nav-links、.menu。
 *       ⚠ **2026-09-25（v1.14）部分推翻**：把容器钉成 nowrap 的代价比顶栏变高更糟 ——
 *       实测菜单项被压到 36px、文字压到邻项上、末几项被 body 裁掉（EX-17/EX-03）。
 *       业务方口径：「宁可顶栏变高折行，也不接受必须拖滚动条才看得到的菜单」。
 *       故重新允许折行，并配套"菜单项不得窄于文字 + 行距 6px + 逐应用量顶栏高度/行数"
 *       （验收方式不变：这类几何缺陷只能用几何量验收，溢出指标测不出来）。
 * ----------------------------------------------------------------------------
 * 依据：WLIT-HOW21 §4.18 手机（安卓竖屏）与折叠屏适配
 * 事实源：本文件（D:\WorkBuddyApps\web-common\wl-mobile.css）
 *         各应用内的 static\wl-mobile.css 由 web-common\wl_mobile_sync.py 同步，
 *         请勿在应用内单独修改。
 * 原则：
 *   1) 桌面（>900px）表现一律不变——所有规则都在媒体查询内；
 *   2) 目标①：任何视口下页面级横向滚动 = 0（宽表在自身容器内横向滚动）；
 *   3) 目标②：点按区域 ≥ 40px、输入控件字号 ≥16px（避免移动端缩放与误触）；
 *   4) 目标③：折叠屏三种形态可用——外屏(~344px 宽)=手机竖屏、展开内屏(≈841×701,
 *      偏方的矮视口)=两列并允许竖向滚动、半折/分屏(高度 ≤520px)=压缩纵向留白；
 *   5) 特殊页面可用类名豁免：.wl-nowrap-table（保持表格布局）、.wl-desktop-only。
 * ========================================================================== */

/* ---------- 触屏通用 ---------- */
@media screen and (hover: none) and (pointer: coarse) {
  * { -webkit-tap-highlight-color: rgba(0, 0, 0, .08); }
  a, button, .btn, [role="button"], input, select, textarea { touch-action: manipulation; }
}

@media screen and (max-width: 900px) {
  html { -webkit-text-size-adjust: 100%; text-size-adjust: 100%; }
  html, body { max-width: 100%; overflow-x: hidden; }

  /* 媒体资源不得撑破容器 */
  img, canvas, video, svg, iframe { max-width: 100%; }
  pre, code { white-space: pre-wrap; word-break: break-word; }

  /* 宽表：在自身容器内横向滚动（不产生页面级横向滚动）。
     ⚠ 2026-09-30 修正（HOW21 v1.163，第 142 轮）：**受管表格必须豁免** —— `display:block` 会破坏
     表格格式化上下文，使表头 `position:sticky` 完全失效（EX-24 实测：容器滚动 800px，表头位移 800px），
     同时 `table-layout:fixed` 列宽失效。受管表格由共享件打 `table.wl-tbl-fixed`（本文件与
     wl-table.css 同特异性、谁后加载谁赢，属脆弱耦合），故在此**源头**直接排除，不再依赖加载顺序；
     横滑由包裹层 `.wl-tblwrap` 承担。未受管的普通表格行为不变。 */
  table:not(.wl-nowrap-table):not(.wl-tbl-fixed) {
    display: block;
    width: 100%;
    max-width: 100%;
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
  }

  /* ── 窄屏受管表格「能折行就折行」（2026-10-01，业务方口径：「窄屏幕改折行」）────────
     背景：受管表格（.wl-tbl-fixed / .wl-nowrap-table）默认保持固定列宽 + 容器内横滚
     （§4.19 1 行优先）。业务方要求窄屏改为折行、不要左右滑。
     但**一律折行会把最宽的表毁掉** —— 实测 EX-23：9 列的供应商档案表高 9,636→48,956px
     （5.1×）、单格折成 53 行、"编码"列一字一行，反而不可读。
     故做法是**逐表判定**（在 wl-table.js 的 fitNarrow() 里量高度后打类）：
       · 列数 ≤4            → 直接折行（实测这类表折后涨幅 1.0~1.4×，可读）
       · 列数 ≥5            → 先试折行；若表高涨幅 >1.5× 或单格折行 >12 行，退回横滚
     判定结果通过 `.wl-tbl-narrow`（折行）与 `.wl-tbl-scrollx`（保持横滚）两个类表达，
     本文件只负责这两类各自的样式；判定逻辑不在 CSS 里（CSS 量不到高度）。
     `!important` 的必要性：列宽由共享脚本写在 `<col>`/`<table>` 的行内 style 上，行内样式
     只有 !important 能压过。 */
  table.wl-tbl-narrow {
    table-layout: auto !important;      /* 让文本列能折行 */
    width: 100% !important;             /* 折行的目的就是"塞进屏宽" */
    /* ★★ 2026-10-13：**不再强制 `min-width:0` 与 `max-width:100%`**。
       这两条 + 下面 col 的 `min-width:0` 合起来＝把共享脚本算好的列宽**整段作废**，
       于是窄屏上浏览器按 `table-layout:fixed`（模板自带 wl-tbl-fixed）**等比压扁**所有列：
       门户版本表的「版本」(实需 92px)、「时间」(实需 120px) 被压到 ~60px ⇒ 真截断 ⇒ 挂 `…`。
       业务方口径：「单元格空间本来就可以容纳文字信息……『…』是因为单元格完全容纳不下
       大段文字而创建的规则」。
       现在放开让表**按内容最小宽撑开**：保底宽（库写在 `<col>`/单元格上的 min-width）生效，
       只让长文本列折行吸收压缩；连保底都塞不进屏宽时表自然变宽、由包裹层横向滚动。 */
  }
  table.wl-tbl-narrow col {
    width: auto !important;
    /* ★★ 2026-10-13：**不再把 min-width 强制为 0**。
       原来这条 `min-width:0!important` 会把共享脚本写在 `<col>` 上的列宽整段作废，
       于是窄屏折行时浏览器把各列**等比压扁** —— 短列（门户版本表：版本号实需 92px、
       时间实需 120px）掉到内容以下 ⇒ 真截断 ⇒ 挂 `…`。
       业务方口径：「单元格空间本来就可以容纳文字信息……『…』是因为单元格完全容纳不下
       大段文字而创建的规则」。现在保底宽由 `wl-table.js` 的 `narrowFloors()` 写进
       **单元格**的 `min-width`（本文件不设 th/td 的 min-width，故不会被压过）：
       原子值列与"内容本就短"的列拿保底、只让长文本列折行吸收；连保底都放不下时
       该表退回 `.wl-tbl-scrollx` 横向滚动。 */
    max-width: none !important;
  }
  /* ★★ 2026-10-13（与 JS 无关的兜底保证）：窄屏下**受管表格一律不用 `table-layout:fixed`**。
     为什么必须有这一条：`render()` 写列宽之前有一个"接管空窗"（脚本未执行 / 表刚被动态插入 /
     本函数与库接管有竞态），此时若模板自带 `wl-tbl-fixed`（fixed 布局）＋ `width:100%`，
     浏览器会把各列**按比例压扁** —— 门户版本表的「版本」(实需 92px)、「时间」(实需 120px)
     就是这样被压到 ~60px、真截断、挂 `…` 的（业务方 2026-10-13 报障）。
     auto 布局下浏览器不会压到内容以下，只会让表变宽、由包裹层横向滚动 ⇒ 结构上不可能再"假 …"。
     桌面（>900px）不受影响：那里仍按 `wl-tbl-fixed` 的契约走 fixed + 用户拖拽列宽。 */
  /* ⚠ 特异性必须**高于** `wl-table.css` 的 `table.wl-tbl-fixed{table-layout:fixed!important}`：
     两边都是 !important 时按特异性决胜负（同特异性才比加载顺序，而加载顺序在 24 个应用里不一致）。
     `html body table.x` = (0,1,3) > `table.x` = (0,1,1)，与加载顺序无关。 */
  html body table.wl-tbl-fixed,
  html body table.wl-nowrap-table,
  html body table.wl-nowrap-tab,
  html body table.wl-tbl-scrollx {
    table-layout: auto !important;
  }
  /* ★★ 2026-10-13（业务方口径：同一页面的按钮"只要能覆盖住文字就够了"，同一排必须等高、同水平线）
     —— **纯 CSS 兜底**。为什么需要它：共享脚本 wl-help.js 里已有一份等价实现（写行内 !important），
     但**有 3 个应用根本没引用 wl-help.js**（实测 EX-31 期货行情 / EX-32 / EX-33），
     它们拿不到那份口径 ⇒ 顶栏控件仍是 36px、与别的应用不一致。
     这条规则由**每个应用都会加载的移动端基线**下发，不依赖任何脚本。
     只改"高度/圆角/内边距/对齐"四项，不碰颜色字号；`!important` 用来压过应用侧的行内尺寸。
     特异性用 `html body` 打头，避免被应用里更特异的规则顶掉。 */
/* ★ 2026-10-13 R5（口径③）：**用户块一律是"纯文字 + 下划线"的可点文本** ——
     不依赖共享脚本是否给它挂上 .wl-user-btn（实测 EX-28 的 `SPAN.me` 就没被挂上 ⇒ 无下划线，
     而业务方口径是「有下划线表示可以点击就够用了」）。窄屏这里按类名兜住：
     去背景/边框/圆角/胶囊、加下划线、**不许截断**（`max-width:none` + `overflow:visible`）。 */
  html body :is(.wl-user-btn,.user-chip,#cur_user,.cur-user,.uhead,.who,.who-box,.me,.userbar,
                .wl-user,.hdr-user,#hdrUser,.wl-username,.user-name,#user-info,.user-info):not(#wlDrawerTools *) {
    background: none !important;
    border: 0 !important;
    border-radius: 0 !important;
    padding: 0 2px !important;
    text-decoration: underline !important;
    text-underline-offset: 3px;
    /* ★ 不许被父容器压窄（口径③"不截断"）：`min-width: max-content` + 不收缩，
       否则 flex 行会把用户块压到 132px 而内容 140px ⇒ scrollWidth > clientWidth（实测 EX-28）。 */
    flex: 0 0 auto !important;
    min-width: max-content !important;
    max-width: none !important;
    max-height: none !important;
    white-space: nowrap !important;
    overflow: visible !important;
    text-overflow: clip !important;
    color: inherit !important;
  }
  /* ★ 2026-10-16（全舰队普查 · 手机档实测）：上面那条 R5 口径给**所有**用户块加了"可点"的下划线，
     但**没有登录层的应用**（EX-18 社交一键分发 / EX-31 期货看板）那颗账号胶囊是**纯展示** ——
     没有会话可退，加下划线就是"看着能点却点不动"的误导（390 档实测被判 FAIL）。
     ⚠ 为什么不能只写一条低特异性的 `[data-wl-nologin="1"]{text-decoration:none}` 覆盖它：
       R5 的选择器里 `:is()` 含 `#cur_user`、`:not()` 含 `#wlDrawerTools` ⇒ 带**两个 id**、
       特异性 (2,0,2) + `!important`，普通写法（(0,x,y)）**量出来仍然是 underline**（单测
       `css_nologin_probe.py` 实测踩到）。所以这里改在**同一条规则上**排除掉纯展示块，
       再用一条**同级别**的规则（同样含 `:not(#wlDrawerTools *)` 与 `:is(#cur_user…)`）把布局兜底补回去。 */
  html body :is(.wl-user-btn,.user-chip,#cur_user,.cur-user,.uhead,.who,.who-box,.me,.userbar,
                .wl-user,.hdr-user,#hdrUser,.wl-username,.user-name,#user-info,.user-info):not(#wlDrawerTools *):not([data-wl-nologin="1"]) {
    background: none !important;
    border: 0 !important;
    border-radius: 0 !important;
    padding: 0 2px !important;
    text-decoration: underline !important;
    text-underline-offset: 3px;
    /* ★ 不许被父容器压窄（口径③"不截断"）：`min-width: max-content` + 不收缩，
       否则 flex 行会把用户块压到 132px 而内容 140px ⇒ scrollWidth > clientWidth（实测 EX-28）。 */
    flex: 0 0 auto !important;
    min-width: max-content !important;
    max-width: none !important;
    max-height: none !important;
    white-space: nowrap !important;
    overflow: visible !important;
    text-overflow: clip !important;
    color: inherit !important;
  }
  /* 纯展示用户块（`data-wl-nologin="1"`）：**布局兜底照旧**（免得窄屏把状态栏顶成两行），
     但**不给下划线、不给手型光标** —— 它点不动，就不该装成能点。 */
  html body :is(.wl-user-btn,.user-chip,#cur_user,.cur-user,.uhead,.who,.who-box,.me,.userbar,
                .wl-user,.hdr-user,#hdrUser,.wl-username,.user-name,#user-info,.user-info):not(#wlDrawerTools *)[data-wl-nologin="1"] {
    background: none !important;
    border: 0 !important;
    border-radius: 0 !important;
    padding: 0 2px !important;
    text-decoration: none !important;
    cursor: default !important;
    flex: 0 0 auto !important;
    min-width: max-content !important;
    max-width: none !important;
    max-height: none !important;
    white-space: nowrap !important;
    overflow: visible !important;
    text-overflow: clip !important;
    color: inherit !important;
  }
  /* ★ 2026-10-13 R3：窄屏顶栏里**收起 logo 图标**（业务方口径只要求"菜单 + 应用名 + 用户名"）。
     实测 EX-18/EX-21：logo 独占一行（应用名/用户名在后面几行）⇒ logo 不收起来就永远 ≥2 行。
     只隐藏图片本身，不删节点；桌面不受影响。 */
  html body :is(nav,header,.topbar,.top,.masthead,.appbar,.app-bar,.top-nav,.navbar,.tb-right,.tb-brand,.sidebar-header,.top-bar,[class*="topbar" i],[id*="TopBar" i])
    > :is(img,.logo,.wl-logo,.brand-logo,.brand img,.brand-wrap img),
  html body :is(nav,header,.topbar,.top,.masthead,.appbar,.app-bar,.top-nav,.navbar,.tb-right,.tb-brand,.sidebar-header,.top-bar,[class*="topbar" i],[id*="TopBar" i])
    :is(.brand,.brand-wrap) > img {
    display: none !important;
  }
  html body :is(nav,header,.topbar,.top,.masthead,.appbar,.app-bar,.top-nav,.navbar,.tb-right,.tb-brand,.sidebar-header,.top-bar,[class*="topbar" i],[id*="TopBar" i])
    :is(button,.btn,[role="button"],.wl-user-btn,.user-chip,.theme-btn,.icon-btn,.mini-btn,
        a.wl-top-link,a.wl-toplink,a) {
    /* 2026-10-14（EX-34 复测后**第二次**改这里）：顶栏控件高度 32px → 36px。
       为什么必须改在**这一条**上：§4.18 自己的判据是「可点目标 ≥36px」，与本条 32px !important 互相矛盾；
       而 `wl-help.js` 那侧（2026-10-14 v0.1.5 波次）也已把注入的行内值改成 36px，但**行内非 !important 压不过本条的 !important**，
       实测 EX-34 经门户打开后仍有 2 个点按目标卡在 32px（可点版本徽标 `a.ver` 48×32、帮助入口 `button.wl-help-entry` 32×32）。
       故把三个维度一起改到 36px（只改 min-height 会被本条自己的 max-height:32px 压回 32px）。
       回退：把下面三行改回 32px 并跑 wl_mobile_sync.py 回灌副本。
       ⚠ 并发提示：本文件 2026-10-13 21:39 已被改过一次到 36px，2026-10-14 15:16 又被整份写回 32px（见 wl-mobile.css.bak_ex34topbar36_*）。
       若再次整份覆盖本文件，请把这三行的 36px 一并保留，否则全舰队顶栏点按目标会重新掉回 32px。 */
    height: 36px !important;
    min-height: 36px !important;
    max-height: 36px !important;
    box-sizing: border-box !important;
    border-radius: 6px !important;
    padding: 0 8px !important;
    display: inline-flex !important;
    align-items: center !important;
    justify-content: center !important;
    line-height: 1 !important;
  }
  table.wl-tbl-narrow th,
  table.wl-tbl-narrow td {
    white-space: normal !important;
    overflow-wrap: anywhere;
    word-break: break-word;
  }
  /* 行动作/按钮不参与折行 —— 实测折行后「打开」「保存」被断成两行（"打/开"），
     按钮文字断开比单元格宽几个像素更难读。文字单元格继续折行，只把"控件"钉成一行。
     ⚠ 选择器必须覆盖到 .btn-mini / a.btn 这类"链接式按钮"，只写 button/.btn 会漏掉它们
     （实测「打开」是 <a class="btn-mini">，第一版就这么漏了）。 */
  table.wl-tbl-narrow td button,
  table.wl-tbl-narrow th button,
  table.wl-tbl-narrow td .btn,
  table.wl-tbl-narrow th .btn,
  table.wl-tbl-narrow td [class*="btn"],
  table.wl-tbl-narrow th [class*="btn"],
  table.wl-tbl-narrow td form { white-space: nowrap !important; }
  /* 折行的表若仍超宽（内容实在放不下），至少在自身容器内滑，不撑破页面 */
  .wl-tblwrap:has(> table.wl-tbl-narrow),
  .wl-tbl-wrap:has(> table.wl-tbl-narrow) { overflow-x: auto; }

  /* 表单控件：满宽 + 字号 16px + 最小点按高度 */
  input:not([type="checkbox"]):not([type="radio"]):not([type="range"]),
  select, textarea {
    width: 100%;
    max-width: 100%;
    box-sizing: border-box;
    font-size: 16px;
    min-height: 42px;
  }
  /* 无障碍隐藏元素不受满宽规则影响：:not([attr]) 把上面规则的特异性抬到 (0,1,1)，
     会压过 .visually-hidden{width:1px}，使 1px 隐藏控件（如隐藏的 file input）变成满宽，
     在窄屏凭空撑出页面级横向滚动（EX-21 实测 +247px）。此处强制还原。 */
  .visually-hidden, .sr-only, [hidden],
  input.visually-hidden, input.sr-only, input[aria-hidden="true"],
  select.visually-hidden, textarea.visually-hidden {
    width: 1px !important;
    height: 1px !important;
    min-height: 0 !important;
    padding: 0 !important;
    margin: -1px !important;
    overflow: hidden !important;
    clip: rect(0 0 0 0) !important;
    white-space: nowrap !important;
    border: 0 !important;
  }
  input[type="checkbox"], input[type="radio"] { width: 20px; height: 20px; }
  label { line-height: 1.5; }

  /* 点按下限必须赢：应用侧常用更高特异性的 `.tab{min-height:34px}` / `.theme-btn{...}`
     把按钮钉在 26~34px（EX-12 实测 8 个不合格点按目标）。安全网按本文件既有做法
     （.wl-ex/.wl-ver、.wl-btn、#uidbg-btn）用 !important —— 只会把点按区变大。 */
  button, .btn, [role="button"], input[type="submit"], input[type="button"] {
    min-height: 40px !important;
    box-sizing: border-box;
  }

  /* 弹窗/抽屉/浮层：贴边、内部滚动 */
  [role="dialog"], .modal, .dialog, .overlay > .box, .popover, .drawer,
  .modal-box, .modal-content {
    min-width: 0 !important;
    max-width: calc(100vw - 20px) !important;
    max-height: 88vh;
    overflow: auto;
  }

  /* ── 遮罩式弹窗（.modal-mask > .modal-card）底部按钮可达性 ────────────────────
     实机故障（EX-10 货号管理系统，vivo X Fold 3 Pro 折叠屏 / 2026-09-15）：
     分区字典「改」弹窗的「保存 / 取消 / 删除该字典行」在手机上够不到，上下左右都滑不出来。
     三个叠加原因：
       ① .modal-card 只有 margin:8vh + max-width，**没有 max-height、没有 overflow** ——
          视口一矮（分屏 / 半折 Flex 模式 / 软键盘弹出吃掉约 300px 可视高度）卡片底部
          就落到屏幕外；
       ② 遮罩 .modal-mask 自身没有 overflow，手机滑不动 → 落到屏幕外的部分**永远找不回来**；
       ③ position:fixed 相对「布局视口」定位，软键盘只缩小「可视视口」，固定遮罩不跟着缩，
          底部按钮正好被键盘压住。
     修复口径（三层冗余，任一层生效即按钮可达）：
       A. 卡片自身限高 + 内部纵向滚动（dvh 优先，老浏览器回落 vh）；
       B. 操作按钮条 .modal-actions 吸附卡片底部（sticky）—— 内容再长也一直看得见；
       C. 遮罩整层可滚动、卡片顶部对齐 —— 万一卡片没能滚，整层仍能滑到按钮。
     只针对 .modal-card（有明确按钮条的遮罩式弹窗），不动其它浮层。 */
  .modal-mask { overflow-y: auto; overflow-x: hidden; -webkit-overflow-scrolling: touch; }
  .modal-mask > .modal-card {
    max-height: calc(100vh - 24px);
    max-height: calc(100dvh - 24px);
    overflow-y: auto;
    overflow-x: hidden;
    -webkit-overflow-scrolling: touch;
    overscroll-behavior: contain;
    scroll-padding-bottom: 64px;   /* 输入框获得焦点/软键盘弹出时不被按钮条压住 */
    margin: 12px auto !important;
  }
  .modal-card > .modal-actions {
    position: sticky;
    bottom: 0;
    z-index: 3;
    background: var(--card, #fff);
    border-top: 1px solid var(--border, rgba(128,128,128,.25));
    padding: 10px 0 4px;
    margin-top: 10px;
  }
  /* 弹窗打开时锁住背后的页面滚动：否则手指一滑是**背后的页面**在滚、弹窗纹丝不动，
     用户以为「滑不动、按钮找不回来」（EX-10 折叠屏实测）。应用在开/关弹窗时给
     <html> 加/去 .wl-modal-open（参考 EX-10 的 syncModalScrollLock()）。
     注意：只用 overflow+overscroll-behavior，**不用 touch-action:none** ——
     后者会把弹窗内部的触屏滚动手势一起吞掉，反而更难滑。 */
  html.wl-modal-open body { overflow: hidden; overscroll-behavior: none; }

  /* 顶部导航：允许换行 + 链接区横滑，避免挤压错位 */
  /* 顶栏命名不统一：补 header 元素（EX-10/EX-23 用裸 header）。 */
  .topbar, .navbar, .header, .app-header, header { flex-wrap: wrap; }
  .topbar .links, .navbar .links, .nav-links, .menu {
    overflow-x: auto;
    white-space: nowrap;
    -webkit-overflow-scrolling: touch;
  }
  /* 导航项点按区域：手机端不足 36px 高的链接统一抬高（触屏可点性） */
  .topbar .links a, .navbar .links a, .nav-links a, .menu a, .topbar .user a {
    min-height: 40px;
    min-width: 36px;
    padding-left: 6px;
    padding-right: 6px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
  }

  /* ═══ v1.14 新增：手机/折叠屏「菜单栏不挤压、不重叠」═══════════════════════════
     缺陷（2026-09-25 业务方报「菜单栏选项文字过于密集，手机上直屏/折叠屏都拥挤、文字重叠」）：
     基线上面那条点按口径给菜单项写了 `min-width:36px`（本意是**点按下限**），
     而各应用在窄屏普遍把菜单行设成 `flex-wrap:nowrap`（EX-17 `.topbar .links`、
     EX-03 `.nav a{flex:1}`、EX-19 `nav`、EX-24 `.nav-inner`、EX-20 `.nav`…）。
     在 nowrap 的 flex 行里，`min-width` 会**取代** flex 项的 `min-width:auto`（内容下限），
     36px 于是从"下限"变成"收缩下限"：实测 EX-17 每项盒子 36px、文字 45px →
     **文字溢出盒子压到邻项文字上**（截图复核确认）；整行仍 680px 宽，末 4 项跑出 390px 视口，
     被 `html,body{overflow-x:hidden}` 裁掉 —— 而页面级 overflow 指标恒为 0，
     mob_sweep/wl check 历次全部静默通过（几何坏了但溢出量不出来）。
     两处收口：
       ① 菜单项**永不窄于自身文字**：`flex:0 0 auto`（不参与伸缩 ⇒ 基准尺寸=内容宽）。
          为什么不用 `min-width:max-content`：那会把点按下限 `min-width:36px` 顶掉，
          实测 EX-25/EX-23 手机档因此新增 12/6 个 <36px 菜单项（详见下面第 ① 条的注释）。
       ② 菜单容器**折行而不是横滑**：菜单项一眼全见（业务方 2026-09-25 口径
          「宁可顶栏变高折行，也不接受必须拖滚动条才看得到的菜单」）。
     为什么用 !important：各应用注入顺序不同 —— EX-17/EX-24 是 `<link>` 在应用 CSS 之后，
     而 EX-19 是 `app.py` 启动时把基线**内联注入在应用 CSS 之前**（base.html L8），
     非 !important 会被应用自己的 nowrap 压回去，同一缺陷只修好一半。
     这是"安全网必须赢"一类（与点按下限同口径），故用 !important；
     需要横滑或单行的应用用豁免类 `.wl-nav-scroll` / `.wl-nav-nowrap`（见文末）。 */
  body nav a, body nav button, body header a, body .nav a, body .nav button,
  body .nav-inner a, body .nav-inner button, body .nav-links a, body .menu a,
  body .tabs a, body .tabs button, body .wl-nav a, body .wl-nav button,
  body .topbar .links a, body .navbar .links a, body .topbar .user a, body header .links a {
    /* 菜单项**不参与伸缩**：flex-basis:auto ⇒ 基准尺寸 = 内容宽（或应用自己写的 width），
       flex-shrink:0 ⇒ 永不被压窄 → 文字不会溢出盒子压到邻项上。
       ★ 这里**刻意不用 `min-width:max-content`**：那样会把上面那条 `min-width:36px`
         （本文件的**点按下限**）直接顶掉。实测（对照 v1.13）：EX-23 手机/外屏档因此新增
         6 个 <36px 的菜单项、EX-25 手机档多出 12 个 31×36 的表格行内「详情/重打」链接 ——
         后者经 v1.13/v1.14 双向对照证明与本次改动**无关**（数量相同，属存量问题，已单列）。
         这类回归**几何判据看不见**，是舰队标准栈 mob_sweep 的 smallTaps 抓到的。
         两个下限必须同时成立：flex:0 0 auto 保住"不小于文字"，
         早先那条 min-width:36px 保住"不小于可点尺寸"。 */
    flex: 0 0 auto !important;
    white-space: nowrap;
  }
  body header, body nav, body .topbar, body .navbar, body .header, body .app-header,
  body .topbar-inner, body .navbar-inner, body .header-inner, body .app-header-inner,
  body .topbar .links, body .navbar .links, body header .links,
  body .nav, body .nav-inner, body .nav-links, body .menu, body .tabs, body .wl-nav {
    flex-wrap: wrap !important;
    overflow-x: visible !important;
    white-space: normal;
    /* 折行后容器高度必须自适应：应用普遍给顶栏写死 height:54px，折出来的第二行会
       **溢出盒子压到正文上**（EX-18 在 841×701 实测 8 个菜单项越出 topbar 盒子 24px，
       而 overflow 指标同样是 0）。"固定高 + 强制折行"必然溢出，故两条绑在一起改。 */
    height: auto !important;
  }
  /* 折行后的行距：菜单项盒高 36~44px，给 6px 行距把两行分开（原来 0~4px 时肉眼是"挤成一坨"） */
  body nav, body .nav, body .nav-inner, body .nav-links, body .menu, body .tabs,
  body .wl-nav, body .topbar .links, body .navbar .links, body header .links {
    row-gap: 6px;
  }
  /* EX-## 与版本号徽标（各应用顶栏通用类名）：窄屏抬高到 ≥36px 点按口径。
     各应用页面末尾注入的 how21 样式里另有 .wl-ex/.wl-ver{min-height:30px}，
     位置更靠后且同优先级会压过基线，故此处加 body 前缀 + !important 强制生效。 */
  /* 宽度也要够：EX-24 的 a.wl-ver（v1.2）实测 35×36 —— 高度够了、宽度差 1px。
     徽标是 §4.10/§4.13 注入到每个应用的**共享组件**，故在基线里一并收口。
     但**只给可交互的那个**保留 36px：`.wl-ver` 是 <a>（点开版本更新说明），
     `.wl-ex` 是 <span>（EX 编码，纯展示、不可点）—— 用户 2026-09-20 要求胶囊变矮省空间，
     把不可点的 span 也撑到 36px 只会白占顶栏高度（手机上少占 23px）。 */
  body .wl-ver { min-height: 36px !important; min-width: 36px;
    display: inline-flex !important; align-items: center !important; justify-content: center !important; }
  /* 同一组件在**竖屏 36px 点按下限**下，若元素仍是 display:inline-block（应用行内样式压过基线），
     文字会整体偏到盒子上沿（EX-20 实测 .wl-ver：盒高 36px、文字中心比盒中心高 10.5px）——
     用户 2026-09-20 反馈「文字不居中」。故用 !important 把两个方向的居中钉死（安全网必须赢）。
     `.wl-ex` 是纯展示 span，不给 36px 下限，但同样要居中。 */
  body .wl-ex { display: inline-flex !important; align-items: center !important; justify-content: center !important; }
  /* UI 调试浮标同理（debug 控件，也按 36px 点按口径） */
  body #uidbg-btn { min-height: 36px !important; }
  /* 共享注入的「📋 操作记录」入口（§4.24 审计入口脚本注入，id 全舰队一致）：
     EX-11 实测在 601–900px 折叠屏展开档只有 87×32px —— 应用侧的点按修正块
     只写在 ≤600px 档里，没覆盖这一档。因它是共享组件，在基线里统一抬到 36px。 */
  body #wlAuditEntry { min-height: 36px; display: inline-flex; align-items: center; }

  /* 表单控件字号：应用里 .input 之类类选择器会盖过元素选择器，移动端统一以 16px 兜底（防聚焦缩放） */
  body input:not([type="checkbox"]):not([type="radio"]):not([type="range"]),
  body select, body textarea,
  body .input, body input.input, body textarea.input, body select.input { font-size: 16px !important; }

  /* 主内容容器与两列栅格：窄屏不得横向溢出、两列叠放 */
  .view, .main, .page, .content, .container, .wrap { max-width: 100% !important; box-sizing: border-box; }
  .row.two, .row-2, .two-col, .split-2, .cols, .cols-2, .cols-3 { grid-template-columns: 1fr !important; }

  /* 卡片/栅格容器：窄屏一律单列（应用里 minmax(340px,1fr) 这类固定 px 下限会把布局视口撑大，
     scrollWidth−innerWidth 测不出来，必须在此归零） */
  [class*="cards"], [class*="grid"], [class*="tiles"] { grid-template-columns: 1fr !important; }

  /* 裸 <nav> 的链接点按尺寸：只改链接本身。
     ⚠ 2026-09-25（v1.14）**部分推翻**了下面这段 2026-09-12 的决定，理由写在这里免得下个会话看懵：
     当时移除 `nav{flex-wrap:wrap}` 是因为 EX-20 顶栏被折成 3 行、42→238px，
     而"溢出/布局视口"指标全是 0 —— 结论是"这类几何缺陷必须用几何量验收"，这条**依然成立**。
     但本轮实测证明：把容器钉成 nowrap 的代价是**菜单项被压到 36px、文字压到邻项上、
     末几项被 body 裁掉**（EX-17 15 项里 12 项文字溢出、4 项跑出屏幕；EX-03 同类）。
     业务方 2026-09-25 明确口径：「宁可顶栏变高折行，也不接受必须拖滚动条才看得到的菜单」。
     故 v1.14 重新允许菜单容器折行，**并配套**：菜单项不得窄于文字（防重叠）+ 行距 6px
     （防挤成一坨）+ 逐应用量顶栏高度与行数（防止重演 238px 那种失控）。
     要保留单行/横滑的应用用 `.wl-nav-nowrap` / `.wl-nav-scroll` 显式豁免。 */
  /* 导航链接：高度与**宽度**都要够（宽度不足同样误触，EX-23 实测 27px 宽的导航链接） */
  nav a { min-height: 40px; min-width: 36px; display: inline-flex; align-items: center;
    justify-content: center; }
  /* 2026-10-02 补：**侧栏 / 抽屉菜单项**的点按口径。
     由来（EX-24 实测，官方六档探针报 mobile smallTaps=26）：上一条 `nav a` 只覆盖「菜单容器是
     <nav> 且项是 <a>」的形态；侧栏类应用（EX-24 的 `.side-item/.side-home/.side-ver`、多数门户的
     `.sidebar-item/.drawer-item/.menu-item`）用的是 <div>/<span>/<a> 挂自定义类，基线全盖不到，
     于是 28~30px 高的菜单行直接进"<36px 点按目标"清单。
     口径与基线既有做法一致：只在窄屏档抬到 36px 下限（桌面不动），`!important` 是为了赢过
     密度基线 body.wl-compact .menu-item{padding:...} 这类更低特异性的写法；
     `justify-content:flex-start` 保持左对齐（不居中，避免菜单文字被推到中间）。 */
  nav a, .side-item, .side-home, .side-ver, .sidebar-item, .sidebar a, .sidebar-link,
  .sidenav a, .drawer a, .drawer-item, .menu-item, .nav-item, .menu a {
    min-height: 36px; min-width: 36px;
    display: inline-flex; align-items: center; justify-content: flex-start;
  }
  /* 2026-10-02 补②：**顶栏图标按钮**的宽度下限。
     由来（EX-24 实测，A/B 对照）：侧栏覆盖后 mobile smallTaps 25 → 6，剩下 6 个全是顶栏控件
     ——`☰` 33×28、`📖` 32×26、主题 `🌓` btn-sm 32×26、用户名 `.who-box.wl-user-btn` 141×26、
     `切换身份` btn-sm 64×26。高度由既有 `button,.btn{min-height:40px !important}` 负责，
     **卡住的是宽度**：`button.btn.btn-sm`(0,2,1) 比 `.btn-sm`(0,1,0) 更特异，
     既有那条 `.btn-sm{min-width:36px}`（无 !important）压不过应用侧的 `.btn.btn-sm{padding:...}`。
     做法与基线既有 `.wl-ex/.wl-ver`、`#uidbg-btn` 一致：只在窄屏档给 36px 下限并加 !important。 */
  header button, header .btn, .topbar button, .topbar .btn,
  button.btn-sm, .btn.btn-sm, button.theme-btn, .theme-btn,
  .who-box, .wl-user-btn, .user-chip, .topbar .btn-icon, header .btn-icon {
    min-width: 36px !important; min-height: 36px;
  }
  /* 2026-10-02 补③：**顶栏容器内**再抬一档特异性。
     由来（EX-24 A/B 受控实验）：应用自己的 `.topbar` 修正块写了
     `#wlTop .btn, #wlTop .theme-btn, #wlTop #wlHelpBtn { min-width:30px !important; ... }`
     —— 同等 !important 下按特异性取胜，基线只写单类名压不过它 ⇒ `🌓`/`📖` 仍是 32×26。
     受控实验（真实页面临时注入后实测）：抬到 36×36 后 **small 6→3、顶栏高度 48px 不变、横向溢出仍 0**，
     即"不会把顶栏挤破"；故把这条按同样口径写进基线，用 `body #<容器>` + 后代选择器与之一致对等取胜。
     仍保留应用自己对**宽度**的最终话语权：只保证"不小于 36px"，不强制等宽。 */
  body header button, body header .btn, body .topbar button, body .topbar .btn,
  body .topbar .theme-btn, body header .theme-btn, body .topbar .btn-icon, body header .btn-icon,
  body .topbar .mini-btn, body header .mini-btn, body .topbar .icon-btn, body header .icon-btn,
  body .topbar .who-box, body .topbar .wl-user-btn, body .topbar .user-chip,
  /* ★ 关键：`.btn.btn-sm` / `.btn.mini-btn`（两个类）—— 实测应用侧常写
     `#wlTop .btn { min-width:30px !important }`（0,1,1）；同等 !important 下按特异性取胜，
     单类名压不过它。两个类 = (0,2,0) 与它打平 → 后写的基线胜出（EX-24 实测 32×26 → 36×36）。
     纪律：这里只做"不小于 36px"的点按下限，不锁尺寸，应用仍可用更特异的写法表达自己的视觉意图。 */
  body .btn.btn-sm, body .btn.mini-btn, body .btn.btn-mini, body .btn.icon-btn, body .btn.btn-icon {
    min-width: 36px !important; min-height: 36px !important;
    display: inline-flex !important; align-items: center; justify-content: center;
  }
  /* 分页数字链接：应用侧普遍写 min-width:26px，手机/折叠屏上宽度不足（EX-23 实测）。
     常见分页类名一并覆盖；.pager span.pd 是「当前页」禁用态，同样抬到可点口径。 */
  .pager a, .pagination a, .page-link, .page-btn,
  .pager span.pd, .pagination span.pd {
    min-width: 36px; min-height: 36px;
    display: inline-flex; align-items: center; justify-content: center;
  }
  /* 「退出/用户区」类文本链接：常常不在 <nav> 内（顶栏用户区、页脚），nav a 规则盖不到。
     各应用类名不一（.logout / .out / .user a / 甚至无类名），按 href 子串兜底最稳。
     由来：EX-23 补齐 nav 与分页后，五个移动档各剩 1 个不合格项，就是这条 24×36 的「退出」。 */
  /* 退出/用户区链接：**宽度与高度都要够** —— EX-21 实测 a.u-out「退出」37×19，
     原来这条只给了 min-width，高度没管上。 */
  a[href*="logout"], a[href*="signout"], a[href*="logoff"],
  .logout, .u-out, .user a, .topbar .user a, header .user a {
    min-width: 36px; min-height: 36px;
    display: inline-flex; align-items: center; justify-content: center;
  }
  .nav-links, .menu { overflow-x: auto; white-space: nowrap; }
  /* 菜单栏豁免钩子（v1.14 起）：
     `.wl-nav-nowrap`  = 应用明确要单行（原语义不变，同时关掉折行与横滑可见性）
     `.wl-nav-scroll`  = 应用明确要横向滚动条（菜单项多到折行会把顶栏吃光时用）
     两者都写在菜单**容器**上。注意：豁免只关容器折行，**不解除菜单项"不得窄于文字"**
     （那是防重叠的安全网，任何应用都不该关）。 */
  .wl-nav-nowrap { flex-wrap: nowrap !important; overflow-x: visible !important; }
  .wl-nav-scroll { flex-wrap: nowrap !important; overflow-x: auto !important;
    white-space: nowrap !important; -webkit-overflow-scrolling: touch; }
  /* 行内 style 写死 display:flex 的工具条：不动它就会把右侧按钮顶出屏幕，并被
     html,body{overflow-x:hidden} 直接裁掉（点不到）——故窄屏允许换行。 */
  [style*="display:flex"], [style*="display: flex"],
  [style*="display:inline-flex"], [style*="display: inline-flex"] { flex-wrap: wrap; }
  /* 行内写死 min-width 的输入/选择框：窄屏归零，避免撑破容器（EX-16/EX-23 实测） */
  input[style*="min-width"], select[style*="min-width"] { min-width: 0 !important; }
  /* 给宽表做横滚的配套容器类（与 wl-nowrap-table 配套：豁免 display:block 之后，
     表自己不滚动了，必须由外层容器横滚；应用自建同名类与基线一致，可直接收编） */
  .wl-tblwrap { overflow-x: auto; -webkit-overflow-scrolling: touch; max-width: 100%; }
  /* 表格内文本链接（单号/附件名等）是"链接点按区 <36px"的最大来源，统一兜底 */
  tbody td a, table a { min-height: 36px; display: inline-flex; align-items: center; }
  /* 各应用命名不一的小按钮：统一最小点按尺寸（高度 + 宽度）。
     含 .btn.sm / .btn-icon —— 图标类按钮常见 32px 宽，宽度不足同样会误触（EX-20 实测）。 */
  .btn-sm, .btn.sm, .mini-btn, .btn-mini, .icon-btn, .btn-icon, .row-btn,
  /* `.wl-btn` 是各应用自写的按钮类名（EX-25/EX-21 等），常是 <a class="wl-btn">：
     既不是 button 也不是 .btn，基线原来的兜底覆盖不到 —— EX-25 实测顶栏/工具条
     6 个点按目标只有 30~31px。 */
  /* 点按下限必须"赢"：应用侧常见更高特异性的 `.topbar button.wl-btn{min-height:30px}`，
     故按本文件既有做法（.wl-ex/.wl-ver、#uidbg-btn）用 !important。
     注意与 wl-compact.css 的区别：**密度基线不用 !important（要可覆盖），
     适配基线对点按下限用 !important（安全网必须生效）**。 */
  .wl-btn, .wl-button, a[class*="wl-btn"] { min-width: 36px; }
  body .wl-btn, body .wl-button, body a[class*="wl-btn"],
  body button.wl-btn, body .wl-btn.theme, body .wl-btn-primary {
    min-height: 36px !important;
    /* 文字居中（用户 2026-09-20）：`.wl-btn` 多为 <a>，既不是 button 也不是 .btn，
       密度基线管不到它；EX-25 实测 4 个顶栏按钮（盒高 36px）文字中心比盒中心高 5px。 */
    display: inline-flex !important;
    align-items: center !important;
    justify-content: center !important;
  }
  /* 通用可点按小链接工具类：应用给元素挂 .wl-tap 即达标（如附件名/单号链接原为 180×24） */
  .wl-tap { min-height: 36px; display: inline-flex; align-items: center; }
  /* 关闭类按钮：常见 16~20px 的「✕」，宽度不足同样误触（EX-20 实测） */
  .close-x, .btn-close, .modal-close, [data-close] {
    min-width: 36px;
    min-height: 36px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
  }

  /* 顶栏内层行：真正的最小内容宽度常来自"顶栏 > 内层行"这一层（EX-20 实测内层行 min-content
     约 500px，在 344px 折叠外屏顶出 110~156px 溢出）。基线只对 .topbar 本体设过 wrap，故补内层。
     注意：这是"允许换行"而非"强制单行"，与已移除的 nav{flex-wrap:wrap}（会破坏应用单行设计）不同；
     补后须用几何量复核顶栏高度/行数，防止行数异常膨胀。 */
  .topbar-inner, .navbar-inner, .header-inner, .app-header-inner {
    flex-wrap: wrap;
    height: auto !important;
    min-height: 54px;
  }
  /* KPI/统计行：.stats 是常见的 flex 行（grid-template-columns 对其无效，必须显式允许换行） */
  .stats, .kpi-row, .stats-row, .stat-row { flex-wrap: wrap; }
  .stats > *, .kpi-row > *, .stats-row > *, .stat-row > * { min-width: 0; }

  /* 网格/弹性子项最小尺寸归零：`grid-template-columns:1fr` 的轨道下限是子项 min-content
     （1fr 等价 minmax(auto,1fr)），宽表/长文本会因此把卡片撑破容器 —— EX-12 实测被撑到 632px，
     而容器只有 342px，页面级溢出 266/301px。故必须给子项 min-width:0。 */
  .cards > *, [class*="cards"] > *, [class*="grid"] > *, [class*="tiles"] > *,
  .kpi-row > *, .stat-grid > *, .stat-row > * { min-width: 0; }
  /* 承载宽表的卡片/容器自身必须可横向滚动：若父级 .card{overflow:hidden} 先把内容剪掉，
     表格自己 overflow-x:auto 也救不回来（EX-01 实测 4 张宽表在手机上不可达、无法滑动）。 */
  [class*="card-body"], [class*="table-wrap"], [class*="tbl-wrap"], [class*="table-scroll"] {
    overflow-x: auto;
  }

  /* 两列/三列表单栅格降级 */
  .form-grid, .grid-2, .grid-3, .two-col, .cols-2, .cols-3, .form-row {
    grid-template-columns: 1fr !important;
  }

  /* 主容器内边距收紧，避免可用宽度被吃掉。
     注意：`.wrap` 只加 max-width，不加 padding —— 部分应用把 .wrap 用作表格单元格内的
     长文本容器（如 EX-24 的 .wrap{max-width:320px}），加内边距会造成窄屏无端多出 12px。 */
  .container, .wrap, .main, .content, .page, .view { max-width: 100% !important; }
  .container, .view { padding-left: 12px !important; padding-right: 12px !important; }
}

/* ---------- 安卓手机竖屏 / 折叠外屏（≤600px）：单列 ---------- */
@media screen and (max-width: 600px) {
  .cards, .grid, .tiles, .kpi-row, .stats-row, .stat-row, .dashboard-grid {
    grid-template-columns: 1fr !important;
  }
  h1 { font-size: 19px; }
  h2 { font-size: 17px; }
  h3 { font-size: 15.5px; }
  .card-actions .btn, .card .btn, .actions .btn { display: block; width: 100%; text-align: center; }
  /* 豁免：字段行内/表格内的按钮（如「✕ 删除」）不该被撑成整行——否则把行挤破
     （EX-16 规格书编辑页实测 310+88px 溢出）。整行按钮只用于卡片操作区。
     ⚠ 只能用 inline-flex + 居中，**不能写 display:inline-block**：这条带 !important，
     会压过密度基线给 .btn 的 inline-flex/align-items:center，而 .btn 又被
     `min-height:40px !important` 撑到 40px —— 文字行盒就贴到盒子上沿，
     实测 EX-24 的 195 个 `a.btn.btn-sm`（「补录」）文字中心比盒中心高 9px（用户反馈"偏高"）。 */
  .fld > .btn, .field > .btn, td .btn, th .btn, .row > .btn, .inline-form .btn, .card-head .btn {
    display: inline-flex !important;
    align-items: center !important;
    justify-content: center !important;
    width: auto !important;
  }
  .container, .view { padding-left: 10px !important; padding-right: 10px !important; }
}

/* ---------- 折叠屏展开内屏 / 小平板（601–900px）：两列，用足宽度 ---------- */
@media screen and (min-width: 601px) and (max-width: 900px) {
  .cards, .grid, .tiles, .dashboard-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr)) !important;
  }
}

/* ---------- 半折（Flex 模式）/ 分屏 / 手机横屏：矮视口，压缩纵向留白 ---------- */
@media screen and (max-height: 520px) {
  .hero, .banner, .page-head, .jumbotron { padding-top: 6px !important; padding-bottom: 6px !important; }
  .topbar, .navbar { position: static !important; }
  .footer, .page-footer { display: none !important; }
  /* 矮视口弹窗：四周收边、内边距收紧，把高度还给内容与按钮条（配合上面的遮罩式弹窗规则） */
  .modal-mask { padding: 0 8px; }
  .modal-mask > .modal-card { margin: 6px auto !important; padding: 12px 14px; }
  .modal-card > .modal-actions { padding: 8px 0 2px; gap: 6px; }
}

/* ---------- 折叠屏展开内屏专项：视口偏方（宽高比 < 1.4），卡片类布局给 2~3 列 ---------- */
@media screen and (min-width: 700px) and (max-width: 900px) and (min-height: 620px) {
  .cards, .tiles { grid-template-columns: repeat(3, minmax(0, 1fr)) !important; }
}

/* ---------- 豁免与提示 ---------- */
@media screen and (max-width: 900px) {
  .wl-desktop-only { display: none !important; }
}
.wl-mobile-hint { display: none; }
@media screen and (max-width: 900px) {
  .wl-mobile-hint { display: block; }
}


/* ============================================================================
 * v1.15（2026-10-03）键盘可达：**可见焦点基线**（HOW21 §4.52/GF03 H2）
 *
 * 为什么加在共享基线：全舰队实测（audit_a11y_and_errors.py）里"没有焦点样式"的对象
 * 几乎全是共享注入件（A.wl-ver 版本徽标、BUTTON.theme-btn、A.wl-who-i、BUTTON.tab、
 * A.logout-btn、BUTTON.mini-btn），而本文件此前**一条 :focus 规则都没有**。
 *
 * 两条硬约束（业务方核心 UI 理念）：
 *   ① 只用 outline —— outline **不占布局、不触发重排**，因此不可能把「外壳三件套」
 *      顶折行 / 撑高（§4.39 状态栏只允许一行、固定高 46px）；不用 padding/border/min-height。
 *   ② 不写 :where()：`:where()` 特异性为 0，会被应用里常见的 `:focus{outline:none!important}`
 *      压过。这里用 `body :is(...)` 把特异性抬到 (0,1,2)，稳赢那些重置规则。
 * ========================================================================== */
body :is(a, button, input, select, textarea, summary, [tabindex], [role="button"], [role="tab"], [role="link"]):focus-visible {
  outline: 2px solid var(--acc, var(--accent, #2563eb)) !important;
  outline-offset: 2px !important;
}
/* 深色主题：焦点色要更亮，否则深底上看不见 */
[data-theme="dark"] body :is(a, button, input, select, textarea, summary, [tabindex], [role="button"], [role="tab"], [role="link"]):focus-visible,
body[data-theme="dark"] :is(a, button, input, select, textarea, summary, [tabindex], [role="button"], [role="tab"], [role="link"]):focus-visible,
body.dark :is(a, button, input, select, textarea, summary, [tabindex], [role="button"], [role="tab"], [role="link"]):focus-visible {
  outline-color: #7fb3ff !important;
}
/* 键盘用户在表格里换焦点时，别让焦点环被容器裁掉 */
.wl-tblwrap:focus-within, .tbl-wrap:focus-within { scroll-margin: 8px; }
