mirror of
https://github.com/Ed1s0nZ/CyberStrikeAI.git
synced 2026-10-18 05:31:19 +02:00
* feat: integrate the mobile UI runtime layer from the migration package 迁移包给出的移动端改造是「运行时注入」架构:mobile.css 只写 767.98px 以下的 规则,mobile-ui.js 在末位加载并包装 switchPage、注入抽屉/底部标签栏/更多面板。 模板侧只有 4 处接线(viewport-fit + interactive-widget、样式层链接、ELK/SheetJS 移动端延迟加载、交互层末位脚本),其余保持上游原样,桌面端零影响。 * feat: 移动端注入层接入 i18n,并把触控下限统一到 44px 迁移包的交互层把标签栏、抽屉、更多面板的文案全写死成中文,en-US/ru-RU 下会中英 混杂;现在所有注入节点统一挂 data-i18n,交给 i18n.js 的 applyTranslations 在语言 切换时自动重译,本层只保留中文兜底。语言项改为按桌面端下拉里真实存在的语言循环 (原来只在 zh/en 之间来回,俄语用户点不到),面板里的 API 文档/GitHub 不再抄一份 URL,改为触发桌面端既有控件;iOS 上没有全屏 API 时给出提示而不是静默无反应; 不在四个标签里的页面点亮"更多",否则三分之一的页面底部栏无任何高亮。 同时补齐 PWA manifest、api-docs 页移动端样式层,并把通知铃铛与头像按钮从 38px 提到本层自己的 --m-touch(44px) 口径。配 web/static/js/mobile-ui-i18n.test.cjs: 键集三方一致、引用键必须三语都有译文、helper 区之外不许出现裸写文案的 API。 * style: 移动端外壳改 iOS 观感,并修掉抽屉页脚错位 观感:顶栏/底栏改透出材质+发丝分隔线,图标按钮一律正圆去底框,文字按钮一律胶囊, 卡片 18、面板顶角 22,按压给 scale 反馈并在 prefers-reduced-motion 下关掉;焦点环 从 2px 硬描边换成 3px 柔光环(forced-colors 下把硬描边还回去)。材质一律用 color-mix 从主题自己的 --bg-primary/--border-color 派生,浅色暗色都跟随。 两处不是"不好看"而是真错: - 抽屉页脚被 insertBefore 插到菜单上面,"返回顶部"出现在列表上方; - 顶栏材质在暗色下被 style.css 的 html[data-theme="dark"] header 不透明渐变压住, 只写 header 选择器不生效,改成同特异性后暗色才真正透出。 圆角与胶囊走 --m-r-icon/--m-r-btn 令牌(24 节那批 !important 规则读的就是它们), 不再往下补选择器与 !important 对轰。 配 scripts/mobile-shot.mjs:手机视口下抓外壳图,--why 用 CDP 匹配样式表回答 "规则写了没生效是没命中还是被谁压住",--eval 量真实计算值。 * fix: 抽屉页脚与底部固定件被 Safari 工具栏压在后面 iOS 的 100dvh 是「工具栏收起时」的最大视口高度,工具栏展开时可见高度只有 innerHeight。两个全屏抽屉写死 height:100dvh,于是页脚那一截正好落在 Safari 底栏后面;bottom:0 的底栏与贴底面板同理。现在抽屉改用 mobile-ui.js 每次 resize 重写的 --m-app-height,贴底固定件按 max(0px, 100dvh - 可见高度) 抬升;不支持 dvh 或桌面端抬升量恒为 0,实测默认态底栏/抽屉位置零位移。 * fix: 去掉底部标签栏里重复的「更多」入口 顶栏的 ··· 与标签栏的「更多」打开的是同一个面板。按一个入口一份实现收掉底部那枚, 标签栏只留四个页面跳转;随之清掉 more2 图标、mobile.tabMore 键与门禁里的点击断言。 落点在四个标签之外的页面不再高亮任何标签——没有「更多」可点了。 * fix: 清掉另外两处重复入口,并把同类视口缺陷扫干净 顺着「底部更多与顶栏 ··· 重复」这条线扫了一遍,还有两处同类: - 面板里的「退出登录」与头像菜单里的退出是同一个动作两个入口,头像菜单是桌面端 一贯的位置,去掉面板那枚;连带删掉只有它能触发的 m-danger 样式与 logout 图标。 - 抽屉页脚的「返回顶部」与面板里的返回顶部是同一个动作两个入口,且抽屉是导航容器, 动作按钮不该住在里面;去掉整个页脚(那句"移动端导航"文案也没有信息量)。 同类视口缺陷两处: - #m-toast 的 bottom 只算到 tabbar-h + safe,底栏按 --m-bar-bottom 抬升时提示条不抬, 工具栏展开时会压在底栏上;实测补前后间距 16px -> 16px。 - api-docs 页容器写 min-height:100dvh,恒定比可见区高出一截,最后一行落在 Safari 底栏后面;改成 100svh(最小视口)。 i18n 契约测试同步:header.logout / mobile.navFooter 不再被引用,mobile 命名空间 18 键。 * style: 手机端对齐 new-api 的卡片密度与 iOS 的填充式表单 仪表盘那排 KPI 在 ≤480px 被桌面样式拍成一列 116px 高的长条,手机上要滚两屏才看完 四个数字。收成两列紧凑网格(奇数张末卡通栏不留空洞),数字 26px/600 + tabular-nums 做主角,标签 12px 弱化,图标块 28px。卡片表面统一成发丝边 + 16 圆角 + 几乎看不见的 投影——桌面的双层阴影在小屏上一屏四张会散。表单改 iOS 填充式(靠底色区分字段), 聚焦只留一圈柔光环(登录框实测叠过两圈),登录卡 20 圆角 + 满宽胶囊主按钮。 KPI 按 nth-child 分的淡彩渐变是产品自己的身份,这一节不跟它抢。 * fix: 补生产侧俄语、修掉白底白字的提示条,并把逐按钮门禁跑到 PASS 用户报的两件事: - 面板里「切换语言」只在中英之间跳 —— 不是逻辑问题,是 ~/csai-生产版 缺俄语资产 (模板没有 ru-RU 选项、i18n/ 只有两个 json、i18n.js 是不认 ru 的旧版)。补齐后 真手指连点验通 中→英→俄→中,且该行文字自身跟着换。 - 点面板按钮时屏幕中间冒出一块白的 —— 是我自己造成的:25.6 把提示条改成浅色材质, 字色还是基底的 #fff,等于白底白字。回到深色 HUD 胶囊,只留一层投影。 逐按钮门禁(需要登录态,本轮首次跑通全量 34 个界面 = 31 页 + 抽屉/面板/会话抽屉展开态): - 硬缺陷 covered/offscreen/zero/pointer-events 全 0;11 条外壳真手指点击全过; - 小于 44px 从 79 降到 3,残留是桌面密集表格里的控件,钉进基线只降不升; - 修掉的真缺陷:子菜单项 42px(本层自己漏的下限)、.ai-channel-manager 的 overflow:hidden 把 4 个通道选择按钮裁到滚不进来、会话抽屉里搜索框 42/分组按钮 24 宽/ 项目行 38/折叠头 30、工具条里 <a onclick> 只有 21px 高(这些链接既没 href 也没 onclick 属性可依赖,判据要放宽到 <a>);复选框口径统一到 24.11 一处并放大到 30px。 - 门禁自己的两个错也修了:scrollIntoView 在「外层 hidden + 内层 auto」的嵌套里根本不滚, 造成 59 个 offscreen 假红,改成逐层滚可滚祖先模拟手指;touch+mouse 双发会让一次点击 变成两次(抽屉开了又关),只发 touch。 - 退出码口径写死:够不到/遮挡/零尺寸/pointer-events 与自家外壳必须 0,桌面遗留小命中区 走基线;基线被压低时注入探针验红(RATCHET FAIL ×2)后撤销复验绿。 * style: 手机端玻璃质感升级,并补上对话上传的安卓适配 观感目标从"iOS 化的平面灰底"升到玻璃质感。平底上做半透明无物可透,玻璃读不出来, 所以先造画布再上材质(mobile.css 第 28 节): - .container 铺环境光(浅色=近白底+右上 accent/左下紫柔光,暗色=深底+更亮柔光), .content-area / .chat-messages 交出实心底色,半透明表面从此有色可透; - 模糊只给小面积/瞬时件:顶栏、底栏、底部面板、抽屉、登录卡、弹窗;常驻卡片 只做半透明+发丝边+顶缘高光,不挂模糊——固定在滚动内容上的大面积模糊是掉帧主因 (25 节实测口径不变);浅深色全用 color-mix 从主题令牌派生,只有顶缘高光按主题 换向;prefers-reduced-transparency 与不支持模糊的环境退回实心。 - index.html 的 mobile.css 版本号递增,防 iPhone Safari 吃旧缓存。 安卓适配:对话上传的 accept="*" 不是合法 MIME 通配(各浏览器/WebView 解析不一致), 改为 "*/*";mobile-tap-audit.mjs 新增 --ua=iphone|android,同一套门禁可换安卓 UA 复跑 (壳层按视口宽度判定、与 UA 无关,换 UA 是给"安卓浏览器下同样合格"留可复现证据)。 验证(都在生产版文件夹跑):iPhone/Android 双 UA 端到端上传(按钮 44px → 触达 选择器 → POST /api/chat-uploads 200 落盘 → 附件条渲染)PASS;双 UA 全量门禁各 34 页 PASS(硬缺陷 0、点击失败 0、44px 基线无回潮)。
3629 lines
128 KiB
CSS
3629 lines
128 KiB
CSS
/* ==========================================================================
|
||
CyberStrikeAI — Mobile UI Layer
|
||
--------------------------------------------------------------------------
|
||
目标:在不改动 style.css(1.1MB)与既有桌面布局的前提下,用一层独立的
|
||
响应式样式把平台改造成"手机优先可用"的形态。
|
||
|
||
设计语言参考 QuantumNous/new-api 的移动端实现:
|
||
- 断点 768px(useIsMobile: innerWidth < 768)
|
||
- 底部滑出式面板(rounded sheet + backdrop-blur 遮罩 + spring 动画)
|
||
- 100svh/dvh 视口单位、--app-header-height 变量驱动的布局高度
|
||
- 抽屉式导航 + 卡片化列表
|
||
|
||
本文件只在 max-width: 767.98px(以及平板/横屏区间)生效,
|
||
桌面端与 ≥768px 的既有表现完全不受影响。
|
||
========================================================================== */
|
||
|
||
/* --------------------------------------------------------------------------
|
||
1. 设计令牌
|
||
-------------------------------------------------------------------------- */
|
||
:root {
|
||
--m-appbar-h: 52px;
|
||
--m-tabbar-h: 58px;
|
||
--m-safe-top: env(safe-area-inset-top, 0px);
|
||
--m-safe-bottom: env(safe-area-inset-bottom, 0px);
|
||
--m-safe-left: env(safe-area-inset-left, 0px);
|
||
--m-safe-right: env(safe-area-inset-right, 0px);
|
||
--m-drawer-w: min(84vw, 320px);
|
||
--m-touch: 44px;
|
||
--m-radius-sheet: 18px;
|
||
--m-radius-card: 14px;
|
||
--m-gutter: 14px;
|
||
/* 24 节「按钮 / 控件视觉体系」的度量:全站按钮只有这一组尺寸口径。
|
||
改造前 style.css 里没有 .btn 基类,圆角 11 种、字号 9 种、字重 7 档、
|
||
同一个 .btn-secondary 出现 12 种签名(_mbtn.mjs 实测 645 个控件)。 */
|
||
--m-r-ctl: 12px;
|
||
/* 图标按钮一律正圆、文字按钮一律胶囊:24 节那批 !important 规则读的就是这两个
|
||
令牌,改令牌一处生效全站,不要再往下补选择器或跟 !important 对轰 */
|
||
--m-r-icon: 50%;
|
||
--m-r-btn: 999px;
|
||
--m-r-pill: 999px;
|
||
--m-ctl-h: var(--m-touch);
|
||
--m-ctl-pad-x: 16px;
|
||
--m-ctl-pad-x-sm: 12px;
|
||
--m-ctl-fs: 14px;
|
||
--m-ctl-fs-sm: 13px;
|
||
--m-ctl-fw: 500;
|
||
--m-ctl-fw-strong: 600;
|
||
--m-ctl-gap: 8px;
|
||
--m-ease: cubic-bezier(0.32, 0.72, 0, 1);
|
||
--m-scrim: rgba(15, 23, 42, 0.5);
|
||
--m-z-tabbar: 800;
|
||
--m-z-scrim: 1200;
|
||
--m-z-drawer: 1201;
|
||
--m-z-sheet: 1202;
|
||
--m-z-toast: 1300;
|
||
/* 运行时由 mobile-ui.js 写入,作为 100dvh 不可用时的兜底 */
|
||
--m-app-height: 100vh;
|
||
/* 贴底固定件(底栏 / 面板)的抬升量:iOS Safari 工具栏展开时,可见视口比
|
||
100dvh 矮一截,bottom:0 的固定件会被 Safari 底栏压住。JS 每次 resize 都会
|
||
重写 --m-app-height,所以这里能实时算出那一截是多少。默认 0,桌面与
|
||
不支持 dvh 的环境都不动。 */
|
||
--m-bar-bottom: 0px;
|
||
}
|
||
|
||
/* --------------------------------------------------------------------------
|
||
2. 视口与滚动基础
|
||
-------------------------------------------------------------------------- */
|
||
@media (max-width: 767.98px) {
|
||
html {
|
||
height: 100%;
|
||
overflow: hidden;
|
||
}
|
||
|
||
body {
|
||
height: 100vh;
|
||
height: 100dvh;
|
||
height: var(--m-app-height, 100dvh);
|
||
overflow: hidden;
|
||
overscroll-behavior: none;
|
||
-webkit-text-size-adjust: 100%;
|
||
text-size-adjust: 100%;
|
||
}
|
||
|
||
.container {
|
||
height: 100%;
|
||
max-height: 100%;
|
||
border-radius: 0;
|
||
box-shadow: none;
|
||
overflow: hidden;
|
||
}
|
||
|
||
/* 触摸设备:去掉 300ms 点击延迟与高亮块 */
|
||
a,
|
||
button,
|
||
.nav-item-content,
|
||
.nav-submenu-item,
|
||
[onclick],
|
||
[role="button"] {
|
||
-webkit-tap-highlight-color: transparent;
|
||
touch-action: manipulation;
|
||
}
|
||
|
||
/* 双击缩放整体抑制(仍保留双指缩放),替代原先的全局 JS touchend 拦截 */
|
||
body {
|
||
touch-action: manipulation;
|
||
}
|
||
|
||
/* iOS 输入聚焦自动放大:所有表单控件至少 16px */
|
||
input,
|
||
select,
|
||
textarea {
|
||
font-size: 16px;
|
||
}
|
||
|
||
/* 滚动容器统一惯性滚动与边界收敛 */
|
||
.page-content,
|
||
.main-sidebar-nav,
|
||
.chat-messages,
|
||
.conversation-list,
|
||
.notification-list,
|
||
.m-sheet-body {
|
||
-webkit-overflow-scrolling: touch;
|
||
overscroll-behavior: contain;
|
||
}
|
||
|
||
/* 触控目标下限 */
|
||
button,
|
||
.btn-primary,
|
||
.btn-secondary,
|
||
.btn-danger,
|
||
.btn-small,
|
||
.nav-item-content,
|
||
.nav-submenu-item,
|
||
.user-menu-item {
|
||
min-height: var(--m-touch);
|
||
}
|
||
|
||
button,
|
||
.btn-primary,
|
||
.btn-secondary,
|
||
.btn-danger {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
gap: 6px;
|
||
}
|
||
|
||
/* 桌面专属元素在手机上隐藏 */
|
||
.m-desktop-only {
|
||
display: none !important;
|
||
}
|
||
}
|
||
|
||
/* 手机专属元素默认隐藏,避免桌面端闪现 */
|
||
.m-mobile-only {
|
||
display: none;
|
||
}
|
||
|
||
@media (max-width: 767.98px) {
|
||
.m-mobile-only {
|
||
display: block;
|
||
}
|
||
|
||
.m-mobile-only.m-flex {
|
||
display: flex;
|
||
}
|
||
|
||
.m-mobile-only.m-inline-flex {
|
||
display: inline-flex;
|
||
}
|
||
}
|
||
|
||
/* --------------------------------------------------------------------------
|
||
3. 顶部应用栏
|
||
-------------------------------------------------------------------------- */
|
||
@media (max-width: 767.98px) {
|
||
header {
|
||
height: var(--m-appbar-h);
|
||
min-height: var(--m-appbar-h);
|
||
padding: 0 var(--m-gutter);
|
||
padding-top: var(--m-safe-top);
|
||
height: calc(var(--m-appbar-h) + var(--m-safe-top));
|
||
min-height: calc(var(--m-appbar-h) + var(--m-safe-top));
|
||
display: flex;
|
||
align-items: center;
|
||
flex-shrink: 0;
|
||
position: relative;
|
||
z-index: 20;
|
||
background: var(--bg-primary);
|
||
border-bottom: 1px solid var(--border-color);
|
||
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.06);
|
||
}
|
||
|
||
.header-content {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 8px;
|
||
width: 100%;
|
||
height: 100%;
|
||
}
|
||
|
||
.header-logo-link {
|
||
flex: 1;
|
||
min-width: 0;
|
||
gap: 8px;
|
||
display: flex;
|
||
align-items: center;
|
||
}
|
||
|
||
.header-logo-link .brand-logo {
|
||
width: 28px;
|
||
height: 28px;
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
.header-logo-link .brand-wordmark--lg {
|
||
font-size: 1.05rem;
|
||
white-space: nowrap;
|
||
overflow: hidden;
|
||
text-overflow: ellipsis;
|
||
}
|
||
|
||
.version-badge {
|
||
display: none;
|
||
}
|
||
|
||
.header-right {
|
||
gap: 4px;
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
.header-actions {
|
||
gap: 4px;
|
||
align-items: center;
|
||
}
|
||
|
||
/* 桌面端的次要操作(API 文档 / GitHub / 主题 / 语言)收进"更多"面板 */
|
||
.header-actions > .openapi-doc-btn,
|
||
.header-actions > .lang-switcher,
|
||
.header-actions > .theme-toggle,
|
||
.header-actions > #theme-toggle-btn,
|
||
.header-actions > .theme-toggle-btn {
|
||
display: none !important;
|
||
}
|
||
|
||
.header-actions > .notification-menu-container,
|
||
.header-actions > .user-menu-container {
|
||
display: flex;
|
||
}
|
||
|
||
/* 汉堡按钮 / 关闭按钮 */
|
||
.m-menu-btn,
|
||
.m-more-btn,
|
||
.m-close-btn {
|
||
width: var(--m-touch);
|
||
height: var(--m-touch);
|
||
min-height: var(--m-touch);
|
||
padding: 0;
|
||
border: none;
|
||
border-radius: 10px;
|
||
background: transparent;
|
||
color: var(--text-primary);
|
||
flex-shrink: 0;
|
||
display: inline-flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
cursor: pointer;
|
||
-webkit-tap-highlight-color: transparent;
|
||
}
|
||
|
||
.m-menu-btn:active,
|
||
.m-more-btn:active,
|
||
.m-close-btn:active {
|
||
background: var(--bg-tertiary);
|
||
}
|
||
|
||
.m-menu-btn svg,
|
||
.m-more-btn svg,
|
||
.m-close-btn svg {
|
||
width: 22px;
|
||
height: 22px;
|
||
}
|
||
|
||
/* 通知与用户菜单是本层唯一漏掉 44px 下限的常驻控件:38px 在手指下是
|
||
「看得见但点不准」,与上面 --m-touch 的口径必须一致 */
|
||
.notification-btn,
|
||
.user-avatar-btn {
|
||
width: var(--m-touch);
|
||
height: var(--m-touch);
|
||
min-height: var(--m-touch);
|
||
padding: 0;
|
||
display: inline-flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
}
|
||
}
|
||
|
||
/* --------------------------------------------------------------------------
|
||
4. 侧边栏 → 抽屉导航
|
||
-------------------------------------------------------------------------- */
|
||
@media (max-width: 767.98px) {
|
||
.main-layout {
|
||
position: relative;
|
||
overflow: hidden;
|
||
min-height: 0;
|
||
flex: 1;
|
||
}
|
||
|
||
.main-sidebar {
|
||
position: fixed;
|
||
top: 0;
|
||
bottom: 0;
|
||
left: 0;
|
||
width: var(--m-drawer-w) !important;
|
||
max-width: 86vw;
|
||
height: 100%;
|
||
height: 100dvh;
|
||
height: var(--m-app-height, 100dvh);
|
||
z-index: var(--m-z-drawer);
|
||
transform: translateX(-102%);
|
||
visibility: hidden;
|
||
transition: transform 0.3s var(--m-ease), visibility 0.3s linear;
|
||
box-shadow: none;
|
||
border-right: 1px solid var(--border-color);
|
||
border-radius: 0 var(--m-radius-sheet) var(--m-radius-sheet) 0;
|
||
display: flex;
|
||
flex-direction: column;
|
||
overflow: hidden;
|
||
}
|
||
|
||
.main-sidebar.m-open {
|
||
transform: translateX(0);
|
||
visibility: visible;
|
||
box-shadow: 0 18px 48px rgba(0, 0, 0, 0.45);
|
||
}
|
||
|
||
/* 折叠态在手机上无意义,强制展开 */
|
||
.main-sidebar.collapsed {
|
||
width: var(--m-drawer-w) !important;
|
||
}
|
||
|
||
.main-sidebar.collapsed .nav-item-content span,
|
||
.main-sidebar.collapsed .nav-submenu-item {
|
||
display: revert;
|
||
}
|
||
|
||
/* 桌面折叠按钮由抽屉头部关闭按钮取代 */
|
||
.sidebar-collapse-btn {
|
||
display: none !important;
|
||
}
|
||
|
||
/* 抽屉头部(由 mobile-ui.js 注入) */
|
||
.m-drawer-head {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
gap: 8px;
|
||
padding: 10px 10px 10px 14px;
|
||
padding-top: calc(10px + var(--m-safe-top));
|
||
border-bottom: 1px solid var(--border-color);
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
.m-drawer-brand {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 8px;
|
||
min-width: 0;
|
||
}
|
||
|
||
.m-drawer-brand img {
|
||
width: 26px;
|
||
height: 26px;
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
.m-drawer-brand .brand-wordmark {
|
||
font-size: 1.02rem;
|
||
white-space: nowrap;
|
||
}
|
||
|
||
.m-drawer-search {
|
||
padding: 8px 12px;
|
||
border-bottom: 1px solid var(--border-color);
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
.m-drawer-search input {
|
||
width: 100%;
|
||
box-sizing: border-box;
|
||
height: 38px;
|
||
padding: 0 12px;
|
||
border-radius: 10px;
|
||
border: 1px solid var(--border-color);
|
||
background: var(--input-bg);
|
||
color: var(--text-primary);
|
||
font-size: 15px;
|
||
outline: none;
|
||
}
|
||
|
||
.m-drawer-search input:focus {
|
||
border-color: var(--accent-color);
|
||
}
|
||
|
||
.m-nav-empty {
|
||
padding: 10px 4px 2px;
|
||
font-size: 13px;
|
||
color: var(--text-muted);
|
||
text-align: center;
|
||
}
|
||
|
||
.m-nav-empty[hidden] {
|
||
display: none;
|
||
}
|
||
|
||
|
||
/* 抽屉内的导航项:更大、更好点 */
|
||
.main-sidebar-nav {
|
||
flex: 1;
|
||
overflow-y: auto;
|
||
padding: 6px 8px calc(12px + var(--m-safe-bottom));
|
||
}
|
||
|
||
.nav-section-label {
|
||
padding: 12px 10px 6px;
|
||
font-size: 0.7rem;
|
||
letter-spacing: 0.06em;
|
||
text-transform: uppercase;
|
||
color: var(--text-muted);
|
||
}
|
||
|
||
.nav-item-content {
|
||
padding: 11px 12px;
|
||
min-height: 46px;
|
||
font-size: 0.95rem;
|
||
border-radius: 10px;
|
||
gap: 12px;
|
||
}
|
||
|
||
.nav-item-content svg {
|
||
width: 20px;
|
||
height: 20px;
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
.nav-submenu-item {
|
||
padding: 10px 12px 10px 44px;
|
||
/* 原来是 42px——本层自己定的 --m-touch(44px) 下限被自己漏掉了一处 */
|
||
min-height: var(--m-touch);
|
||
font-size: 0.9rem;
|
||
border-radius: 8px;
|
||
}
|
||
|
||
.nav-item.active > .nav-item-content,
|
||
.nav-item-content.active {
|
||
background: color-mix(in srgb, var(--accent-color) 14%, transparent);
|
||
color: var(--accent-color);
|
||
}
|
||
|
||
.nav-submenu-item.active {
|
||
background: color-mix(in srgb, var(--accent-color) 12%, transparent);
|
||
color: var(--accent-color);
|
||
}
|
||
|
||
/* 菜单搜索命中的项 */
|
||
.m-nav-hit > .nav-item-content,
|
||
.nav-submenu-item.m-nav-hit {
|
||
outline: 1px solid color-mix(in srgb, var(--accent-color) 45%, transparent);
|
||
}
|
||
|
||
.m-nav-hidden {
|
||
display: none !important;
|
||
}
|
||
|
||
/* 遮罩 */
|
||
.m-scrim {
|
||
position: fixed;
|
||
inset: 0;
|
||
z-index: var(--m-z-scrim);
|
||
/* 全屏 backdrop-filter 在无 GPU 加速环境代价极高,用不透明度替代 */
|
||
background: var(--m-scrim);
|
||
opacity: 0;
|
||
visibility: hidden;
|
||
transition: opacity 0.24s ease, visibility 0.24s linear;
|
||
}
|
||
|
||
.m-scrim.m-show {
|
||
opacity: 1;
|
||
visibility: visible;
|
||
}
|
||
}
|
||
|
||
/* --------------------------------------------------------------------------
|
||
5. 底部标签栏
|
||
-------------------------------------------------------------------------- */
|
||
@media (max-width: 767.98px) {
|
||
.content-area {
|
||
padding-bottom: calc(var(--m-tabbar-h) + var(--m-safe-bottom));
|
||
background: var(--bg-secondary);
|
||
}
|
||
|
||
#m-tabbar {
|
||
position: fixed;
|
||
left: 0;
|
||
right: 0;
|
||
bottom: var(--m-bar-bottom);
|
||
z-index: var(--m-z-tabbar);
|
||
display: flex;
|
||
align-items: stretch;
|
||
height: calc(var(--m-tabbar-h) + var(--m-safe-bottom));
|
||
padding-bottom: var(--m-safe-bottom);
|
||
padding-left: var(--m-safe-left);
|
||
padding-right: var(--m-safe-right);
|
||
/* 固定底栏带 backdrop-filter 时,软件渲染每帧都要重算模糊,是移动端掉帧主因 */
|
||
background: var(--bg-primary);
|
||
border-top: 1px solid var(--border-color);
|
||
box-shadow: 0 -2px 14px rgba(0, 0, 0, 0.06);
|
||
transition: transform 0.24s var(--m-ease);
|
||
}
|
||
|
||
#m-tabbar.m-hidden {
|
||
transform: translateY(110%);
|
||
}
|
||
|
||
.m-tab {
|
||
flex: 1 1 0;
|
||
min-width: 0;
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
justify-content: center;
|
||
gap: 2px;
|
||
padding: 6px 2px 4px;
|
||
border: none;
|
||
background: transparent;
|
||
color: var(--text-muted);
|
||
/* 原 0.66rem = 10.56px,是本层自己漏掉的"小字号下限 12px"(见 18.2),
|
||
底部标签栏是主导航,字号必须达标 */
|
||
font-size: 12px;
|
||
line-height: 1.15;
|
||
position: relative;
|
||
border-radius: var(--m-r-ctl);
|
||
transition: color 0.16s ease, transform 0.16s ease;
|
||
-webkit-tap-highlight-color: transparent;
|
||
touch-action: manipulation;
|
||
}
|
||
|
||
.m-tab svg {
|
||
width: 23px;
|
||
height: 23px;
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
.m-tab span {
|
||
max-width: 100%;
|
||
overflow: hidden;
|
||
text-overflow: ellipsis;
|
||
white-space: nowrap;
|
||
}
|
||
|
||
.m-tab.m-active {
|
||
color: var(--accent-color);
|
||
}
|
||
|
||
.m-tab.m-active svg {
|
||
transform: translateY(-1px) scale(1.06);
|
||
}
|
||
|
||
.m-tab:active {
|
||
transform: scale(0.94);
|
||
}
|
||
|
||
.m-tab-badge {
|
||
position: absolute;
|
||
top: 3px;
|
||
left: 50%;
|
||
margin-left: 6px;
|
||
min-width: 18px;
|
||
height: 18px;
|
||
padding: 0 5px;
|
||
border-radius: 9px;
|
||
background: var(--error-color, #ef4444);
|
||
color: #fff;
|
||
font-size: 11px;
|
||
line-height: 18px;
|
||
text-align: center;
|
||
font-weight: 600;
|
||
box-sizing: border-box;
|
||
}
|
||
|
||
.m-tab-dot {
|
||
position: absolute;
|
||
top: 6px;
|
||
left: 50%;
|
||
margin-left: 8px;
|
||
width: 8px;
|
||
height: 8px;
|
||
border-radius: 50%;
|
||
background: var(--error-color, #ef4444);
|
||
}
|
||
|
||
/* 键盘弹出时让出空间 */
|
||
body.m-keyboard #m-tabbar {
|
||
transform: translateY(110%);
|
||
}
|
||
|
||
body.m-keyboard .content-area {
|
||
padding-bottom: 0;
|
||
}
|
||
}
|
||
|
||
/* --------------------------------------------------------------------------
|
||
6. 底部滑出面板(更多 / 快捷操作)
|
||
-------------------------------------------------------------------------- */
|
||
@media (max-width: 767.98px) {
|
||
#m-sheet {
|
||
position: fixed;
|
||
left: 0;
|
||
right: 0;
|
||
bottom: 0;
|
||
z-index: var(--m-z-sheet);
|
||
width: 95%;
|
||
margin: 0 auto;
|
||
bottom: calc(8px + var(--m-safe-bottom) + var(--m-bar-bottom));
|
||
background: var(--bg-primary);
|
||
border: 1px solid var(--border-color);
|
||
border-radius: var(--m-radius-sheet);
|
||
box-shadow: 0 -8px 40px rgba(0, 0, 0, 0.32);
|
||
transform: translateY(calc(100% + 24px));
|
||
opacity: 0;
|
||
visibility: hidden;
|
||
transition: transform 0.32s var(--m-ease), opacity 0.2s ease, visibility 0.32s linear;
|
||
max-height: 78vh;
|
||
max-height: 78dvh;
|
||
display: flex;
|
||
flex-direction: column;
|
||
overflow: hidden;
|
||
}
|
||
|
||
#m-sheet.m-show {
|
||
transform: translateY(0);
|
||
opacity: 1;
|
||
visibility: visible;
|
||
}
|
||
|
||
.m-sheet-grip {
|
||
width: 38px;
|
||
height: 4px;
|
||
border-radius: 2px;
|
||
background: var(--border-color);
|
||
margin: 8px auto 2px;
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
.m-sheet-head {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
padding: 6px 16px 10px;
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
.m-sheet-title {
|
||
font-size: 0.95rem;
|
||
font-weight: 600;
|
||
color: var(--text-primary);
|
||
}
|
||
|
||
.m-sheet-body {
|
||
overflow-y: auto;
|
||
padding: 0 10px 12px;
|
||
display: grid;
|
||
grid-template-columns: repeat(4, 1fr);
|
||
gap: 4px;
|
||
}
|
||
|
||
.m-sheet-item {
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
justify-content: center;
|
||
gap: 6px;
|
||
padding: 12px 4px;
|
||
border: none;
|
||
background: transparent;
|
||
border-radius: 12px;
|
||
color: var(--text-secondary);
|
||
font-size: 0.72rem;
|
||
text-align: center;
|
||
line-height: 1.2;
|
||
min-height: 74px;
|
||
}
|
||
|
||
.m-sheet-item:active {
|
||
background: var(--bg-tertiary);
|
||
}
|
||
|
||
.m-sheet-item svg {
|
||
width: 22px;
|
||
height: 22px;
|
||
}
|
||
|
||
.m-sheet-item.m-on {
|
||
color: var(--accent-color);
|
||
background: color-mix(in srgb, var(--accent-color) 10%, transparent);
|
||
}
|
||
|
||
.m-sheet-sep {
|
||
grid-column: 1 / -1;
|
||
height: 1px;
|
||
background: var(--border-color);
|
||
margin: 8px 6px;
|
||
}
|
||
}
|
||
|
||
/* --------------------------------------------------------------------------
|
||
7. 页面头 / 内容区
|
||
-------------------------------------------------------------------------- */
|
||
@media (max-width: 767.98px) {
|
||
.page-header {
|
||
padding: 10px var(--m-gutter);
|
||
flex-direction: column;
|
||
flex-wrap: nowrap;
|
||
gap: 8px;
|
||
align-items: stretch;
|
||
border-radius: 0;
|
||
}
|
||
|
||
/* 标题独占一行,操作按钮区满宽换到下一行(避免 space-between 把按钮挤窄、
|
||
主按钮右端出屏被截)。按钮区内部仍可横向滚动,但占满整行、左对齐平齐。 */
|
||
.page-header h1,
|
||
.page-header h2,
|
||
.page-header h3 {
|
||
font-size: 1.05rem;
|
||
line-height: 1.3;
|
||
width: 100%;
|
||
}
|
||
|
||
.page-header-actions {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 6px;
|
||
width: 100%;
|
||
padding-bottom: 2px;
|
||
flex-wrap: wrap;
|
||
}
|
||
|
||
.page-header-actions > * {
|
||
flex: 0 0 auto;
|
||
white-space: nowrap;
|
||
}
|
||
|
||
.page-content {
|
||
padding: var(--m-gutter) var(--m-gutter) calc(var(--m-gutter) + 8px);
|
||
overflow-x: hidden;
|
||
}
|
||
|
||
/* 页面切换的轻量过渡 */
|
||
.page.active {
|
||
animation: m-page-in 0.22s var(--m-ease);
|
||
}
|
||
|
||
@keyframes m-page-in {
|
||
from {
|
||
opacity: 0;
|
||
transform: translateY(6px);
|
||
}
|
||
|
||
to {
|
||
opacity: 1;
|
||
transform: none;
|
||
}
|
||
}
|
||
|
||
/* 卡片化:常见容器统一圆角与内边距 */
|
||
.card,
|
||
.stat-card,
|
||
.metric-card,
|
||
.dashboard-card,
|
||
.panel,
|
||
.settings-section,
|
||
.info-card {
|
||
border-radius: var(--m-radius-card);
|
||
}
|
||
}
|
||
|
||
/* --------------------------------------------------------------------------
|
||
8. 表格 → 横向滚动 + 边缘渐隐
|
||
-------------------------------------------------------------------------- */
|
||
@media (max-width: 767.98px) {
|
||
.m-table-scroll {
|
||
overflow-x: auto;
|
||
overflow-y: hidden;
|
||
-webkit-overflow-scrolling: touch;
|
||
overscroll-behavior-x: contain;
|
||
margin-left: calc(-1 * var(--m-gutter));
|
||
margin-right: calc(-1 * var(--m-gutter));
|
||
padding: 0 var(--m-gutter);
|
||
/* 左右渐隐阴影(Lea Verou 滚动阴影) */
|
||
background:
|
||
linear-gradient(to right, var(--bg-primary) 30%, rgba(255, 255, 255, 0)) left / 32px 100% no-repeat local,
|
||
linear-gradient(to left, var(--bg-primary) 30%, rgba(255, 255, 255, 0)) right / 32px 100% no-repeat local,
|
||
radial-gradient(farthest-side at 0 50%, rgba(15, 23, 42, 0.16), rgba(15, 23, 42, 0)) left / 12px 100% no-repeat scroll,
|
||
radial-gradient(farthest-side at 100% 50%, rgba(15, 23, 42, 0.16), rgba(15, 23, 42, 0)) right / 12px 100% no-repeat scroll;
|
||
}
|
||
|
||
.m-table-scroll > table {
|
||
min-width: 560px;
|
||
}
|
||
|
||
.m-table-scroll.m-tight > table {
|
||
min-width: 0;
|
||
}
|
||
|
||
table,
|
||
.data-table {
|
||
font-size: 0.82rem;
|
||
}
|
||
|
||
table th,
|
||
table td,
|
||
.data-table thead th,
|
||
.data-table tbody td {
|
||
padding: 9px 10px;
|
||
white-space: nowrap;
|
||
}
|
||
|
||
/* 表格内的按钮别撑破行 */
|
||
table .btn-primary,
|
||
table .btn-secondary,
|
||
table .btn-danger,
|
||
.data-table .btn-primary,
|
||
.data-table .btn-secondary,
|
||
.data-table .btn-danger {
|
||
min-height: 34px;
|
||
padding: 4px 10px;
|
||
font-size: 0.78rem;
|
||
}
|
||
|
||
/* 单元格里的长文本允许换行 */
|
||
.data-table td .m-wrap,
|
||
td.m-wrap {
|
||
white-space: normal;
|
||
min-width: 160px;
|
||
}
|
||
}
|
||
|
||
/* --------------------------------------------------------------------------
|
||
9. 表单与按钮
|
||
-------------------------------------------------------------------------- */
|
||
@media (max-width: 767.98px) {
|
||
.form-group,
|
||
.form-row {
|
||
margin-bottom: 12px;
|
||
}
|
||
|
||
.form-group label {
|
||
font-size: 0.85rem;
|
||
margin-bottom: 6px;
|
||
}
|
||
|
||
input[type="text"],
|
||
input[type="search"],
|
||
input[type="password"],
|
||
input[type="number"],
|
||
input[type="email"],
|
||
input[type="url"],
|
||
input[type="date"],
|
||
input[type="datetime-local"],
|
||
select,
|
||
textarea {
|
||
width: 100%;
|
||
box-sizing: border-box;
|
||
min-height: var(--m-touch);
|
||
padding: 10px 12px;
|
||
border-radius: 10px;
|
||
}
|
||
|
||
textarea {
|
||
min-height: 96px;
|
||
resize: vertical;
|
||
}
|
||
|
||
/* 一行多列的表单在手机上堆叠 */
|
||
.form-grid,
|
||
.form-row.multi,
|
||
.settings-grid {
|
||
grid-template-columns: 1fr !important;
|
||
display: grid;
|
||
gap: 12px;
|
||
}
|
||
|
||
.form-actions,
|
||
.page-header-actions.m-stack {
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
gap: 8px;
|
||
}
|
||
|
||
.form-actions > button,
|
||
.modal-footer > button {
|
||
flex: 1 1 auto;
|
||
}
|
||
}
|
||
|
||
/* --------------------------------------------------------------------------
|
||
10. 弹窗 / 下拉 / 浮层
|
||
-------------------------------------------------------------------------- */
|
||
@media (max-width: 767.98px) {
|
||
.modal {
|
||
padding: 0;
|
||
}
|
||
|
||
.modal-content {
|
||
width: 100%;
|
||
max-width: 100%;
|
||
height: 100%;
|
||
max-height: 100%;
|
||
margin: 0;
|
||
border-radius: 0;
|
||
border: none;
|
||
animation: m-sheet-up 0.26s var(--m-ease);
|
||
padding-top: var(--m-safe-top);
|
||
padding-bottom: var(--m-safe-bottom);
|
||
box-sizing: border-box;
|
||
}
|
||
|
||
@keyframes m-sheet-up {
|
||
from {
|
||
transform: translateY(16px);
|
||
opacity: 0.4;
|
||
}
|
||
|
||
to {
|
||
transform: none;
|
||
opacity: 1;
|
||
}
|
||
}
|
||
|
||
.modal-header {
|
||
padding: 12px var(--m-gutter);
|
||
flex-shrink: 0;
|
||
position: sticky;
|
||
top: 0;
|
||
background: var(--bg-primary);
|
||
z-index: 2;
|
||
border-bottom: 1px solid var(--border-color);
|
||
}
|
||
|
||
.modal-header h2,
|
||
.modal-header h3 {
|
||
font-size: 1.02rem;
|
||
}
|
||
|
||
.modal-body {
|
||
padding: var(--m-gutter);
|
||
flex: 1;
|
||
overflow-y: auto;
|
||
-webkit-overflow-scrolling: touch;
|
||
}
|
||
|
||
.modal-footer {
|
||
padding: 10px var(--m-gutter);
|
||
padding-bottom: calc(10px + var(--m-safe-bottom));
|
||
flex-shrink: 0;
|
||
position: sticky;
|
||
bottom: 0;
|
||
background: var(--bg-primary);
|
||
border-top: 1px solid var(--border-color);
|
||
display: flex;
|
||
gap: 8px;
|
||
flex-wrap: wrap;
|
||
}
|
||
|
||
.modal-close,
|
||
.modal .close {
|
||
width: var(--m-touch);
|
||
height: var(--m-touch);
|
||
min-height: var(--m-touch);
|
||
}
|
||
|
||
/* 头部下拉:贴边全宽 */
|
||
.notification-dropdown,
|
||
.user-menu-dropdown,
|
||
.lang-dropdown {
|
||
position: fixed !important;
|
||
left: 8px !important;
|
||
right: 8px !important;
|
||
top: calc(var(--m-appbar-h) + var(--m-safe-top) - 4px) !important;
|
||
width: auto !important;
|
||
max-width: none !important;
|
||
max-height: 70vh;
|
||
overflow-y: auto;
|
||
-webkit-overflow-scrolling: touch;
|
||
border-radius: var(--m-radius-card);
|
||
z-index: 1210;
|
||
}
|
||
|
||
/* 角色 / 项目 / 对话模式选择面板在手机上统一为底部抽屉,但**不盖输入框**:
|
||
YG 反馈「输入框和这三个功能点重叠」,实测面板 bottom:66px 恰好盖住输入条
|
||
(.chat-input-container 占据视口底部 186px)。现在 bottom 用 JS 测得的
|
||
--m-panel-offset(输入条顶部到视口底 + 8px 间距),面板始终弹在输入条正上方,
|
||
微信输入面板同款行为:输入条全程可见可点,点输入条即收起面板。
|
||
对话模式面板原先漏在这一组之外,仍按桌面的 position:absolute + left:0 定位,
|
||
在 320–412px 视口下以按钮包裹层为基准取全屏宽度,右边缘实测越界 198px。 */
|
||
.role-selection-panel,
|
||
.chat-project-panel,
|
||
.agent-mode-panel {
|
||
position: fixed !important;
|
||
left: 8px !important;
|
||
right: 8px !important;
|
||
bottom: var(--m-panel-offset, calc(var(--m-tabbar-h) + var(--m-safe-bottom) + 8px)) !important;
|
||
top: auto !important;
|
||
width: auto !important;
|
||
max-width: none !important;
|
||
max-height: var(--m-panel-maxh, 62vh);
|
||
border-radius: var(--m-radius-sheet);
|
||
z-index: 1210;
|
||
/* 面板与背景同色,上向投影把抽屉与聊天区明确分开 */
|
||
box-shadow: 0 -10px 30px rgba(0, 0, 0, 0.16), 0 -1px 0 rgba(0, 0, 0, 0.06);
|
||
}
|
||
|
||
/* 轻提示 */
|
||
#m-toast {
|
||
position: fixed;
|
||
left: 50%;
|
||
/* 底栏按 --m-bar-bottom 抬升时提示条要一起抬,否则会压在底栏上 */
|
||
bottom: calc(var(--m-tabbar-h) + var(--m-safe-bottom) + 16px + var(--m-bar-bottom));
|
||
transform: translate(-50%, 12px);
|
||
z-index: var(--m-z-toast);
|
||
max-width: 88vw;
|
||
padding: 10px 16px;
|
||
border-radius: 999px;
|
||
background: rgba(15, 23, 42, 0.92);
|
||
color: #fff;
|
||
font-size: 0.82rem;
|
||
line-height: 1.35;
|
||
text-align: center;
|
||
opacity: 0;
|
||
visibility: hidden;
|
||
transition: opacity 0.2s ease, transform 0.24s var(--m-ease), visibility 0.24s;
|
||
pointer-events: none;
|
||
}
|
||
|
||
#m-toast.m-show {
|
||
opacity: 1;
|
||
visibility: visible;
|
||
transform: translate(-50%, 0);
|
||
}
|
||
}
|
||
|
||
/* --------------------------------------------------------------------------
|
||
11. 对话页
|
||
-------------------------------------------------------------------------- */
|
||
@media (max-width: 767.98px) {
|
||
.chat-page-layout {
|
||
flex-direction: row;
|
||
}
|
||
|
||
/* 会话列表 → 左侧抽屉 */
|
||
.conversation-sidebar {
|
||
position: fixed;
|
||
top: 0;
|
||
bottom: 0;
|
||
left: 0;
|
||
width: var(--m-drawer-w) !important;
|
||
max-width: 86vw;
|
||
height: 100%;
|
||
height: 100dvh;
|
||
height: var(--m-app-height, 100dvh);
|
||
z-index: var(--m-z-drawer);
|
||
transform: translateX(-102%);
|
||
visibility: hidden;
|
||
transition: transform 0.3s var(--m-ease), visibility 0.3s linear;
|
||
border-radius: 0 var(--m-radius-sheet) var(--m-radius-sheet) 0;
|
||
box-shadow: none;
|
||
padding-top: var(--m-safe-top);
|
||
}
|
||
|
||
.conversation-sidebar.m-open {
|
||
transform: translateX(0);
|
||
visibility: visible;
|
||
box-shadow: 0 18px 48px rgba(0, 0, 0, 0.45);
|
||
}
|
||
|
||
.conversation-sidebar.collapsed {
|
||
width: var(--m-drawer-w) !important;
|
||
}
|
||
|
||
/* 桌面语义的「折叠」在手机上只会加一个无效 class,隐藏掉,让位给关闭按钮 */
|
||
.conversation-sidebar-collapse-btn {
|
||
display: none !important;
|
||
}
|
||
|
||
/* 抽屉只盖住左侧 320px,右侧露出的工具条按钮会误触,打开时整体隐藏 */
|
||
body.m-chat-drawer-open .m-chat-bar {
|
||
visibility: hidden;
|
||
}
|
||
|
||
.m-chat-drawer-close {
|
||
margin-left: auto;
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
.m-chat-drawer-head {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
gap: 8px;
|
||
padding: 8px 10px 8px var(--m-gutter);
|
||
border-bottom: 1px solid var(--border-color);
|
||
background: var(--bg-primary);
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
.m-chat-drawer-title {
|
||
font-size: 0.9375rem;
|
||
font-weight: 600;
|
||
color: var(--text-primary);
|
||
}
|
||
|
||
.conversation-header {
|
||
padding: 6px var(--m-gutter);
|
||
}
|
||
|
||
.chat-messages {
|
||
padding: 12px 12px 12px 12px;
|
||
}
|
||
|
||
/* 消息气泡占满宽度 */
|
||
.chat-messages .message,
|
||
.chat-messages .message-row,
|
||
.chat-messages .conversation-message {
|
||
max-width: 100%;
|
||
}
|
||
|
||
/* 轮次导航条在窄屏上太挤,直接收起 */
|
||
#chat-turn-rail {
|
||
display: none !important;
|
||
}
|
||
|
||
#chat-return-latest {
|
||
right: 10px;
|
||
bottom: 12px;
|
||
}
|
||
|
||
.chat-input-container {
|
||
padding: 8px 10px;
|
||
gap: 6px;
|
||
border-top: 1px solid var(--border-color);
|
||
}
|
||
|
||
.chat-input-primary-row {
|
||
gap: 6px;
|
||
}
|
||
|
||
.chat-input-leading {
|
||
gap: 6px;
|
||
}
|
||
|
||
/* 输入区里的次要按钮收成图标 */
|
||
.chat-input-container .role-selector-text {
|
||
max-width: 88px;
|
||
overflow: hidden;
|
||
text-overflow: ellipsis;
|
||
white-space: nowrap;
|
||
}
|
||
|
||
/* 三个选择面板的关闭按钮桌面是 32×32,手机端放大到 44×44 满足触控 */
|
||
.role-selection-panel-close {
|
||
width: var(--m-touch) !important;
|
||
height: var(--m-touch) !important;
|
||
min-width: var(--m-touch) !important;
|
||
min-height: var(--m-touch) !important;
|
||
}
|
||
|
||
/* 发送按钮桌面是 40×40 圆形,手机端补足到 44×44(触控最小命中区) */
|
||
.chat-input-container .send-btn,
|
||
#chat-send-btn {
|
||
width: var(--m-touch) !important;
|
||
min-width: var(--m-touch) !important;
|
||
height: var(--m-touch) !important;
|
||
min-height: var(--m-touch) !important;
|
||
}
|
||
|
||
.chat-input-container .send-btn svg {
|
||
width: 20px;
|
||
height: 20px;
|
||
}
|
||
|
||
/* ------------------------------------------------------------------
|
||
19.1 触摸命中区统一补齐到 44×44(WCAG 2.5.8 / iOS HIG 最小可点区)
|
||
依据 _mtouch.mjs 实测:顶部栏图标 38×38、通用按钮高 40、
|
||
.btn-small 高 38、设置页导航项高 37、对话工具条高 40 —— 均低于 44。
|
||
只提升命中区高度/宽度,不改字号与配色。
|
||
------------------------------------------------------------------ */
|
||
.header-logo-link,
|
||
#notification-bell-btn,
|
||
#user-avatar-btn,
|
||
.m-chat-bar-btn,
|
||
.chat-upload-btn,
|
||
.btn-secondary,
|
||
.btn-primary,
|
||
.btn-small,
|
||
.btn-danger,
|
||
.settings-nav-item,
|
||
.settings-custom-select-trigger,
|
||
.page-header-actions button,
|
||
.page-header-actions a {
|
||
min-height: var(--m-touch) !important;
|
||
}
|
||
|
||
#notification-bell-btn,
|
||
#user-avatar-btn,
|
||
.chat-upload-btn {
|
||
width: var(--m-touch) !important;
|
||
min-width: var(--m-touch) !important;
|
||
}
|
||
|
||
/* 设置页导航 chip「C2」是最短项,实测只有 41px 宽 */
|
||
.settings-nav-item {
|
||
min-width: var(--m-touch) !important;
|
||
}
|
||
|
||
/* 复选框/单选框的尺寸见 24.11(已并入按钮体系,避免两处各说一套) */
|
||
|
||
.chat-input-field textarea,
|
||
.chat-input-field .chat-textarea {
|
||
max-height: 132px;
|
||
font-size: 16px;
|
||
}
|
||
|
||
#chat-hitl-approval-dock {
|
||
border-radius: var(--m-radius-card);
|
||
}
|
||
|
||
/* 附件列表横向滚动 */
|
||
.chat-file-list {
|
||
overflow-x: auto;
|
||
flex-wrap: nowrap;
|
||
-webkit-overflow-scrolling: touch;
|
||
}
|
||
|
||
/* 对话页移动端工具条(由 mobile-ui.js 注入到 .chat-container 首位) */
|
||
#m-chat-bar {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 8px;
|
||
flex-shrink: 0;
|
||
padding: 6px 10px;
|
||
background: var(--bg-primary);
|
||
border-bottom: 1px solid var(--border-color);
|
||
}
|
||
|
||
.m-chat-bar-spacer {
|
||
flex: 1;
|
||
}
|
||
|
||
.m-chat-bar-btn {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
gap: 6px;
|
||
min-height: 36px;
|
||
padding: 0 13px;
|
||
border-radius: 999px;
|
||
border: 1px solid var(--border-color);
|
||
background: var(--bg-tertiary);
|
||
color: var(--text-primary);
|
||
font-size: 0.8125rem;
|
||
font-weight: 500;
|
||
line-height: 1;
|
||
cursor: pointer;
|
||
-webkit-tap-highlight-color: transparent;
|
||
transition: transform 0.12s var(--m-ease), background 0.15s;
|
||
}
|
||
|
||
.m-chat-bar-btn svg {
|
||
width: 16px;
|
||
height: 16px;
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
.m-chat-bar-btn:active {
|
||
transform: scale(0.95);
|
||
}
|
||
|
||
.m-chat-bar-btn.m-primary {
|
||
background: var(--accent-color);
|
||
border-color: var(--accent-color);
|
||
color: #ffffff;
|
||
}
|
||
|
||
/* _mchat12.mjs 实测:会话抽屉条目 38px、会话设置折叠头 39px、
|
||
HITL 审批人开关仅 30px——都藏在抽屉/折叠区,之前全站扫描扫不到。
|
||
这些是可点交互控件,统一提到 44px。 */
|
||
#conversation-sidebar .conversation-item,
|
||
#conversation-sidebar .project-conversation-item,
|
||
#conversation-reasoning-toggle,
|
||
.hitl-reviewer-toggle-btn,
|
||
.hitl-config-select,
|
||
.hitl-config-field .hitl-config-label {
|
||
min-height: var(--m-touch) !important;
|
||
}
|
||
|
||
.hitl-reviewer-toggle-btn {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
}
|
||
}
|
||
|
||
/* --------------------------------------------------------------------------
|
||
12. 终端 / WebShell / C2
|
||
-------------------------------------------------------------------------- */
|
||
@media (max-width: 767.98px) {
|
||
.webshell-layout,
|
||
.c2-layout,
|
||
.terminal-layout {
|
||
flex-direction: column !important;
|
||
}
|
||
|
||
.webshell-sidebar,
|
||
.c2-sidebar,
|
||
.terminal-sidebar {
|
||
width: 100% !important;
|
||
max-width: none !important;
|
||
max-height: 40vh;
|
||
border-right: none;
|
||
border-bottom: 1px solid var(--border-color);
|
||
}
|
||
|
||
.terminal-container,
|
||
.xterm {
|
||
font-size: 12px;
|
||
}
|
||
|
||
.xterm-viewport {
|
||
-webkit-overflow-scrolling: touch;
|
||
overscroll-behavior: contain;
|
||
}
|
||
|
||
/* 终端工具条横向滚动 */
|
||
.terminal-toolbar,
|
||
.webshell-toolbar,
|
||
.c2-toolbar {
|
||
overflow-x: auto;
|
||
flex-wrap: nowrap;
|
||
scrollbar-width: none;
|
||
-webkit-overflow-scrolling: touch;
|
||
}
|
||
|
||
.terminal-toolbar::-webkit-scrollbar,
|
||
.webshell-toolbar::-webkit-scrollbar,
|
||
.c2-toolbar::-webkit-scrollbar {
|
||
display: none;
|
||
}
|
||
}
|
||
|
||
/* --------------------------------------------------------------------------
|
||
13. 登录页
|
||
-------------------------------------------------------------------------- */
|
||
@media (max-width: 767.98px) {
|
||
.login-overlay {
|
||
padding: 16px;
|
||
padding-top: calc(16px + var(--m-safe-top));
|
||
padding-bottom: calc(16px + var(--m-safe-bottom));
|
||
align-items: center;
|
||
overflow-y: auto;
|
||
-webkit-overflow-scrolling: touch;
|
||
}
|
||
|
||
.login-card {
|
||
width: 100%;
|
||
max-width: 420px;
|
||
padding: 22px 18px;
|
||
border-radius: var(--m-radius-sheet);
|
||
margin: auto;
|
||
}
|
||
|
||
.login-title {
|
||
font-size: 1.25rem;
|
||
}
|
||
|
||
.login-submit {
|
||
min-height: 48px;
|
||
font-size: 1rem;
|
||
width: 100%;
|
||
}
|
||
}
|
||
|
||
/* --------------------------------------------------------------------------
|
||
14. 网格 / 统计卡 / 图表
|
||
-------------------------------------------------------------------------- */
|
||
@media (max-width: 767.98px) {
|
||
.stats-grid,
|
||
.kpi-grid,
|
||
.cards-grid,
|
||
.metrics-grid,
|
||
.dashboard-grid,
|
||
.overview-grid {
|
||
grid-template-columns: 1fr !important;
|
||
gap: 10px;
|
||
}
|
||
|
||
.stats-grid.m-two,
|
||
.kpi-grid.m-two {
|
||
grid-template-columns: repeat(2, minmax(0, 1fr)) !important;
|
||
}
|
||
|
||
/* 图表容器限高,避免 canvas 撑出屏幕 */
|
||
canvas {
|
||
max-width: 100% !important;
|
||
}
|
||
|
||
.chart-container,
|
||
.graph-container,
|
||
#fact-graph,
|
||
#asset-graph {
|
||
min-height: 260px;
|
||
max-height: 62vh;
|
||
}
|
||
|
||
/* 标签 / 徽章不换行溢出 */
|
||
.badge,
|
||
.tag,
|
||
.status-badge,
|
||
.pill {
|
||
white-space: nowrap;
|
||
}
|
||
}
|
||
|
||
/* --------------------------------------------------------------------------
|
||
15. 平板区间(768–1023.98px):保留桌面结构,仅做收敛
|
||
-------------------------------------------------------------------------- */
|
||
@media (min-width: 768px) and (max-width: 1023.98px) {
|
||
.main-sidebar {
|
||
width: 190px;
|
||
}
|
||
|
||
.page-content {
|
||
padding: 14px 16px;
|
||
}
|
||
|
||
.chat-messages {
|
||
padding: 16px 16px 16px 24px;
|
||
}
|
||
|
||
.conversation-sidebar {
|
||
width: 264px;
|
||
}
|
||
}
|
||
|
||
/* --------------------------------------------------------------------------
|
||
16. 横屏手机:把底部栏压薄,让出纵向空间
|
||
-------------------------------------------------------------------------- */
|
||
@media (max-width: 900px) and (orientation: landscape) and (max-height: 500px) {
|
||
:root {
|
||
--m-tabbar-h: 46px;
|
||
--m-appbar-h: 44px;
|
||
}
|
||
|
||
#m-tabbar .m-tab span {
|
||
display: none;
|
||
}
|
||
|
||
#m-tabbar .m-tab svg {
|
||
width: 21px;
|
||
height: 21px;
|
||
}
|
||
|
||
.main-sidebar {
|
||
width: min(70vw, 300px) !important;
|
||
}
|
||
}
|
||
|
||
/* --------------------------------------------------------------------------
|
||
17. 无障碍与性能
|
||
-------------------------------------------------------------------------- */
|
||
@media (max-width: 767.98px) {
|
||
@media (prefers-reduced-motion: reduce) {
|
||
|
||
.main-sidebar,
|
||
.conversation-sidebar,
|
||
#m-tabbar,
|
||
#m-sheet,
|
||
.m-scrim,
|
||
#m-toast {
|
||
transition-duration: 0.01ms !important;
|
||
}
|
||
|
||
.page.active {
|
||
animation: none !important;
|
||
}
|
||
}
|
||
|
||
/* 焦点可见性(键盘 / 辅助设备) */
|
||
a:focus-visible,
|
||
button:focus-visible,
|
||
input:focus-visible,
|
||
select:focus-visible,
|
||
textarea:focus-visible,
|
||
[tabindex]:focus-visible {
|
||
outline: 2px solid var(--accent-color);
|
||
outline-offset: 2px;
|
||
}
|
||
}
|
||
|
||
/* 抽屉/面板打开时锁定背景滚动 */
|
||
body.m-locked {
|
||
overflow: hidden !important;
|
||
}
|
||
|
||
/* --------------------------------------------------------------------------
|
||
17.6 选择面板层级修正(关键)
|
||
--------------------------------------------------------------------------
|
||
.chat-input-container 带 container-type: inline-size,会创建独立的层叠
|
||
上下文,导致内部 position:fixed 的 .chat-project-panel / .role-selection-panel
|
||
/ .agent-mode-panel 的 z-index:1210 只在容器内部比较,无法与 body 级
|
||
#m-scrim(z-index:1200) 竞争 —— 实测 elementFromPoint 命中 .m-scrim,
|
||
面板收不到任何触摸事件,下滑关闭失效。
|
||
面板打开期间把容器提升到 1215(高于 scrim 1200 / drawer 1201 / sheet 1202,
|
||
低于 toast 1300),容器本身无 position,故需显式 position: relative。
|
||
-------------------------------------------------------------------------- */
|
||
body.m-panel-open .chat-input-container {
|
||
position: relative;
|
||
z-index: 1215;
|
||
}
|
||
|
||
/* --------------------------------------------------------------------------
|
||
18. 可读性 / 对比度 / 溢出修复
|
||
--------------------------------------------------------------------------
|
||
依据 _mvisual.mjs 实测:light 主题 --text-muted(#adb5bd) 在白底上只有
|
||
2.07:1,--text-secondary(#6c757d) 4.69:1,均不满足 WCAG AA(4.5:1);
|
||
11px 标签在手机上不可读;WebShell 工作区比视口宽 5px;设置页下拉选中值
|
||
与 AI 通道 chip 被 flex 压缩到 6~22px 宽。
|
||
以下仅在移动端生效,桌面端保持原样。
|
||
-------------------------------------------------------------------------- */
|
||
@media (max-width: 767.98px) {
|
||
|
||
/* 18.1 文本色令牌提到 AA 级 */
|
||
html:not([data-theme="dark"]) {
|
||
--text-secondary: #525d6c;
|
||
/* 白底 6.6:1,灰底(≥#f8fafc)仍 ≥6.2:1 */
|
||
--text-muted: #5b6472;
|
||
/* 白底 6.0:1,浅灰底(#f1f3f5) 5.5:1 —— 原 #adb5bd 仅 2.07:1 */
|
||
/* 原 #3b82f6 作正文色在白底仅 3.68:1,深一档后 5.2:1 */
|
||
--accent-color: #2563eb;
|
||
}
|
||
|
||
html[data-theme="dark"] {
|
||
--text-muted: #9ca3af;
|
||
/* #111827 底 7.2:1 */
|
||
}
|
||
|
||
/* 18.2 小字号下限 12px */
|
||
.dashboard-severity-insight-score-label,
|
||
.dashboard-severity-insight-urgent-label,
|
||
.dashboard-severity-center-label,
|
||
.dashboard-severity-status-label,
|
||
.mcp-stats-kpi__label,
|
||
.mcp-stats-kpi__chip,
|
||
.pagination-info,
|
||
.pagination-page,
|
||
.hitl-tab-badge,
|
||
.version-badge,
|
||
/* 补漏(_mprobe.mjs 实测仍为 11px):projects 页的状态胶囊、统计 chip、
|
||
事实筛选标签,以及分页的「每页」标签 */
|
||
.projects-status-pill,
|
||
.projects-stat-chip,
|
||
.projects-fact-filter-label,
|
||
.pagination-page-size {
|
||
font-size: 12px !important;
|
||
}
|
||
|
||
/* 18.2b 第九轮(审计覆盖从假 14 页修成真实 29 页后)新暴露的小字。
|
||
asset-overview 的资产类型统计标签 11px、协议表头 9px;
|
||
agents-management 的角色徽章 11px;platform-rbac 的状态胶囊 11px。
|
||
图标字符(如 .tool-expand-icon 的 ▶ 10px)不属于文本,不在此列。 */
|
||
.asset-type-item span,
|
||
.asset-protocol-compact__header p,
|
||
.asset-panel-meta,
|
||
.asset-protocol-columns span,
|
||
.agent-role-badge,
|
||
.rbac-pill {
|
||
font-size: 12px !important;
|
||
}
|
||
|
||
/* 18.3 语义色徽章/数值加粗,补偿配色本身的低对比 */
|
||
.dashboard-severity-insight-risk-badge,
|
||
.dashboard-severity-status-value,
|
||
.dashboard-severity-insight-score-value {
|
||
font-weight: 700;
|
||
}
|
||
|
||
/* 18.4 WebShell / C2 / 终端工作区横向溢出 */
|
||
.webshell-main,
|
||
.webshell-workspace,
|
||
.c2-main,
|
||
.terminal-main {
|
||
width: 100% !important;
|
||
max-width: 100% !important;
|
||
min-width: 0 !important;
|
||
box-sizing: border-box;
|
||
overflow-x: hidden;
|
||
}
|
||
|
||
/* 18.5 设置页自定义下拉:选中值不再被压扁 */
|
||
*:has(> .settings-custom-select-value) {
|
||
min-width: 0;
|
||
}
|
||
|
||
.settings-custom-select-value {
|
||
flex: 1 1 max-content !important;
|
||
min-width: 0 !important;
|
||
max-width: 100%;
|
||
overflow: hidden;
|
||
text-overflow: ellipsis;
|
||
white-space: nowrap;
|
||
}
|
||
|
||
/* 18.6 AI 通道 chip:容器占满整行并允许换行,chip 不再被压到不可读 */
|
||
*:has(> .ai-channel-editor-chip) {
|
||
flex: 1 1 100% !important;
|
||
flex-wrap: wrap !important;
|
||
width: 100%;
|
||
min-width: 0;
|
||
row-gap: 6px;
|
||
}
|
||
|
||
.ai-channel-editor-chip {
|
||
flex: 0 0 auto !important;
|
||
max-width: 100%;
|
||
overflow: hidden;
|
||
text-overflow: ellipsis;
|
||
white-space: nowrap;
|
||
}
|
||
|
||
/* 18.7 对话页人工审批标签:原思路是"缩小 1px 就能完整显示",实测不成立
|
||
—— 见 24.14 的真实根因(max-width:142px 才是瓶颈,缩字号只是把裁切推迟)。 */
|
||
|
||
/* 18.8 dashboard 残留 11px 标签 */
|
||
.dashboard-batch-side-stat-label,
|
||
.dashboard-severity-progress-legend-item span,
|
||
.dashboard-severity-status-text span:not([id]) {
|
||
font-size: 12px !important;
|
||
}
|
||
|
||
/* 18.9 硬编码浅灰文本(不随令牌走)逐个纠正 */
|
||
#c2-sessions-count,
|
||
#page-knowledge-management .empty-state p,
|
||
#page-knowledge-management .empty-state div {
|
||
color: var(--text-secondary) !important;
|
||
}
|
||
|
||
/* 18.10 语义色徽章 / 状态数值:加深到 AA 级 */
|
||
.role-card-badge.enabled {
|
||
color: #157347;
|
||
background: rgba(40, 167, 69, 0.16);
|
||
}
|
||
|
||
#dashboard-status-fp {
|
||
color: #64748b !important;
|
||
}
|
||
|
||
/* 18.10b 第七轮补:语义色**文字**再次加深(原 2.09~2.88:1)
|
||
重算方式不是拿白底硬套,而是用 `_mcontrast.mjs` 逐层合成真实有效背景
|
||
(徽章自己还叠了 rgba(34,197,94,0.12)+0.04 两层底 → #dcf6e6),再对
|
||
"保持色相与饱和度、只压亮度"做二分求解,目标 5.0:1(比 AA 的 4.5 留一点
|
||
余量,避免不同背景合成算法得出不同结论)。
|
||
最要紧的是 dashboard 的「安全」徽章与四个状态计数——它们是页面主数据,
|
||
2.09:1 在手机户外基本读不出来。原则:**只动亮度,不动色相**,所以
|
||
「红=高危 / 绿=已修复 / 琥珀=待确认 / 灰=已忽略」的语义完整保留,
|
||
纠正的只是「把填充色直接当文字色用」这个反模式。
|
||
深色主题不受影响(同 18.14 的做法,见 23.4 的对称处理)。 */
|
||
html:not([data-theme="dark"]) #dashboard-severity-risk-level {
|
||
color: #107636 !important;
|
||
}
|
||
|
||
html:not([data-theme="dark"]) #dashboard-status-open {
|
||
color: #d81212 !important;
|
||
}
|
||
|
||
html:not([data-theme="dark"]) #dashboard-status-confirmed {
|
||
color: #986206 !important;
|
||
}
|
||
|
||
html:not([data-theme="dark"]) #dashboard-status-fixed {
|
||
color: #167e3c !important;
|
||
}
|
||
|
||
html:not([data-theme="dark"]) #dashboard-status-ignored {
|
||
color: #5a6d88 !important;
|
||
}
|
||
|
||
html:not([data-theme="dark"]) .dashboard-recommend-arrow {
|
||
color: #67707f !important;
|
||
}
|
||
|
||
html:not([data-theme="dark"]) .projects-fact-filter-label {
|
||
color: #5d718c !important;
|
||
}
|
||
|
||
/* 18.10c 必填项星号:样式表里有 4 种写法(`.required-mark` / `.form-required` /
|
||
`.required` / 内联 `style="color: red;"`),同一种语义 4 套颜色。
|
||
其中内联那种是纯 #ff0000,在白底上只有 4.0:1(星号也是文字,归 AA)。
|
||
统一到 18.11 已经在用的 #b02a37(≈6.0:1),一个语义一个颜色。
|
||
内联样式优先级高于普通规则,必须 !important 才压得住。 */
|
||
html:not([data-theme="dark"]) label > span[style*="color: red"],
|
||
html:not([data-theme="dark"]) label > span[style*="color:red"],
|
||
html:not([data-theme="dark"]) label > span.form-required,
|
||
html:not([data-theme="dark"]) label > span.required,
|
||
html:not([data-theme="dark"]) label > span.required-mark {
|
||
color: #b02a37 !important;
|
||
}
|
||
|
||
/* 18.11 白底红字按钮:原 #dc3545 仅 4.0:1 */
|
||
.btn-secondary.btn-danger,
|
||
.btn-secondary.btn-delete {
|
||
color: #b02a37 !important;
|
||
}
|
||
|
||
/* 18.12 C2 工具栏文字型按钮(无类名,继承 accent 色);
|
||
排除带内联背景的按钮,避免文字色与底色撞车 */
|
||
#page-c2-sessions button:not(.btn-primary):not(.btn-secondary):not(.btn-danger):not([style*="background"]) {
|
||
color: #1d4ed8 !important;
|
||
}
|
||
|
||
/* 18.13 dashboard / HITL / 知识库残留的低对比文本(原 3.3~4.5:1) */
|
||
#dashboard-fix-rate,
|
||
.dashboard-feed-tab {
|
||
color: var(--text-secondary) !important;
|
||
}
|
||
|
||
.dashboard-feed-tab.active {
|
||
color: var(--accent-color) !important;
|
||
}
|
||
|
||
.dashboard-empty-action,
|
||
#page-knowledge-management .empty-state button,
|
||
#page-knowledge-management .empty-state .btn,
|
||
#hitl-pending-count {
|
||
background-color: #2563eb !important;
|
||
border-color: #2563eb !important;
|
||
color: #ffffff !important;
|
||
font-weight: 600;
|
||
}
|
||
|
||
/* 18.14 硬编码灰/蓝文本再深一档(实测 4.0~4.34:1)
|
||
注意:这个深灰只在亮色主题下成立,深色主题下由区块 23.4 覆写。 */
|
||
html:not([data-theme="dark"]) #chat-hitl-shortcut-text,
|
||
html:not([data-theme="dark"]) #page-hitl .hitl-reviewer-toggle-btn,
|
||
html:not([data-theme="dark"]) #page-hitl .hitl-reviewer-toggle-btn span {
|
||
color: #4a5462 !important;
|
||
}
|
||
|
||
#projects-list-count {
|
||
color: #0052cc !important;
|
||
}
|
||
|
||
#page-settings .required-mark {
|
||
color: #b02a37 !important;
|
||
}
|
||
}
|
||
|
||
/* ==========================================================================
|
||
19. 设置页两栏布局在移动端塌陷(实测正文区仅剩 98px 宽)
|
||
--------------------------------------------------------------------------
|
||
根因:.page-content.settings-layout 是 flex-direction:row,
|
||
.settings-sidebar 固定 200px。390px 视口下 .settings-content 只剩 162px,
|
||
再扣 32px×2 内边距 → 正文 98px,下拉选中值与 AI 通道 chip 被压到 6~22px。
|
||
方案:移动端改单列,左侧导航变成顶部横向滚动的胶囊标签条。
|
||
========================================================================== */
|
||
@media (max-width: 767.98px) {
|
||
|
||
#page-settings .page-content.settings-layout {
|
||
flex-direction: column !important;
|
||
padding: 0 0 16px !important;
|
||
}
|
||
|
||
#page-settings .settings-sidebar {
|
||
width: 100% !important;
|
||
max-width: 100% !important;
|
||
height: auto !important;
|
||
flex: 0 0 auto !important;
|
||
border-right: 0 !important;
|
||
border-bottom: 1px solid var(--border-color);
|
||
background: var(--bg-primary);
|
||
position: sticky;
|
||
top: 0;
|
||
z-index: 5;
|
||
}
|
||
|
||
#page-settings .settings-nav {
|
||
display: flex !important;
|
||
flex-direction: row !important;
|
||
width: 100% !important;
|
||
height: auto !important;
|
||
min-height: 0 !important;
|
||
overflow-x: auto !important;
|
||
overflow-y: hidden !important;
|
||
gap: 6px;
|
||
padding: 8px 10px;
|
||
box-sizing: border-box;
|
||
scrollbar-width: none;
|
||
-webkit-overflow-scrolling: touch;
|
||
}
|
||
|
||
#page-settings .settings-nav::-webkit-scrollbar {
|
||
display: none;
|
||
}
|
||
|
||
#page-settings .settings-nav-item {
|
||
flex: 0 0 auto !important;
|
||
width: auto !important;
|
||
max-width: none !important;
|
||
white-space: nowrap;
|
||
padding: 8px 13px;
|
||
border-radius: 999px;
|
||
font-size: 13px;
|
||
border-left: 0 !important;
|
||
border-bottom: 0 !important;
|
||
}
|
||
|
||
#page-settings .settings-nav-item.active {
|
||
background: var(--accent-color);
|
||
color: #ffffff;
|
||
}
|
||
|
||
#page-settings .settings-content {
|
||
width: 100% !important;
|
||
max-width: 100% !important;
|
||
min-width: 0 !important;
|
||
flex: 1 1 auto !important;
|
||
padding: 14px 12px 24px !important;
|
||
box-sizing: border-box;
|
||
overflow-x: hidden;
|
||
}
|
||
|
||
/* 19.1 设置页内所有可伸缩容器放开宽度,禁止再被压缩 */
|
||
#page-settings .settings-section-content,
|
||
#page-settings .settings-subsection,
|
||
#page-settings .ai-channel-manager,
|
||
#page-settings .ai-channel-manager-body,
|
||
#page-settings .ai-channel-editor,
|
||
#page-settings .ai-channel-editor-head,
|
||
#page-settings .ai-channel-editor-meta,
|
||
#page-settings .ai-channel-switcher,
|
||
#page-settings .ai-channel-switcher-field,
|
||
#page-settings .settings-custom-select,
|
||
#page-settings .settings-custom-select-trigger {
|
||
width: 100% !important;
|
||
max-width: 100% !important;
|
||
min-width: 0 !important;
|
||
box-sizing: border-box;
|
||
}
|
||
|
||
/* 19.2 通道选择区原为 grid,移动端改为单列堆叠 */
|
||
#page-settings .ai-channel-switcher-field {
|
||
display: block !important;
|
||
}
|
||
|
||
/* 19.3 设置页宽表(审计日志 / 存储明细)自带 min-width:560px,
|
||
在 390px 视口直接撑破页面 → 改为容器内横向滚动 */
|
||
#page-settings *:has(> table.audit-log-table) {
|
||
overflow-x: auto !important;
|
||
max-width: 100% !important;
|
||
box-sizing: border-box;
|
||
-webkit-overflow-scrolling: touch;
|
||
}
|
||
|
||
#page-settings table.audit-log-table {
|
||
max-width: none;
|
||
}
|
||
|
||
/* 19.4 审计筛选区:.audit-field 固定 min-width:150px,
|
||
320px 视口下第二个字段被挤出屏幕 → 允许压缩 + 整行换行 */
|
||
#page-settings .audit-field {
|
||
min-width: 0 !important;
|
||
flex: 1 1 140px !important;
|
||
}
|
||
|
||
#page-settings .audit-datetime-field,
|
||
#page-settings .audit-datetime-btn {
|
||
min-width: 0 !important;
|
||
}
|
||
|
||
#page-settings *:has(> .audit-field) {
|
||
flex-wrap: wrap !important;
|
||
}
|
||
}
|
||
|
||
/* --------------------------------------------------------------------------
|
||
20. 页面头功能按钮布局 / 工具条触控 / 底部安全区
|
||
-------------------------------------------------------------------------- */
|
||
@media (max-width: 767.98px) {
|
||
|
||
/* 20.1 页面头功能按钮位置
|
||
根因:style.css:19132 的 @media (max-width: 768px) 把 .page-header-actions
|
||
设为 flex-direction: column; align-items: stretch;。本文件此前只覆盖了
|
||
align-items / flex-wrap / width,没有覆盖 flex-direction,于是
|
||
「刷新 / 批量导入 / 新增资产」这类按钮在手机上各占一行、各自居中。
|
||
改为横向换行自适应排列:能一行就一行(宽度 ≥444 左右),放不下自动换行,
|
||
任何设备宽度下按钮都完整可见、无需横向滑动。
|
||
注意:不要改回 nowrap + overflow-x —— 那会让主按钮(保存/新建)被推到
|
||
视口外需横滑才能看到,违背"自适应"诉求。 */
|
||
.page-header-actions,
|
||
.page-header > .page-header-actions,
|
||
.platform-rbac-page .page-header-actions,
|
||
.mcp-monitor-page .page-header-actions {
|
||
flex-direction: row !important;
|
||
flex-wrap: wrap !important;
|
||
align-items: center !important;
|
||
justify-content: flex-start !important;
|
||
gap: 8px !important;
|
||
width: 100%;
|
||
padding-bottom: 0;
|
||
}
|
||
|
||
/* 20.1b「已与服务端同步」状态块(tool-guard)84px 太占宽,会把主按钮挤出
|
||
一行。允许它在窄容器里收缩省略,留出空间给按钮。 */
|
||
.page-header-actions > .tool-guard-save-state {
|
||
flex: 0 1 auto;
|
||
min-width: 0;
|
||
max-width: 96px;
|
||
white-space: nowrap;
|
||
overflow: hidden;
|
||
text-overflow: ellipsis;
|
||
font-size: 11px;
|
||
}
|
||
|
||
.page-header-actions > * {
|
||
flex: 0 0 auto;
|
||
white-space: nowrap;
|
||
}
|
||
|
||
/* 头部文字按钮统一到可点尺寸并留出横向内边距 */
|
||
.page-header-actions > button,
|
||
.page-header-actions > a.btn,
|
||
.page-header-actions > .btn-primary,
|
||
.page-header-actions > .btn-secondary,
|
||
.page-header-actions > .btn-danger {
|
||
min-height: var(--m-touch) !important;
|
||
min-width: 64px;
|
||
padding-left: 14px !important;
|
||
padding-right: 14px !important;
|
||
}
|
||
|
||
/* 20.2 图标型按钮(分页 ‹ › 等)原本只有 20~32px 宽,点不中 */
|
||
.btn-icon-pagination,
|
||
.btn-icon,
|
||
.table-icon-btn,
|
||
.page-size-select {
|
||
min-width: var(--m-touch) !important;
|
||
min-height: var(--m-touch) !important;
|
||
}
|
||
|
||
/* 20.3 工作流画布工具条:5 个按钮挤在 32px 宽里,文字被截断 */
|
||
.workflow-toolbar,
|
||
.workflow-toolbar-actions,
|
||
.workflow-canvas-toolbar,
|
||
.workflow-toolbar-group {
|
||
flex-wrap: wrap !important;
|
||
gap: 6px !important;
|
||
}
|
||
|
||
.workflow-toolbar-button,
|
||
.workflow-save-button {
|
||
min-width: 72px !important;
|
||
min-height: var(--m-touch) !important;
|
||
padding: 0 10px !important;
|
||
font-size: 12px;
|
||
}
|
||
|
||
/* 20.4 小号按钮保底触控高度(原 .btn-small 只有 30~36px 高) */
|
||
.btn-small {
|
||
min-height: var(--m-touch) !important;
|
||
padding: 0 12px !important;
|
||
}
|
||
|
||
/* 20.5 底部安全区:在标签栏之上再留 10px,
|
||
避免滚到底后最后一行控件仍贴住标签栏 */
|
||
.content-area {
|
||
padding-bottom: calc(var(--m-tabbar-h) + var(--m-safe-bottom) + 10px);
|
||
}
|
||
|
||
/* 20.6 页面内自定义下拉触发器高度不足 44px */
|
||
.settings-custom-select-trigger,
|
||
.monitor-filter-select-trigger,
|
||
.projects-filter-select-trigger {
|
||
min-height: var(--m-touch) !important;
|
||
}
|
||
|
||
/* 20.7 对话页顶部工具条按钮原为 36px 高 */
|
||
.m-chat-bar-btn {
|
||
min-height: var(--m-touch) !important;
|
||
padding: 0 12px !important;
|
||
}
|
||
|
||
/* 20.8 上传等纯图标按钮宽高都不足 */
|
||
.chat-upload-btn {
|
||
min-width: var(--m-touch) !important;
|
||
min-height: var(--m-touch) !important;
|
||
}
|
||
}
|
||
|
||
/* ==========================================================================
|
||
21. 内容区滚动模型修复(手机端局部滚动容器塌陷)
|
||
--------------------------------------------------------------------------
|
||
桌面端这些页面用「固定高度容器 + 内部 overflow:hidden」把滚动锁在局部,
|
||
例如 .asset-list-card 自己滚分页。390x664 的手机视口下父级 flex 空间不足,
|
||
这些局部滚动容器被压到 16~48px 高,内部控件被 overflow:hidden 裁掉,
|
||
而且无论怎么滑动都露不出来。改成「内容区整页滚动 + 内部容器按内容展开」。
|
||
========================================================================== */
|
||
@media (max-width: 767.98px) {
|
||
|
||
/* 21.1 资产库:.asset-list-card 实测仅 48px 高,里面的分页控件 183px 全被裁 */
|
||
.page-content.asset-content {
|
||
display: block !important;
|
||
overflow-y: auto !important;
|
||
overflow-x: hidden !important;
|
||
-webkit-overflow-scrolling: touch;
|
||
}
|
||
|
||
.asset-list-card {
|
||
display: block !important;
|
||
flex: none !important;
|
||
height: auto !important;
|
||
max-height: none !important;
|
||
min-height: 0 !important;
|
||
overflow: visible !important;
|
||
}
|
||
|
||
#asset-pagination,
|
||
.pagination-container.pagination-fixed {
|
||
position: static !important;
|
||
height: auto !important;
|
||
min-height: 0 !important;
|
||
}
|
||
|
||
/* 21.2 技能管理:#skills-list 实测仅 16px 高,5483px 内容挤成一条缝 */
|
||
.page-content.page-content-with-pagination {
|
||
display: block !important;
|
||
overflow-y: auto !important;
|
||
overflow-x: hidden !important;
|
||
-webkit-overflow-scrolling: touch;
|
||
}
|
||
|
||
#skills-list,
|
||
.skills-grid {
|
||
flex: none !important;
|
||
height: auto !important;
|
||
max-height: none !important;
|
||
min-height: 0 !important;
|
||
overflow: visible !important;
|
||
}
|
||
|
||
#skills-pagination {
|
||
position: static !important;
|
||
height: auto !important;
|
||
}
|
||
|
||
/* 21.3 平台 RBAC:.rbac-panel-detail 实测 2px、#rbac-tab-roles 28px */
|
||
.platform-rbac-page .page-content {
|
||
display: block !important;
|
||
overflow-y: auto !important;
|
||
overflow-x: hidden !important;
|
||
-webkit-overflow-scrolling: touch;
|
||
}
|
||
|
||
#rbac-view-users,
|
||
.rbac-layout {
|
||
display: block !important;
|
||
height: auto !important;
|
||
min-height: 0 !important;
|
||
overflow: visible !important;
|
||
}
|
||
|
||
.rbac-panel,
|
||
.rbac-tab-panel,
|
||
#rbac-tab-roles,
|
||
#rbac-tab-permissions,
|
||
#rbac-tab-resources,
|
||
#rbac-tab-audit {
|
||
flex: none !important;
|
||
height: auto !important;
|
||
max-height: none !important;
|
||
min-height: 0 !important;
|
||
overflow: visible !important;
|
||
}
|
||
|
||
/* 21.4 工作流:侧栏节点列表与画布工具条被 overflow:hidden 裁掉 */
|
||
.page-content.workflow-page-content {
|
||
display: block !important;
|
||
min-height: 0 !important;
|
||
overflow-y: auto !important;
|
||
overflow-x: hidden !important;
|
||
-webkit-overflow-scrolling: touch;
|
||
}
|
||
|
||
.workflow-sidebar {
|
||
height: auto !important;
|
||
max-height: none !important;
|
||
overflow: visible !important;
|
||
}
|
||
|
||
/* 画布本身需要一块固定高度,不能被内容压成 0 */
|
||
.workflow-main {
|
||
height: auto !important;
|
||
min-height: 380px !important;
|
||
max-height: none !important;
|
||
overflow: visible !important;
|
||
}
|
||
|
||
/* 21.5 C2 会话「重置」按钮实测 24x44,横向点不中 */
|
||
#page-c2-sessions button,
|
||
.c2-sessions-page button {
|
||
min-width: 44px !important;
|
||
}
|
||
}
|
||
|
||
/* --------------------------------------------------------------------------
|
||
22. 平板竖屏(768–1023.98px):对话页三个选择面板同样贴底
|
||
桌面规则 style.css:29402 的 @media (max-width:768px) 把 .role-selection-panel /
|
||
.agent-mode-panel 改成 width:calc(100vw - 16px) + left:-8px,但仍是
|
||
position:absolute,定位基准是各自在 100–200px 处的按钮包裹层;实测 768x1024
|
||
下两者右边缘分别越界 563px 与 654px,面板完全落在屏幕之外。
|
||
-------------------------------------------------------------------------- */
|
||
@media (min-width: 768px) and (max-width: 1023.98px) {
|
||
.role-selection-panel,
|
||
.chat-project-panel,
|
||
.agent-mode-panel {
|
||
position: fixed !important;
|
||
left: 16px !important;
|
||
right: 16px !important;
|
||
bottom: var(--m-panel-offset, 16px) !important;
|
||
top: auto !important;
|
||
width: auto !important;
|
||
max-width: none !important;
|
||
max-height: var(--m-panel-maxh, 62vh);
|
||
border-radius: var(--m-radius-sheet);
|
||
z-index: 1210;
|
||
box-shadow: 0 -10px 30px rgba(0, 0, 0, 0.16), 0 -1px 0 rgba(0, 0, 0, 0.06);
|
||
}
|
||
}
|
||
|
||
/* --------------------------------------------------------------------------
|
||
22.2 触摸型横屏平板(1024–1439.98px + pointer:coarse):模式面板仍会越界
|
||
_mchat11.mjs 实测 1024x768 下 .agent-mode-panel 右边缘 1035 > 1024(offR=11)。
|
||
桌面鼠标保持原样(_mdesktop.mjs 已证明 1024x768 的桌面溢出为既有问题,不归本层管)。
|
||
-------------------------------------------------------------------------- */
|
||
@media (min-width: 1024px) and (max-width: 1439.98px) and (pointer: coarse) {
|
||
.role-selection-panel,
|
||
.chat-project-panel,
|
||
.agent-mode-panel {
|
||
position: fixed !important;
|
||
left: 16px !important;
|
||
right: 16px !important;
|
||
bottom: var(--m-panel-offset, 16px) !important;
|
||
top: auto !important;
|
||
width: auto !important;
|
||
max-width: none !important;
|
||
max-height: var(--m-panel-maxh, 62vh);
|
||
border-radius: var(--m-radius-sheet);
|
||
z-index: 1210;
|
||
box-shadow: 0 -10px 30px rgba(0, 0, 0, 0.16), 0 -1px 0 rgba(0, 0, 0, 0.06);
|
||
}
|
||
}
|
||
|
||
/* --------------------------------------------------------------------------
|
||
23. 深色主题对比度修正(_mdark.mjs 全站实测出 4 类违规)
|
||
深色令牌里 --accent-color 是 #60a5fa(浅蓝),配白字只有 2.54:1;
|
||
语义绿 #15803d 在 #111f29 底上 3.33:1;危险红 #b02a37 在 #111827 底上 2.73:1。
|
||
统一只改文字色、不动背景,保证亮色主题与桌面端完全不受影响。
|
||
-------------------------------------------------------------------------- */
|
||
@media (max-width: 767.98px) {
|
||
|
||
/* 23.1 浅蓝底(#60a5fa)上的白字 → 深墨蓝 #0b1120,实测 9.4:1 */
|
||
html[data-theme="dark"] .btn-primary,
|
||
html[data-theme="dark"] .btn-primary:hover,
|
||
html[data-theme="dark"] .btn-primary:focus,
|
||
html[data-theme="dark"] .m-chat-bar-btn.m-primary,
|
||
html[data-theme="dark"] .settings-nav-item.active,
|
||
html[data-theme="dark"] .chat-input-container .send-btn,
|
||
html[data-theme="dark"] .ai-channel-save-btn,
|
||
html[data-theme="dark"] #hitl-pending-count,
|
||
html[data-theme="dark"] .dashboard-empty-action,
|
||
html[data-theme="dark"] #page-knowledge-management .empty-state button,
|
||
html[data-theme="dark"] #page-knowledge-management .empty-state .btn {
|
||
color: #0b1120 !important;
|
||
}
|
||
|
||
html[data-theme="dark"] .btn-primary svg,
|
||
html[data-theme="dark"] .m-chat-bar-btn.m-primary svg,
|
||
html[data-theme="dark"] .chat-input-container .send-btn svg,
|
||
html[data-theme="dark"] .settings-nav-item.active svg {
|
||
color: #0b1120 !important;
|
||
fill: currentColor;
|
||
stroke: currentColor;
|
||
}
|
||
|
||
/* 23.2 语义绿在深底上提亮:#15803d → #4ade80,实测 8.9:1 */
|
||
html[data-theme="dark"] .is-success,
|
||
html[data-theme="dark"] .dashboard-kpi-sub-text.is-success,
|
||
html[data-theme="dark"] .mcp-stats-kpi__value--rate.is-success,
|
||
html[data-theme="dark"] .mcp-stats-kpi__status.is-success,
|
||
html[data-theme="dark"] .mcp-stats-tool-item__rate.is-success,
|
||
html[data-theme="dark"] .mcp-stats-rate.is-success {
|
||
color: #4ade80 !important;
|
||
}
|
||
|
||
/* 刷新闪烁态「上次更新」徽章同样是硬编码 #15803d */
|
||
html[data-theme="dark"] .dashboard-last-updated.is-flash {
|
||
color: #4ade80 !important;
|
||
background: rgba(74, 222, 128, 0.14);
|
||
}
|
||
|
||
/* 23.3 危险红在深底上提亮:#b02a37 → #f87171,实测 6.4:1 */
|
||
html[data-theme="dark"] {
|
||
--danger-color: #f87171;
|
||
--success-color: #4ade80;
|
||
}
|
||
|
||
html[data-theme="dark"] .required-mark,
|
||
html[data-theme="dark"] .btn-danger,
|
||
html[data-theme="dark"] .btn-secondary.btn-small.danger,
|
||
html[data-theme="dark"] .text-danger,
|
||
html[data-theme="dark"] .is-danger {
|
||
color: #f87171 !important;
|
||
}
|
||
|
||
/* 23.4 18.14 的硬编码深灰只对亮色成立,深色下交回 --text-muted(#9ca3af) */
|
||
html[data-theme="dark"] #chat-hitl-shortcut-text,
|
||
html[data-theme="dark"] #page-hitl .hitl-reviewer-toggle-btn,
|
||
html[data-theme="dark"] #page-hitl .hitl-reviewer-toggle-btn span {
|
||
color: var(--text-muted) !important;
|
||
}
|
||
}
|
||
|
||
/* ==========================================================================
|
||
24. 按钮 / 控件视觉体系统一
|
||
--------------------------------------------------------------------------
|
||
_mbtn.mjs 在 27 页上实测 645 个可点控件,改造前的客观问题:
|
||
|
||
· style.css 里**没有 .btn 基类**(`^\s*\.btn\s*\{` 零命中),因此没有尺寸
|
||
基准:.btn-danger 是唯一 10px 20px / 15px 的"大一号"按钮,.btn-search 与
|
||
.pagination-btn 固定 height:32px,.btn-icon-pagination 只有 20x20,
|
||
.settings-custom-select-trigger 同一页存在 32/38/42/48px 四种高度。
|
||
· 类语义被打破:.btn-secondary 一个类出现 **12 种签名**(205 个实例)——
|
||
高度 44/52/71、圆角 6px/8px、字号 13px/14px、横内边距 12/14/16/18px;
|
||
.btn-primary 6 种、.btn-small 4 种。
|
||
· 度量发散:圆角 11 种(0/4/5/6/7/8/10/12/14/999px/50%)、字号 9 种
|
||
(10.56~16px)、字重 7 档(400/500/520/560/600/650/700)。
|
||
· 同一行内尺寸互不相同(39 处容器):mcp-management 分页「上一页/下一页」
|
||
被 style.css:11867 的 `flex:1 + max-width:120px` 压到 53px 宽、中文换行
|
||
撑高成 53x71,而同行「首页/末页」是 44x52;资产库工具条三个按钮的横内边距
|
||
是 16/16/6;工作流工具条的圆角是 7px 与 0px。
|
||
· 手机主导航(底部标签栏)字号 10.56px、角标 9.6px,低于本层 18.2 自己
|
||
定的 12px 下限。
|
||
|
||
本节只做"收敛",不改任何布局结构与配色(配色仍由 18/23 节负责):
|
||
按钮高度 -> 44px(触控下限,也是唯一档)
|
||
圆角 -> 矩形控件 10px / 方形图标按钮 12px / 标签胶囊 999px
|
||
字号 -> 标准 14px、小号与胶囊 13px
|
||
字重 -> 常规 500、主要行动与选中态 600
|
||
横内边距 -> 标准 16px、小号 12px
|
||
分组间距 -> 8px
|
||
|
||
两条刻意不碰:`.btn-compact`(style.css:32833 显式 `min-height:0`,它是侧栏
|
||
分页的紧凑按钮,抬到 44px 会把侧栏撑破)与 `.chat-files-dropdown-item`
|
||
(是左对齐的菜单行,不是按钮,单独定义)。
|
||
========================================================================== */
|
||
@media (max-width: 767.98px) {
|
||
|
||
/* 24.1 基底:所有"按钮化控件"共用同一套度量,取代原先散落在
|
||
20.1 / 20.2 / 20.4 / 20.6 / 20.7 / 20.8 的逐类补丁。
|
||
只设左右内边距,不动上下——保持 style.css 里各族的垂直视觉重心。 */
|
||
:is(.btn-primary, .btn-secondary, .btn-danger, .btn-ghost,
|
||
.btn-small, .btn-sm, .btn-filter, .btn-search,
|
||
.mcp-detail-btn, .btn-delete, .btn-loading,
|
||
.page-header-actions > button, .page-header-actions > a.btn,
|
||
.tools-actions button, .attack-chain-action-btn,
|
||
.attack-chain-filters button, .robot-manager-toolbar button,
|
||
.robot-command-entry button, .asset-batch-menu button,
|
||
.workflow-toolbar-button, .workflow-save-button,
|
||
.m-chat-bar-btn, .chat-session-shortcut, .role-selector-btn,
|
||
.new-chat-btn, .ai-channel-save-btn, .dashboard-empty-action,
|
||
.dashboard-severity-status-filter-btn, .empty-state button,
|
||
.workflow-node-palette button, .c2-sessions-quick-links button,
|
||
.syntax-guide-toggle) {
|
||
min-height: var(--m-ctl-h) !important;
|
||
padding-left: var(--m-ctl-pad-x) !important;
|
||
padding-right: var(--m-ctl-pad-x) !important;
|
||
font-size: var(--m-ctl-fs) !important;
|
||
font-weight: var(--m-ctl-fw) !important;
|
||
border-radius: var(--m-r-btn) !important;
|
||
line-height: 1.25 !important;
|
||
box-sizing: border-box;
|
||
display: inline-flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
}
|
||
|
||
/* 24.2 小号档:横内边距收到 12px,字号 13px(高度仍是 44px 触控下限) */
|
||
:is(.btn-small, .btn-sm, .btn-filter, .btn-search,
|
||
.btn-icon-pagination, .mcp-detail-btn,
|
||
.tools-actions button, .workflow-toolbar-button,
|
||
.workflow-save-button, .m-chat-bar-btn, .chat-session-shortcut,
|
||
.workflow-node-palette button, .c2-sessions-quick-links button,
|
||
.syntax-guide-toggle, .robot-command-entry button) {
|
||
padding-left: var(--m-ctl-pad-x-sm) !important;
|
||
padding-right: var(--m-ctl-pad-x-sm) !important;
|
||
font-size: var(--m-ctl-fs-sm) !important;
|
||
}
|
||
|
||
/* 24.3 图标档:纯图标按钮一律 44x44 正方形,圆角略大于文字按钮,
|
||
让"图标块"与"文字条"在一起时不显单薄。
|
||
(原来 .chat-upload-btn 36x36/圆角 10、.btn-icon-pagination 20x20、
|
||
顶部图标 38x38,三种口径并存) */
|
||
:is(.btn-icon, .btn-icon-pagination, .chat-upload-btn,
|
||
.m-menu-btn, .m-more-btn, .m-close-btn, .projects-list-item-menu,
|
||
#notification-bell-btn, #user-avatar-btn, .header-actions .btn-icon) {
|
||
width: var(--m-ctl-h) !important;
|
||
min-width: var(--m-ctl-h) !important;
|
||
height: var(--m-ctl-h) !important;
|
||
min-height: var(--m-ctl-h) !important;
|
||
padding: 0 !important;
|
||
border-radius: var(--m-r-icon) !important;
|
||
font-size: var(--m-ctl-fs-sm) !important;
|
||
font-weight: var(--m-ctl-fw) !important;
|
||
}
|
||
|
||
:is(.btn-icon, .chat-upload-btn, .m-menu-btn, .m-more-btn, .m-close-btn,
|
||
#notification-bell-btn, #user-avatar-btn) svg {
|
||
width: 20px;
|
||
height: 20px;
|
||
}
|
||
|
||
/* 24.4 行内文字按钮(.btn-link):原来只有 32px 宽、圆角 0、横内边距 6px,
|
||
和旁边 6px 圆角按钮排在一行时基线都不齐。给它按钮的位置感,但保持无底无框。 */
|
||
.btn-link {
|
||
min-width: var(--m-touch) !important;
|
||
min-height: var(--m-ctl-h) !important;
|
||
padding-left: var(--m-ctl-pad-x-sm) !important;
|
||
padding-right: var(--m-ctl-pad-x-sm) !important;
|
||
font-size: var(--m-ctl-fs-sm) !important;
|
||
font-weight: var(--m-ctl-fw) !important;
|
||
border-radius: var(--m-r-btn) !important;
|
||
background: transparent !important;
|
||
box-shadow: none !important;
|
||
}
|
||
|
||
/* 24.5 标签 / 胶囊档:凡是"一组里选一个"的控件统一胶囊形,
|
||
原来 .rbac-tab 是 0 圆角 + 1px 内边距、.projects-tab 是 8px、
|
||
.hitl-page-tab 是 0 圆角、.asset-period-switch 是 11px 字号、
|
||
.c2-tasks-time-preset-btn 是 12px 字号。 */
|
||
:is(.rbac-tab, .projects-tab, .dashboard-feed-tab, .hitl-page-tab,
|
||
.rbac-workspace-tab, .settings-nav-item, .preset-chip,
|
||
.asset-period-switch button, .c2-tasks-time-preset-btn,
|
||
.hitl-reviewer-toggle-btn) {
|
||
min-height: var(--m-ctl-h) !important;
|
||
padding-left: 14px !important;
|
||
padding-right: 14px !important;
|
||
font-size: var(--m-ctl-fs-sm) !important;
|
||
font-weight: var(--m-ctl-fw) !important;
|
||
border-radius: var(--m-r-pill) !important;
|
||
line-height: 1.25 !important;
|
||
white-space: nowrap;
|
||
box-sizing: border-box;
|
||
}
|
||
|
||
:is(.rbac-tab, .projects-tab, .dashboard-feed-tab, .hitl-page-tab,
|
||
.rbac-workspace-tab, .settings-nav-item, .preset-chip,
|
||
.asset-period-switch button, .c2-tasks-time-preset-btn,
|
||
.hitl-reviewer-toggle-btn).is-active,
|
||
:is(.rbac-tab, .projects-tab, .dashboard-feed-tab, .hitl-page-tab,
|
||
.rbac-workspace-tab, .settings-nav-item, .preset-chip,
|
||
.asset-period-switch button, .c2-tasks-time-preset-btn,
|
||
.hitl-reviewer-toggle-btn).active {
|
||
font-weight: var(--m-ctl-fw-strong) !important;
|
||
}
|
||
|
||
/* 分段控件(周期切换)容器跟着胶囊化,3px 内衬保留 */
|
||
.asset-period-switch {
|
||
border-radius: var(--m-r-pill) !important;
|
||
padding: 3px !important;
|
||
gap: 2px !important;
|
||
display: inline-flex !important;
|
||
align-items: center;
|
||
}
|
||
|
||
/* 24.5b rbac-summary-count 是"查看明细 70"的**虚线文字按钮**,style.css 设计为
|
||
border-radius:0 + 虚线底边 + color:secondary。上面把它误纳入胶囊档,被强制
|
||
成全圆角、无背景的怪圈(实测 42×44、border-radius:999px)。排除它并还原
|
||
虚线文字按钮本义,仅给移动端 44px 命中高。 */
|
||
.rbac-summary-count--interactive {
|
||
border-radius: 0 !important;
|
||
background: none !important;
|
||
min-height: var(--m-touch) !important;
|
||
padding: 0 2px 1px !important;
|
||
display: inline-flex !important;
|
||
align-items: flex-end;
|
||
}
|
||
|
||
/* 24.6 下拉触发器:与按钮同高同圆角,但文字左对齐、右端留给箭头。
|
||
原来同一类在资产库有 32/38/42/48px 四种高度、在内距 9/11/12 之间跳动。 */
|
||
:is(.settings-custom-select-trigger, .monitor-filter-select-trigger,
|
||
.projects-filter-select-trigger, .vuln-filter-select-trigger,
|
||
.tasks-filter-select-trigger, .chat-files-filter-select-trigger,
|
||
.c2-form-select-trigger, .asset-custom-select .settings-custom-select-trigger) {
|
||
min-height: var(--m-ctl-h) !important;
|
||
padding-left: var(--m-ctl-pad-x-sm) !important;
|
||
padding-right: var(--m-ctl-pad-x-sm) !important;
|
||
font-size: var(--m-ctl-fs) !important;
|
||
font-weight: var(--m-ctl-fw) !important;
|
||
border-radius: var(--m-r-ctl) !important;
|
||
line-height: 1.25 !important;
|
||
box-sizing: border-box;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
gap: 8px;
|
||
}
|
||
|
||
/* 24.7 分页结构修复
|
||
实测:mcp-management 分页里「上一页/下一页」53x71(中文被挤成两行),
|
||
同行「首页/末页」44x52 —— style.css:11867 在 ≤768px 给
|
||
`.pagination-fixed .pagination-controls .btn-secondary` 设了
|
||
`flex:1; min-width:60px; max-width:120px`,按钮被压窄后文字换行撑高。
|
||
这里取消伸缩、禁止换行、允许整行折行,四个按钮回到同一高度。 */
|
||
:is(.pagination-controls, .pagination-fixed .pagination-controls,
|
||
.pagination) {
|
||
display: flex !important;
|
||
flex-wrap: wrap !important;
|
||
align-items: center !important;
|
||
gap: 6px !important;
|
||
}
|
||
:is(.pagination-controls, .pagination-fixed .pagination-controls) > :is(button, .btn-secondary, .btn-primary) {
|
||
flex: 0 0 auto !important;
|
||
max-width: none !important;
|
||
min-width: var(--m-touch) !important;
|
||
min-height: var(--m-ctl-h) !important;
|
||
padding-left: var(--m-ctl-pad-x-sm) !important;
|
||
padding-right: var(--m-ctl-pad-x-sm) !important;
|
||
font-size: var(--m-ctl-fs-sm) !important;
|
||
border-radius: var(--m-r-ctl) !important;
|
||
white-space: nowrap !important;
|
||
}
|
||
|
||
/* 24.8 分组间距统一:控件成组出现时一律 8px,原来 6/8/10/12/16 混用 */
|
||
:is(.page-header-actions, .tools-actions, .rbac-tabs, .projects-tabs,
|
||
.dashboard-feed-tabs, .attack-chain-filters, .asset-toolbar-main,
|
||
.workflow-toolbar, .workflow-toolbar-group, .workflow-node-palette,
|
||
.chat-composer-context, .chat-composer-footer-leading,
|
||
.c2-tasks-time-presets, .c2-sessions-quick-links, .settings-nav,
|
||
.asset-saved-views, .header-actions, .hitl-reviewer-toggle,
|
||
.syntax-guide-actions, .rbac-summary-permissions, .empty-state) {
|
||
gap: var(--m-ctl-gap) !important;
|
||
}
|
||
|
||
/* 24.9 可点卡片 / 行的圆角归一到卡片档(原为 0/4/8/10/12 五种混用) */
|
||
:is(.dashboard-resource-item, .dashboard-severity-legend-item,
|
||
.dashboard-severity-status-cell, .dashboard-access-stat,
|
||
.dashboard-recommend-item, .tool-guard-rule-summary,
|
||
.rbac-user-row, .stat-card, .dashboard-kpi-card) {
|
||
border-radius: var(--m-radius-card) !important;
|
||
}
|
||
|
||
/* 24.10 层级:主要行动与选中态用 600,其余 500。
|
||
原来同一个界面里并存 400/500/520/560/600/650 六档字重。 */
|
||
:is(.btn-primary, .new-chat-btn, .ai-channel-save-btn,
|
||
.rbac-summary-count, .empty-state button,
|
||
.role-selector-btn.m-primary) {
|
||
font-weight: var(--m-ctl-fw-strong) !important;
|
||
}
|
||
|
||
.chat-input-container .send-btn {
|
||
font-weight: var(--m-ctl-fw-strong) !important;
|
||
}
|
||
|
||
/* 24.11 表单勾选类控件:视觉 24px,命中面 44x44(由整行 label 提供)
|
||
实测结论(_mchk2.mjs,运行时注入对照实验):Chrome 对
|
||
input[type=checkbox]/radio 这类替换元素**不采纳作者的 padding**——连运行时
|
||
注入 `input[type=checkbox]{padding:10px !important}` 都不生效(computed
|
||
padding 恒为 0、外框恒为 24x24)。按 CSS 层叠规范,!important 的优先级是
|
||
反的:UA 的 !important 高于作者的 !important,而 Blink 的 UA 样式表对勾选框
|
||
强制了内衬。所以"把本体撑到 44px"这条路在本平台上不成立(真撑大了视觉上也
|
||
是个巨大方框)。正确做法是:本体保持 24px 视觉,把 44px 命中面交给整行
|
||
label —— 实测该行 68x44,点行内任意位置都能切换。 */
|
||
input[type="checkbox"],
|
||
input[type="radio"] {
|
||
width: 30px !important;
|
||
height: 30px !important;
|
||
min-width: 30px !important;
|
||
min-height: 30px !important;
|
||
/* 仍需 !important:style.css 的 `.auto-refresh-toggle input[type=checkbox]`
|
||
(18871)等后代选择器特异性更高,会把它按回 18px */
|
||
}
|
||
|
||
label:has(> input[type="checkbox"]),
|
||
label:has(> input[type="radio"]) {
|
||
min-height: var(--m-touch);
|
||
display: inline-flex;
|
||
align-items: center;
|
||
gap: 8px;
|
||
}
|
||
|
||
/* 24.12 胶囊标签条:横向滚动,不换行、不裁切
|
||
_mprobe.mjs 实测 `.hitl-page-tabs` 在 320px 视口 clientW=292 / scrollW=371,
|
||
且 overflow-x 是 visible —— 第 4 个页签右边缘 385 > 视口 320,被祖先
|
||
`.page-content{overflow-x:hidden}` 直接切掉,**手指也滑不出来**:一个点不到
|
||
的页签。390px 下也已溢出 9px。这里沿用文件里既有的"横向滚动 + nowrap"惯例
|
||
(见 6.x 终端工具条、19.3 宽表),把溢出交还给标签条自己滚动。
|
||
只列真正单行排布的胶囊条,工作流工具条这类靠换行展示全部的容器不动。 */
|
||
:is(.hitl-page-tabs, .projects-tabs, .dashboard-feed-tabs, .rbac-tabs,
|
||
.rbac-workspace-tabs, .c2-tasks-time-presets) {
|
||
flex-wrap: nowrap !important;
|
||
overflow-x: auto !important;
|
||
overflow-y: hidden !important;
|
||
scrollbar-width: none;
|
||
-webkit-overflow-scrolling: touch;
|
||
overscroll-behavior-x: contain;
|
||
scroll-snap-type: x proximity;
|
||
}
|
||
|
||
:is(.hitl-page-tabs, .projects-tabs, .dashboard-feed-tabs, .rbac-tabs,
|
||
.rbac-workspace-tabs, .c2-tasks-time-presets)::-webkit-scrollbar {
|
||
display: none;
|
||
}
|
||
|
||
/* 条目不许被压扁(否则"横向滚动"会退化成"每个页签都被挤成省略号") */
|
||
:is(.hitl-page-tabs, .projects-tabs, .dashboard-feed-tabs, .rbac-tabs,
|
||
.rbac-workspace-tabs, .c2-tasks-time-presets) > * {
|
||
flex: 0 0 auto !important;
|
||
scroll-snap-align: start;
|
||
}
|
||
|
||
/* 24.13 projects 页残留小字号已并入 18.2 的下限清单(保持单一出处) */
|
||
|
||
/* 24.14 对话页「人工审批:关闭」按钮:文字不再被截断
|
||
实测根因(_mprobe.mjs):按钮被 style.css 的 max-width:142px 钉死,而内衬
|
||
16px 在图标+间距之外只剩 69px 给标签,标签实际需要 84px → 恒显省略号
|
||
(iPhone SE 上只剩 49px)。原 18.7 用"字号缩 1px"绕,属于治标。
|
||
底部这一行总宽 368px,上传键 44 + 发送键 44 之后仍有富余,放宽即可完整显示。 */
|
||
#chat-hitl-shortcut {
|
||
max-width: none !important;
|
||
padding-left: var(--m-ctl-pad-x-sm) !important;
|
||
padding-right: var(--m-ctl-pad-x-sm) !important;
|
||
font-size: var(--m-ctl-fs-sm) !important;
|
||
overflow: hidden !important;
|
||
}
|
||
|
||
/* 24.9 会话快捷按钮的文本由 JS 动态写入(如「Agent 审查:关闭 · OpenAI 协议模型 · qwen3-max」),
|
||
实测比按钮宽 30px+。原来强制 nowrap + visible 会被按钮容器裁掉尾部;
|
||
改为在按钮内收缩,超出显示省略号(回到 style.css:44875 的初衷)。 */
|
||
#chat-hitl-shortcut-text {
|
||
flex: 1 1 auto !important;
|
||
min-width: 0 !important;
|
||
font-size: var(--m-ctl-fs-sm) !important;
|
||
overflow: hidden !important;
|
||
text-overflow: ellipsis !important;
|
||
white-space: nowrap !important;
|
||
text-align: left;
|
||
}
|
||
|
||
/* 24.15 自制开关:**不得**套用 24.11 的原生勾选框尺寸
|
||
(必须排在 24.11 之后,靠层叠接管)
|
||
tool-guard 页「调用拦截」把复选框做成了开关:tool-guard.css:68 定义
|
||
30×18 胶囊轨道 + 12px 圆形滑块(::after,left:2,选中 translateX(12));
|
||
tool-guard.js:205-218 同时还给这个 input 挂了 `.theme-checkbox` 类。
|
||
24.11 是 `input[type=checkbox]{width/height:24px !important}`——特异性
|
||
(0,1,1) 低于 `.tool-guard-page .tool-guard-switch input[type=checkbox]`
|
||
(0,2,1),但一加 !important 就反超,于是:
|
||
· 轨道被压成 24×24 方块(本该是 30×18 的胶囊)
|
||
· 滑块仍是 left2 + 12 + 位移12 = 右缘 26,**越出轨道**
|
||
· 未选中态:24 宽轨道里左侧一个 12px 圆点、右侧空 10px → 坏掉的控件
|
||
这里按原设计还原轨道与滑块,并用更高特异性接管两态位移。 */
|
||
.tool-guard-page .tool-guard-switch input[type="checkbox"] {
|
||
width: 30px !important;
|
||
height: 18px !important;
|
||
min-width: 30px !important;
|
||
min-height: 18px !important;
|
||
border-radius: 999px !important;
|
||
padding: 0 !important;
|
||
position: relative !important;
|
||
}
|
||
|
||
/* 未选中态:滑块归位。transform 必须显式声明,否则会从 24.16 的命中区
|
||
规则里继承 `translate(-50%,-50%)`,把滑块挪到轨道外 */
|
||
.tool-guard-page .tool-guard-switch input[type="checkbox"]::after {
|
||
content: '' !important;
|
||
position: absolute !important;
|
||
top: 2px !important;
|
||
left: 2px !important;
|
||
width: 12px !important;
|
||
height: 12px !important;
|
||
border-radius: 50% !important;
|
||
background: #fff !important;
|
||
transform: none !important;
|
||
}
|
||
|
||
/* 选中态:left2 + 滑块12 + 位移12 = 右缘 26,轨道内宽 28(30 减 1px 边框),
|
||
右侧留 2px —— 与未选中态左侧留 2px 对称 */
|
||
.tool-guard-page .tool-guard-switch input[type="checkbox"]:checked::after {
|
||
transform: translateX(12px) !important;
|
||
}
|
||
|
||
/* 裸开关:label 内只有 input、没有文字时宽度只有 24px,给它 44 命中面。
|
||
`justify-content` 在 auto 宽度下无副作用(内容即容器),所以对带文字的
|
||
「启用调用拦截」那行(104×44)不产生影响。 */
|
||
.tool-guard-page .tool-guard-switch {
|
||
min-height: var(--m-touch);
|
||
min-width: var(--m-touch);
|
||
justify-content: center;
|
||
}
|
||
|
||
/* 24.16 勾选框(.theme-checkbox):等比圆角 + 44px 命中面
|
||
(a) 等比圆角:24.11 把本体放大到 24px,但 `.theme-checkbox` 自己的
|
||
border-radius 是 4px(为默认 16px 设计),24px 下显得方。按钮体系是
|
||
10px/44px ≈ 23%,这里取 6px/24px = 25%——**按尺寸等比**才叫协调。
|
||
(b) 44px 命中面:24.11 的注释写着"命中面交给整行 label",但全站有 22 个
|
||
勾选框并没有可点的 label(mcp-management 工具列表 20 个、
|
||
asset-library 表头全选、info-collect 全选),本体 24×24 在手机上
|
||
很难点中。`.theme-checkbox` 是 appearance:none 的,此时 input 会渲染
|
||
伪元素、**且伪元素参与命中测试**;原生外观下则被 UA 样式表锁死——
|
||
这正是 24.11 里"padding 撑不开"的原因,两者是同一个机制的两面。
|
||
所以用一个透明 44×44 ::after 撑开命中面:不占布局、不改视觉。 */
|
||
.theme-checkbox {
|
||
position: relative !important;
|
||
border-radius: 6px !important;
|
||
}
|
||
|
||
.theme-checkbox::after {
|
||
content: '' !important;
|
||
position: absolute !important;
|
||
top: 50% !important;
|
||
left: 50% !important;
|
||
width: 44px !important;
|
||
height: 44px !important;
|
||
transform: translate(-50%, -50%) !important;
|
||
background: transparent !important;
|
||
}
|
||
|
||
/* 24.17 开关型隐形 input 必须排除在 24.11 之外
|
||
项目里其实有**三套**勾选/开关机制,24.11 只能套第一套:
|
||
1. `.theme-checkbox`(style.css:43032)——真·勾选框,appearance:none、
|
||
可见可点,24.16 已给它等比圆角与 44px 命中面;
|
||
2. `.modern-checkbox` + `.checkbox-custom`(style.css:11011)——开关,
|
||
input 本体是 `position:absolute; opacity:0; width:0; height:0;
|
||
pointer-events:none`,**根本不接收点击**,点击由外层 `.checkbox-label`
|
||
代收,视觉交给兄弟元素 `.checkbox-custom`(44×24 胶囊 + 16px 滑块,
|
||
选中 translateX(20):2+16+20 = 38 ≤ 40,左右各留 2px,设计本身正确);
|
||
3. `.tool-guard-page .tool-guard-switch input`——30×18 开关,见 24.15。
|
||
24.11 给第 2 套的 input 强推 24×24,等于在页面上多出一层 24×24 的隐形盒子
|
||
(因为 pointer-events:none 所以不拦点击,但没有任何存在理由,也会让
|
||
审计脚本把它误判成"点不中的勾选框")。这里恢复它的 0×0。 */
|
||
input.modern-checkbox {
|
||
width: 0 !important;
|
||
height: 0 !important;
|
||
min-width: 0 !important;
|
||
min-height: 0 !important;
|
||
}
|
||
|
||
/* 第 2 套开关的真实点击接收者是 `.checkbox-label`(实测 150×40,差 4px)。
|
||
这才是"点不中"的正确修复点——修 label,而不是修那个不可见的 input。
|
||
必须 !important:info-collect 有一条
|
||
`#info-collect-full-option .checkbox-label{min-height:40px}`(特异性 1,2,0)
|
||
压着这里的 (0,1,0);基础规则那边的 40px 则是 `padding:8px 0` + 24px 内容得来的。 */
|
||
.checkbox-label {
|
||
min-height: var(--m-touch) !important;
|
||
}
|
||
}
|
||
|
||
/* ==========================================================================
|
||
区块 25:审计覆盖被修正后(假 14 页 → 真实 29 页)新暴露的问题收口
|
||
--------------------------------------------------------------------------
|
||
起因:`_mtouch.mjs` / `_mdark.mjs` 的页表里有 6 个并不存在的页面 id,而
|
||
`switchPage()` 对无效 id 是静默 no-op —— 那 6 页一直在重复测上一页,
|
||
于是「14 页全 0」是假覆盖。修好页表(共用 `_pages.mjs` 的 29 个真实 id,
|
||
切换后回读 `.page.active` 断言)再测,下面这些问题才第一次被看见。
|
||
========================================================================== */
|
||
@media (max-width: 767.98px) {
|
||
|
||
/* 25.1 info-collect 表单在手机上仍是 4 列栅格。
|
||
基础规则(style.css:30644)的
|
||
grid-template-columns: minmax(160px,.7fr) 同 ×2
|
||
+ minmax(150px,.45fr) + minmax(280px,1fr)
|
||
最小合计 750px,390px 屏上第 3/4 列被直接推出视口;而
|
||
`@media (max-width:980px)` 里改为单列的那条(style.css:30627)被写在
|
||
**它之后**且特异性同为 (0,1,0) —— 顺序错误让这个覆盖永久失效。
|
||
实测「完整模式」选项 left=390 right=540(vw=390),整块不在屏内。 */
|
||
.info-collect-form-row {
|
||
grid-template-columns: 1fr !important;
|
||
}
|
||
|
||
/* 25.2 mcp-management 统计条用 flex-wrap:nowrap,
|
||
「📌 常驻: 49」right=409、「🔗 已连接: 0」right=468,都越过屏幕右缘。 */
|
||
#tools-stats,
|
||
.external-mcp-stats {
|
||
flex-wrap: wrap !important;
|
||
}
|
||
|
||
/* 25.3 语义色文字:沿用 18.10b 的同一套体系(一个语义一个色,只压亮度、
|
||
冻结色相与饱和度,目标 ≥4.5:1),限定亮色主题。注释里是修复前的实测值。 */
|
||
|
||
/* 中性灰 —— 与 .projects-fact-filter-label 取同值,全站灰标签一色到底 */
|
||
.c2-tasks-stat-label, /* 2.56 on #fff */
|
||
.c2-events-stat-label,
|
||
.c2-tasks-time-preset-btn, /* 2.45 on #f8fafc */
|
||
.c2-events-time-preset-btn {
|
||
color: #5d718c !important;
|
||
}
|
||
|
||
/* 信息蓝 */
|
||
#c2-events-stat-info, /* 3.68 */
|
||
.c2-tasks-time-preset-btn.is-active, /* 3.36 on #eff5fe */
|
||
.c2-events-time-preset-btn.is-active,
|
||
.agent-role-badge--orchestrator, /* 4.36 on #e0edff */
|
||
#rbac-metric-users, /* 4.34 on #e5ecf9,strong 是本体的 id */
|
||
.rbac-metric-users,
|
||
.rbac-metric-users span {
|
||
color: #1557e7 !important;
|
||
}
|
||
|
||
/* 待处理琥珀 */
|
||
#c2-tasks-stat-pending, /* 2.15 */
|
||
#c2-events-stat-warn {
|
||
color: #986206 !important;
|
||
}
|
||
|
||
/* 失败 / 严重 红 */
|
||
#c2-tasks-stat-failed, /* 3.76 */
|
||
#c2-events-stat-critical {
|
||
color: #d81212 !important;
|
||
}
|
||
|
||
/* 成功绿(.monitor-stat-value 是 28.8px 大字号,标准线是 3.0,实测 2.97 差 0.03) */
|
||
#c2-tasks-stat-success, /* 2.54 */
|
||
.monitor-stat-value.is-success {
|
||
color: #167e3c !important;
|
||
}
|
||
|
||
/* 授权橙 */
|
||
#rbac-metric-assignments, /* 3.00 on #f7e9e2,strong 是本体的 id */
|
||
.rbac-metric-assignments,
|
||
.rbac-metric-assignments span {
|
||
color: #ad4109 !important;
|
||
}
|
||
|
||
/* 浅粉底上的危险按钮文字:同属危险语义,但底色 #f6e9ec 比 dashboard 那处的
|
||
#fef8f8 更深,沿用同一个 #d81212 只有 4.42:1,所以按底色单独压暗。 */
|
||
#c2-tasks-batch-delete span, /* 3.84 */
|
||
#c2-events-batch-delete span {
|
||
color: #c22231 !important;
|
||
}
|
||
|
||
/* 25.4 c2 的主行动按钮:c2.css 拿 --c2-accent(#3b82f6)(c2.css:8)当按钮底色,
|
||
白字只有 3.68:1。同一个 #3b82f6 作正文色时已在 18.x 处理过,作按钮底色这条漏了。
|
||
压深到 #2563eb → 5.17:1。
|
||
**必须限定亮色主题**:深色主题下 `--c2-accent` 会变成浅蓝,按钮是"浅底+深字",
|
||
在深色里改背景会直接把文字对比度打下来(实测 3.64:1)。 */
|
||
html:not([data-theme="dark"]) .c2-payload-card .btn-primary,
|
||
html:not([data-theme="dark"]) #c2-build-btn {
|
||
background: #2563eb !important;
|
||
border-color: #2563eb !important;
|
||
}
|
||
|
||
/* 25.5 第九轮第二遍:新暴露页面里剩下的文本类小字也纳入 12px 下限。
|
||
`.tool-expand-icon` 的 ▶(10px)是图标字符、`svg text`(9px)是图表内标注,
|
||
两者属图形元素,不受文本字号下限约束,保持原尺寸。 */
|
||
.skill-card-tags span, /* 11.52px 技能标签 */
|
||
.c2-tasks-field span, /* 11px 筛选字段标题 */
|
||
.c2-events-field span,
|
||
#tools-stats strong, /* 11.2px 工具统计数字 */
|
||
.asset-protocol-empty p, /* 11px「暂无数据」 */
|
||
.asset-recent-badge, /* 10px「7 天」 */
|
||
.asset-recent-caption { /* 11px「占当前资产总量的 0%」 */
|
||
font-size: 12px !important;
|
||
}
|
||
|
||
/* 25.6 iPhone SE(320px 视口)下 info-collect 的结果工具栏被推出屏幕:
|
||
「列 / 导出 CSV / 导出 JSON」right=386 > 320。让它换行而不是溢出。
|
||
(同屏 `span.rbac-context-stat` 的 right=326 也越界 6px,但它的父容器
|
||
尚未定位,属边缘情况,先记录不动。) */
|
||
.info-collect-results-toolbar,
|
||
#fofa-selected-meta {
|
||
flex-wrap: wrap !important;
|
||
}
|
||
|
||
/* 25.6b header 是单行 space-between,左栏 min-width:240px 仍会把工具栏挤出;
|
||
改为上下两行:左栏占满一行,工具栏换到下一行右对齐。 */
|
||
.info-collect-results-header {
|
||
flex-wrap: wrap !important;
|
||
}
|
||
.info-collect-results-header-left {
|
||
min-width: 0 !important;
|
||
flex: 1 1 100% !important;
|
||
}
|
||
|
||
/* 25.6c rbac context 胶囊:max-width:min(25%,360px) 在 320px 下只有 80px,
|
||
两个统计("1个角色·3项授权")放不下,第二个 right=326 越界 6px。
|
||
窄屏放行换行且取消 25% 上限。 */
|
||
.rbac-metric-context {
|
||
max-width: none !important;
|
||
flex-wrap: wrap !important;
|
||
}
|
||
|
||
/* 25.7 输入控件高度兜底:区块 7 的 input/select{min-height:var(--m-touch)}
|
||
特异性 (0,1,1) 不够,被专项规则覆盖成 36/38/40/42px。
|
||
- c2.css `#page-c2-events .c2-events-field .form-control`(1,2,1) 锁 36px
|
||
- knowledge 的 `.knowledge-filters .search-box`(0,2,0) -> 38px
|
||
- rbac 的 `.rbac-search .form-input` -> 40px
|
||
- settings 的 `.form-group input`(settings 页) -> 42px
|
||
这里用 `#page-*` 前缀 + !important 压过,同时保留原 box-sizing/padding。
|
||
(form-control 设 height+min-height 都要改;.search-box input 与裸 input
|
||
走 min-height 即可。) */
|
||
#page-c2-tasks .c2-tasks-field .form-control,
|
||
#page-c2-events .c2-events-field .form-control,
|
||
#page-knowledge-management .knowledge-search-field input,
|
||
#page-platform-rbac .rbac-search .form-input,
|
||
#page-settings .form-group input,
|
||
#page-settings input[type="text"],
|
||
#page-settings input[type="password"],
|
||
#page-settings input[type="url"] {
|
||
height: var(--m-ctl-h) !important;
|
||
min-height: var(--m-ctl-h) !important;
|
||
}
|
||
}
|
||
|
||
/* ==========================================================================
|
||
区块 26:深色主题(html[data-theme="dark"])
|
||
--------------------------------------------------------------------------
|
||
这批违规同样是"审计覆盖修正后才被看见"的:`_mdark.mjs` 的页表此前含 6 个
|
||
不存在的页面 id,14 页里那 6 页一直在重复测上一页,所以"深色 0 违规"是假覆盖。
|
||
|
||
39 处的推荐色用 `_mcontrast.mjs` 的新 OFFLINE 模式离线求出 —— 它刻意复用与
|
||
在页面里跑时**同一份 solveFor()**,避免"离线一套算法、在线一套算法"分叉。
|
||
方向与亮色相反:深色下要**提亮**前景(搜索方向由前景/背景的明暗关系自动决定,
|
||
无须人工指定)。取值同样遵循"一个语义一个色",括号内是修复前的实测比值。
|
||
|
||
两处结论经**像素裁决**(`_mpixel.mjs` + THEME=dark)确认可信:CSS 计算的
|
||
`.mcp-stats-kpi__chip.is-ok` = #166534 与像素真值完全吻合(2.04:1),
|
||
`.role-card-badge.enabled` = #157347 同样吻合(2.43:1)——不是建模误差。
|
||
========================================================================== */
|
||
html[data-theme="dark"] {
|
||
|
||
/* 26.1 【已回滚的误判,留作记录】深色主题下 `.btn-primary` 的常规形态是
|
||
"浅蓝底 #60a5fa + 深墨蓝文字",实测 9.4:1 —— 与亮色主题的"深蓝底 + 白字"
|
||
互为反色,这是**有意设计**(正是 23.1 区块处理过的那套写法)。
|
||
我最初把它误判成"深字压蓝底",统一改成浅色文字,结果把 18 个页面里
|
||
可见的主按钮从 9.4:1 一次性压到 2.21:1 —— `_mdark.mjs` 重测后立刻暴露。
|
||
结论:**不要动 `.btn-primary` 的文字色**。
|
||
|
||
真正有问题的是登录按钮:`#login-overlay .btn-primary.login-submit` 上叠了
|
||
background-image: linear-gradient(135deg,#2563eb,#1d4ed8) 的深蓝渐变,
|
||
把浅蓝底盖掉了,文字仍是深墨蓝 → 实测 1:1 ~ 3.64:1。只修这一处。 */
|
||
#login-overlay .btn-primary,
|
||
#login-overlay .login-submit {
|
||
color: #eceff8 !important;
|
||
}
|
||
|
||
/* 26.2 中性灰 —— 深色下一律提亮到同一色:取各元素解里最亮的一档
|
||
(#848fa0 是"筛选按钮 / #1f2937 底"的解,对更暗的底只会比值更高)。
|
||
`.btn-secondary` 的分页按钮这里必须带上 `*`:按钮自身的文字其实是
|
||
子元素承载的,只改按钮本体会看不到任何变化(实测过)。 */
|
||
.c2-tasks-stat-label, /* 3.49 on #131a27 */
|
||
.c2-events-stat-label,
|
||
.c2-tasks-time-preset-btn, /* 3.75 on #0c1220 */
|
||
.c2-events-time-preset-btn,
|
||
#projects-detail-meta-time, /* 3.72 */
|
||
button.btn-secondary, /* 2.48 */
|
||
button.btn-secondary * {
|
||
color: #8c97a8 !important;
|
||
}
|
||
|
||
/* 26.3 信息蓝 */
|
||
#c2-events-stat-info, /* 2.95 */
|
||
.c2-tasks-time-preset-btn.is-active, /* 2.33 on #1e2d45 */
|
||
.c2-events-time-preset-btn.is-active,
|
||
.agent-role-badge--orchestrator, /* 2.69 */
|
||
.rbac-metric-users,
|
||
.rbac-metric-users span { /* 2.77 */
|
||
color: #6591f1 !important;
|
||
}
|
||
|
||
/* 26.4 紫 */
|
||
.rbac-metric-roles,
|
||
.rbac-metric-roles span { /* 2.90 */
|
||
color: #9c6af1 !important;
|
||
}
|
||
|
||
/* 26.5 绿 —— #24a655 是"启用徽章 / #142f2c 底"的解(对更暗的 chip 底只会更高) */
|
||
#c2-tasks-stat-success, /* 3.39 */
|
||
.mcp-stats-kpi__chip.is-ok, /* 2.04 ← 像素裁决过 */
|
||
.rbac-pill.is-ok, /* 2.27 */
|
||
.role-card-badge.enabled { /* 2.42 ← 像素裁决过 */
|
||
color: #24a655 !important;
|
||
}
|
||
/* dashboard 的「安全」徽章底色更亮(#163a36),需要更亮的绿 */
|
||
#dashboard-severity-risk-level {
|
||
color: #18b351 !important; /* 3.77 */
|
||
}
|
||
|
||
/* 26.6 红 —— #f04a4a 是"失败 chip / #271c2a 底"的解(#ef3e3e 对 #211a29 只有 4.35:1) */
|
||
#c2-tasks-stat-failed, /* 3.33 */
|
||
#c2-events-stat-critical,
|
||
#c2-tasks-batch-delete span, /* 2.86 */
|
||
#c2-events-batch-delete span,
|
||
.btn-secondary.btn-delete, /* 2.73 */
|
||
.mcp-stats-kpi__chip.is-fail { /* 1.97 */
|
||
color: #f25858 !important;
|
||
}
|
||
#dashboard-status-open {
|
||
color: #ef4646 !important; /* 4.45,差 0.05,单独按解取值 */
|
||
}
|
||
|
||
/* 26.7 琥珀 */
|
||
#c2-tasks-stat-pending, /* 3.39 */
|
||
#c2-events-stat-warn {
|
||
color: #b47407 !important;
|
||
}
|
||
|
||
/* 26.8 橙 */
|
||
.rbac-metric-assignments,
|
||
.rbac-metric-assignments span { /* 2.72 */
|
||
color: #e9580c !important;
|
||
}
|
||
|
||
/* 26.9 知识库「未启用」提示(rgb(102,102,102) 在深底上只有 3.28:1) */
|
||
#page-knowledge-management h3 {
|
||
color: #7c7c7c !important;
|
||
}
|
||
|
||
/* 26.10 mcp-management 的「全部」筛选按钮是白字压在浅蓝 #60a5fa 上:
|
||
冻结色相与饱和度后**无解**(白色没有可提亮的余量,求解器原样返回 #ffffff),
|
||
所以只能压深底色。 */
|
||
.btn-filter.active {
|
||
background: #2563eb !important;
|
||
border-color: #2563eb !important;
|
||
}
|
||
|
||
/* 26.11 c2 会话工具栏的文字型按钮:18.12 给的 #1d4ed8 在深底上只有 2.84:1。
|
||
那条规则的特异性是 (1,4,1)——四个 `:not()` 里的类与属性**都要计入**特异性,
|
||
所以这里必须原样带上同一个选择器才压得住(4 个 `:not()` 里的类与属性都要计入特异性)。
|
||
|
||
**踩过的坑**:这条规则原先我写成了 `html[data-theme="dark"][data-theme="dark"] #page-...`,
|
||
而它所在的位置是本文件末尾 `html[data-theme="dark"] { ... }` 块的**内部** ——
|
||
CSS 嵌套会把它解释成 `html[data-theme="dark"] html[data-theme="dark"][data-theme="dark"] #page-...`,
|
||
也就是"`html` 是 `html` 的后代",**结构性永不匹配**。表现为"改了毫无反应",
|
||
而且**连把特异性翻倍都毫无反应**——因为根本没有参与匹配。
|
||
块内规则已经自带 `html[data-theme="dark"]` 前缀,这里反而不能再写。 */
|
||
#page-c2-sessions button:not(.btn-primary):not(.btn-secondary):not(.btn-danger):not([style*="background"]) {
|
||
color: #6591f1 !important;
|
||
}
|
||
|
||
/* 26.12 空状态行动按钮:18.13 给它们铺了实心 #2563eb 底,
|
||
23.1 又按"浅蓝底(#60a5fa)"的假设把文字改成深墨蓝 —— 两轮修复前提不一致,
|
||
结果成了"深蓝底上的深蓝字"(实测 3.64:1)。底色既然固定是 #2563eb,
|
||
深色下文字就必须回转浅色(5.17:1)。前缀由所属的 `html[data-theme="dark"]` 块提供,
|
||
这里**不能**再手写一遍(原因见 26.11 的注释)。 */
|
||
.dashboard-empty-action,
|
||
#page-knowledge-management .empty-state button,
|
||
#page-knowledge-management .empty-state .btn,
|
||
#hitl-pending-count {
|
||
color: #eceff8 !important;
|
||
}
|
||
|
||
/* 26.13 未修项:asset-library 分页的「首页/上一页/下一页/尾页」在首页时是
|
||
`:disabled` 态,取 #475569 浅灰属有意设计 —— WCAG 1.4.3 明确豁免禁用控件,
|
||
不计入对比度要求。`_mdark.mjs` 会照报,属工具侧尚未过滤 `:disabled`。 */
|
||
}
|
||
|
||
/* --------------------------------------------------------------------------
|
||
27. C2 会话管理页移动端布局修正(第十轮)
|
||
实测(390x664 视口,登录 mtester):
|
||
- c2.css:4371 的 @media (max-width:768px) 给 .c2-session-layout 设
|
||
min-height:calc(100vh - 140px) —— 移动端该页可用内容区实测只有 445px 高,
|
||
而 100vh-140px = 524px,硬撑出 81px 垂直溢出 → .page-content 出现滚动条,
|
||
布局底部 B676 伸到 #m-tabbar(顶 T606) 之下 70px,内容被底部标签栏盖住;
|
||
- c2.css:4473 的 @media (max-width:1100px) 在样式表里位于 768px 断点**之后**,
|
||
同特异性下后声明胜 → .c2-session-sidebar-wrap 被卡回 width:280px,
|
||
390px 视口下会话列表只占 72% 宽,右侧直接露出深色背景;
|
||
- 会话主区 .c2-session-main 被 layout 的 auto 高度压到 266px,空态卡片
|
||
底部越界,下端内容被切。
|
||
修复方向:高度交给内容区实际算(flex:1 + min-height:0),侧栏手机占满全宽、
|
||
最高 260px 内部滚动,主区接管剩余空间并内部滚动。只作用于 ≤767.98px。
|
||
-------------------------------------------------------------------------- */
|
||
@media (max-width: 767.98px) {
|
||
#page-c2-sessions .c2-session-layout {
|
||
min-height: 0 !important;
|
||
height: 100% !important;
|
||
max-height: none !important;
|
||
overflow: hidden !important;
|
||
}
|
||
|
||
#page-c2-sessions .c2-session-sidebar-wrap {
|
||
width: 100% !important;
|
||
min-width: 0 !important;
|
||
max-width: none !important;
|
||
max-height: 260px !important;
|
||
flex-shrink: 0 !important;
|
||
border-right: none !important;
|
||
}
|
||
|
||
#page-c2-sessions .c2-session-sidebar,
|
||
#page-c2-sessions #c2-session-list {
|
||
overflow-y: auto !important;
|
||
min-height: 0 !important;
|
||
-webkit-overflow-scrolling: touch;
|
||
overscroll-behavior: contain;
|
||
}
|
||
|
||
#page-c2-sessions .c2-session-main {
|
||
flex: 1 1 auto !important;
|
||
min-height: 0 !important;
|
||
overflow-y: auto !important;
|
||
-webkit-overflow-scrolling: touch;
|
||
overscroll-behavior: contain;
|
||
padding: 12px 14px 18px !important;
|
||
}
|
||
}
|
||
|
||
/* --------------------------------------------------------------------------
|
||
25. iOS 观感修订:材质 / 圆角 / 按压反馈
|
||
--------------------------------------------------------------------------
|
||
口径:
|
||
- 材质一律用 color-mix 从主题自己的 --bg-primary / --border-color 派生,
|
||
浅色与暗色自动跟随;写死 rgba 会在暗色下糊成一块白雾。
|
||
- backdrop-filter 只在浏览器支持时启用,不支持就退回实心背景(观感一致,
|
||
只是没有透出)。固定栏的模糊是软件渲染掉帧主因(见 5 节),所以全站只给
|
||
顶栏与底栏各一层 blur(20px),抽屉/面板用不透明材质不再加模糊。
|
||
- 圆角收成一个阶梯:控件胶囊、图标按钮正圆、卡片 18、面板顶角 22。
|
||
本层原有的 10/12/14/18 四种混用在手机上读起来是"没对齐",不是"设计过"。
|
||
- 按压反馈用 scale,且在 prefers-reduced-motion 下整体关掉。
|
||
- 所有改动只碰观感:44px 触控下限、层级、滚动容器一概不动。
|
||
-------------------------------------------------------------------------- */
|
||
:root {
|
||
--m-r-card: 18px;
|
||
--m-r-panel: 22px;
|
||
--m-material: color-mix(in srgb, var(--bg-primary) 82%, transparent);
|
||
--m-material-solid: color-mix(in srgb, var(--bg-primary) 96%, transparent);
|
||
--m-hairline: color-mix(in srgb, var(--border-color) 55%, transparent);
|
||
--m-fill-quaternary: color-mix(in srgb, var(--text-primary) 6%, transparent);
|
||
--m-fill-press: color-mix(in srgb, var(--text-primary) 10%, transparent);
|
||
--m-ring: color-mix(in srgb, var(--accent-color) 30%, transparent);
|
||
--m-shadow-panel: 0 -12px 40px rgba(0, 0, 0, 0.22);
|
||
--m-shadow-card: 0 1px 2px rgba(0, 0, 0, 0.04);
|
||
}
|
||
|
||
@media (max-width: 767.98px) {
|
||
/* 25.1 顶栏 / 底栏:透出材质 + 发丝分隔线。
|
||
顶栏必须写成 html[data-theme] header:style.css 用同一条特异性给暗色塞了
|
||
不透明渐变,只写 header 会在暗色下丢掉材质(实测 background 被压成渐变)。 */
|
||
header,
|
||
html[data-theme] header {
|
||
background: var(--m-material-solid);
|
||
border-bottom: 1px solid var(--m-hairline);
|
||
box-shadow: none;
|
||
}
|
||
|
||
#m-tabbar {
|
||
background: var(--m-material-solid);
|
||
border-top: 1px solid var(--m-hairline);
|
||
box-shadow: none;
|
||
}
|
||
|
||
@supports ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
|
||
header,
|
||
html[data-theme] header {
|
||
background: var(--m-material);
|
||
-webkit-backdrop-filter: saturate(180%) blur(20px);
|
||
backdrop-filter: saturate(180%) blur(20px);
|
||
}
|
||
|
||
#m-tabbar {
|
||
background: var(--m-material);
|
||
-webkit-backdrop-filter: saturate(180%) blur(20px);
|
||
backdrop-filter: saturate(180%) blur(20px);
|
||
}
|
||
}
|
||
|
||
/* 25.2 圆角阶梯:卡片、面板、控件、图标按钮 */
|
||
.card,
|
||
.stat-card,
|
||
.metric-card,
|
||
.dashboard-card,
|
||
.panel,
|
||
.settings-section,
|
||
.info-card {
|
||
border-radius: var(--m-r-card);
|
||
box-shadow: var(--m-shadow-card);
|
||
}
|
||
|
||
#m-sheet {
|
||
border-radius: var(--m-r-panel) var(--m-r-panel) 0 0;
|
||
box-shadow: var(--m-shadow-panel);
|
||
}
|
||
|
||
.main-sidebar {
|
||
border-radius: 0 var(--m-r-panel) var(--m-r-panel) 0;
|
||
border-right: none;
|
||
}
|
||
|
||
input:not([type=checkbox]):not([type=radio]),
|
||
select,
|
||
textarea {
|
||
border-radius: 12px;
|
||
}
|
||
|
||
button,
|
||
.btn-primary,
|
||
.btn-secondary,
|
||
.btn-danger,
|
||
.btn-small,
|
||
.btn-sm,
|
||
.m-chat-bar-btn {
|
||
border-radius: var(--m-r-pill);
|
||
}
|
||
|
||
/* 图标按钮去底去框:桌面用的是 .header-actions button(类+元素)两条特异性,
|
||
本层只写类名会被压住(实测 border 仍是 1px),所以这里必须同形写 */
|
||
.header-actions :is(.m-more-btn, .m-close-btn, .notification-btn, .user-avatar-btn, .btn-icon),
|
||
.m-menu-btn {
|
||
border: none;
|
||
background: transparent;
|
||
}
|
||
|
||
/* 次要按钮:iOS 的"填充"样式,去掉描边不再和主按钮抢层次 */
|
||
.btn-secondary,
|
||
.btn-small,
|
||
.btn-sm {
|
||
background: var(--m-fill-quaternary);
|
||
border-color: transparent;
|
||
}
|
||
|
||
/* 25.3 发丝线:抽屉 / 面板 / 会话条的内部分隔 */
|
||
.m-drawer-head,
|
||
.m-drawer-search,
|
||
.m-sheet-head,
|
||
.m-chat-bar {
|
||
border-bottom-color: var(--m-hairline);
|
||
}
|
||
|
||
.m-sheet-sep {
|
||
background: var(--m-hairline);
|
||
}
|
||
|
||
.m-sheet-grip {
|
||
width: 36px;
|
||
height: 5px;
|
||
border-radius: 999px;
|
||
background: color-mix(in srgb, var(--text-muted) 45%, transparent);
|
||
}
|
||
|
||
/* 25.4 按压反馈:可见的"点到了",不改变布局尺寸 */
|
||
.m-tab,
|
||
.m-sheet-item,
|
||
.m-chat-bar-btn,
|
||
.m-menu-btn,
|
||
.m-more-btn,
|
||
.m-close-btn,
|
||
.notification-btn,
|
||
.user-avatar-btn,
|
||
.btn-primary,
|
||
.btn-secondary,
|
||
.btn-danger,
|
||
.btn-small,
|
||
.nav-item-content,
|
||
.nav-submenu-item {
|
||
transition: transform 0.12s ease, background-color 0.12s ease, color 0.16s ease, opacity 0.12s ease;
|
||
}
|
||
|
||
.m-tab:active,
|
||
.m-sheet-item:active,
|
||
.m-chat-bar-btn:active,
|
||
.btn-primary:active,
|
||
.btn-secondary:active,
|
||
.btn-danger:active,
|
||
.btn-small:active {
|
||
transform: scale(0.96);
|
||
background-color: var(--m-fill-press);
|
||
}
|
||
|
||
.btn-primary:active {
|
||
/* 主按钮按压时保持强调色,只压暗,不变成灰底 */
|
||
background-color: color-mix(in srgb, var(--accent-color) 88%, #000);
|
||
}
|
||
|
||
/* 当前标签:图标后面一枚圆形底色,比整格变色更接近系统底栏 */
|
||
.m-tab.m-active {
|
||
color: var(--accent-color);
|
||
background: transparent;
|
||
}
|
||
|
||
.m-tab.m-active svg {
|
||
background: color-mix(in srgb, var(--accent-color) 12%, transparent);
|
||
border-radius: 50%;
|
||
padding: 2px;
|
||
box-sizing: content-box;
|
||
}
|
||
|
||
/* 25.5 焦点环:从 2px 硬描边换成 3px 柔光环,键盘可达性不降级 */
|
||
a:focus-visible,
|
||
button:focus-visible,
|
||
input:focus-visible,
|
||
select:focus-visible,
|
||
textarea:focus-visible,
|
||
[tabindex]:focus-visible {
|
||
outline: none;
|
||
box-shadow: 0 0 0 3px var(--m-ring);
|
||
}
|
||
|
||
.m-drawer-search input:focus {
|
||
border-color: color-mix(in srgb, var(--accent-color) 55%, transparent);
|
||
}
|
||
|
||
/* 强制高对比下柔光环会被抹掉,这里把硬描边还给它 */
|
||
@media (forced-colors: active) {
|
||
a:focus-visible,
|
||
button:focus-visible,
|
||
input:focus-visible,
|
||
select:focus-visible,
|
||
textarea:focus-visible,
|
||
[tabindex]:focus-visible {
|
||
outline: 2px solid Highlight;
|
||
outline-offset: 2px;
|
||
}
|
||
}
|
||
|
||
/* 工具条里的 <a> 按钮(查看全部 / 拉取模型列表 / 视觉测试):它们是操作控件而不是
|
||
正文链接,桌面写成 21-29px 高的行内块,手指点不中。给到本层的触控下限,
|
||
字号与颜色不动。正文里的链接(.markdown-body 内)不在这些容器里,不受影响。 */
|
||
:is(.page-header-actions, .dashboard-section-actions, .dashboard-section-header,
|
||
.model-pick-row, .asset-toolbar, .settings-toolbar, .settings-form,
|
||
.form-group, .info-collect-toolbar, .settings-advanced-block > div)
|
||
a:not(.btn-primary):not(.btn-secondary):not(.btn-danger) {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
min-height: var(--m-touch);
|
||
padding: 0 8px;
|
||
box-sizing: border-box;
|
||
}
|
||
|
||
/* 会话抽屉:本层把它做成全屏抽屉,里面的行就必须按 44 触控口径来
|
||
(实测搜索框 42、分组按钮 24 宽、项目行 38、"最近对话"折叠头 30) */
|
||
:is(#conversation-sidebar .conversation-search-box input,
|
||
#conversation-sidebar .add-group-btn,
|
||
#conversation-sidebar .project-folder-item,
|
||
#conversation-sidebar .recent-conversations-toggle,
|
||
#conversation-sidebar .project-folder-header) {
|
||
min-height: var(--m-touch);
|
||
}
|
||
|
||
#conversation-sidebar .add-group-btn {
|
||
min-width: var(--m-touch);
|
||
}
|
||
|
||
/* 调用拦截的开关:input 是 30x18 的滑块,命中区其实是包着它的 label。
|
||
把 label 撑到触控下限,手指点的就是整块开关而不是那条 18px 的芯。 */
|
||
.tool-guard-toggle {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
min-width: var(--m-touch);
|
||
min-height: var(--m-touch);
|
||
}
|
||
|
||
/* RBAC 概览里的计数胶囊:20px 宽点不中,补足到下限(文字居中,不改视觉密度) */
|
||
.rbac-summary-count {
|
||
min-width: var(--m-touch);
|
||
}
|
||
|
||
/* 桌面把 .ai-channel-manager 设成 overflow:hidden(style.css:4796,靠固定高度自截),
|
||
手机上它的内容比盒子高,超出的一截被裁掉——实测 4 个通道选择按钮 scrollIntoView
|
||
也拉不进视口,属于「看得见点不到」。这里交还给页面滚动容器。 */
|
||
.ai-channel-manager {
|
||
overflow: visible;
|
||
}
|
||
|
||
/* 25.6 遮罩与轻提示:遮罩不加模糊(全屏模糊是掉帧主因),提示条用材质 */
|
||
.m-scrim {
|
||
background: color-mix(in srgb, var(--m-scrim) 88%, transparent);
|
||
}
|
||
|
||
/* 提示条保持基底的深色 HUD 胶囊(1023 行):这里曾把它改成浅色材质,
|
||
但字色仍是 #fff,结果白底白字——用户看到的就是"屏幕中间一块白的"。
|
||
只补一层投影,底色与字色不动。 */
|
||
#m-toast {
|
||
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.18);
|
||
}
|
||
}
|
||
|
||
@media (max-width: 767.98px) and (prefers-reduced-motion: reduce) {
|
||
/* 关掉按压缩放,只保留颜色反馈 */
|
||
.m-tab,
|
||
.m-sheet-item,
|
||
.m-chat-bar-btn,
|
||
.btn-primary,
|
||
.btn-secondary,
|
||
.btn-danger,
|
||
.btn-small {
|
||
transition: background-color 0.12s ease, color 0.16s ease;
|
||
}
|
||
|
||
.m-tab:active,
|
||
.m-sheet-item:active,
|
||
.m-chat-bar-btn:active,
|
||
.btn-primary:active,
|
||
.btn-secondary:active,
|
||
.btn-danger:active,
|
||
.btn-small:active {
|
||
transform: none;
|
||
}
|
||
}
|
||
|
||
@supports (height: 100dvh) {
|
||
:root {
|
||
--m-bar-bottom: max(0px, calc(100dvh - var(--m-app-height, 100dvh)));
|
||
}
|
||
}
|
||
|
||
/* --------------------------------------------------------------------------
|
||
26. 密度与表面:对齐 new-api 的卡片体系 + iOS 的分组列表与填充式表单
|
||
--------------------------------------------------------------------------
|
||
这一节只管"看起来挤不挤、齐不齐",不改配色语言:KPI 卡那套按 nth-child 分的
|
||
淡彩渐变是产品自己的身份(style.css:23789-23793),不跟它抢。
|
||
-------------------------------------------------------------------------- */
|
||
@media (max-width: 767.98px) {
|
||
/* 26.1 KPI:桌面在 ≤480px 把 5 张卡拍成一列 116px 高的长条,手机上要滚
|
||
两屏才看完四个数字。改成两列紧凑网格,数字才是主角。 */
|
||
.dashboard-kpi-row {
|
||
grid-template-columns: repeat(2, minmax(0, 1fr)) !important;
|
||
gap: 10px;
|
||
margin-bottom: 16px;
|
||
}
|
||
|
||
/* 奇数张时末卡通栏,右下角不留空洞 */
|
||
.dashboard-kpi-row > .dashboard-kpi-card:last-child:nth-child(odd) {
|
||
grid-column: 1 / -1;
|
||
}
|
||
|
||
.dashboard-kpi-card {
|
||
padding: 12px 13px !important;
|
||
min-height: 0 !important;
|
||
gap: 0 !important;
|
||
}
|
||
|
||
.dashboard-kpi-label {
|
||
font-size: 12px;
|
||
line-height: 1.35;
|
||
font-weight: 500;
|
||
color: var(--text-muted);
|
||
}
|
||
|
||
.dashboard-kpi-value {
|
||
font-size: 26px;
|
||
line-height: 1.15;
|
||
font-weight: 600;
|
||
letter-spacing: -0.02em;
|
||
font-variant-numeric: tabular-nums;
|
||
margin-top: 6px;
|
||
}
|
||
|
||
.dashboard-kpi-sub,
|
||
.dashboard-kpi-sub-text {
|
||
font-size: 12px;
|
||
line-height: 1.4;
|
||
}
|
||
|
||
.dashboard-kpi-icon {
|
||
width: 28px;
|
||
height: 28px;
|
||
border-radius: 9px;
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
.dashboard-kpi-icon svg {
|
||
width: 15px;
|
||
height: 15px;
|
||
}
|
||
|
||
.dashboard-access-strip {
|
||
grid-template-columns: repeat(2, minmax(0, 1fr)) !important;
|
||
gap: 10px;
|
||
}
|
||
|
||
/* 26.2 卡片表面统一:发丝边 + 16 圆角 + 几乎看不见的投影。
|
||
桌面的 0 2px 8px 双层阴影在小屏上会把每张卡都"抬起来",一屏四张就散了。 */
|
||
:is(.card, .stat-card, .metric-card, .dashboard-card, .panel,
|
||
.settings-section, .info-card) {
|
||
border: 1px solid var(--m-hairline);
|
||
border-radius: var(--m-r-card);
|
||
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.03);
|
||
}
|
||
|
||
/* 26.3 页面头:标题与操作行收成一组,不再各占一段空白 */
|
||
.page-header h2,
|
||
.page-header h1 {
|
||
font-size: 20px;
|
||
font-weight: 600;
|
||
letter-spacing: -0.01em;
|
||
}
|
||
|
||
.page-header {
|
||
gap: 8px;
|
||
margin-bottom: 12px;
|
||
}
|
||
|
||
/* 26.4 填充式表单(iOS 的写法:字段靠底色区分,不靠一圈灰边框) */
|
||
:is(.form-group, .settings-form, .modal-body, .m-drawer-search) :is(input, select, textarea) {
|
||
background: var(--m-fill-quaternary);
|
||
border-color: transparent;
|
||
border-radius: 12px;
|
||
}
|
||
|
||
/* 聚焦:只留一圈柔光环。再改 border 颜色会与 25.5 的环叠成两圈(登录框实测如此)*/
|
||
:is(.form-group, .settings-form, .modal-body, .m-drawer-search) :is(input, select, textarea):focus {
|
||
background: var(--bg-primary);
|
||
border-color: transparent;
|
||
box-shadow: 0 0 0 3px var(--m-ring);
|
||
}
|
||
|
||
/* 26.5 登录卡:满宽卡片 + 填充式字段 + 胶囊主按钮 */
|
||
.login-card {
|
||
border-radius: 20px;
|
||
box-shadow: 0 18px 40px rgba(0, 0, 0, 0.12);
|
||
}
|
||
|
||
.login-form .btn-primary,
|
||
.login-card .btn-primary {
|
||
width: 100%;
|
||
border-radius: var(--m-r-pill);
|
||
}
|
||
|
||
/* 26.6 分组列表:卡片内的行之间只留发丝线,行高按触控下限走 */
|
||
:is(.settings-section, .card, .panel, .info-card) :is(.form-group, .settings-row, .list-row) + :is(.form-group, .settings-row, .list-row) {
|
||
border-top: 1px solid var(--m-hairline);
|
||
}
|
||
}
|
||
|
||
/* --------------------------------------------------------------------------
|
||
28. 玻璃质感:环境光画布 + 玻璃表面 + 顶缘高光
|
||
--------------------------------------------------------------------------
|
||
目标:把手机端从"平面灰底 + 分隔线"推进到 Apple 的玻璃材质语言。
|
||
玻璃要读得出来,前提是材料后面有东西可透,所以这一节先做两件事:
|
||
|
||
- 画布:.container 铺一层极淡的环境光(浅色 = 近白底 + 右上 accent / 左下紫的
|
||
柔光;暗色 = 深底 + 同色更亮的柔光),再把 .content-area / .chat-messages 的
|
||
实心底色交还给这层画布。此后所有半透明表面都有色可透,各页面自身的内容背景
|
||
一律不动。
|
||
- 表面分三档:模糊(backdrop-filter)只给"小面积或瞬时"的件 —— 顶栏、底栏
|
||
(25 节已有)、底部面板、抽屉、登录卡、弹窗;它们要么面积小,要么只在被打开
|
||
时才绘制,不挂在常驻滚动内容上。常驻卡片(.card/.stat-card/... 一列)只做
|
||
半透明 + 发丝边 + 顶缘高光,不挂模糊 —— 固定栏的大面积模糊是移动端掉帧
|
||
主因(25 节实测),这条口径不动。
|
||
- 浅色与暗色全部经 color-mix 从主题令牌派生;只有"顶缘高光"必须换向
|
||
(浅色 = 白线,暗色 = 极淡白线),单独覆写。
|
||
- prefers-reduced-transparency: reduce 时不问浏览器支持与否,全部退回实心。
|
||
-------------------------------------------------------------------------- */
|
||
@media (max-width: 767.98px) {
|
||
:root {
|
||
/* 栏体材质从 82% 提到 62%:有模糊托底,透出的是画布而不是一块灰板 */
|
||
--m-material: color-mix(in srgb, var(--bg-primary) 62%, transparent);
|
||
/* 玻璃卡(常驻,不挂模糊):透出画布的一点色 */
|
||
--m-glass-card: color-mix(in srgb, var(--card-bg) 66%, transparent);
|
||
/* 玻璃面板(瞬时件,配模糊):抽屉 / 底部面板 / 登录卡 / 弹窗 */
|
||
--m-glass-panel: color-mix(in srgb, var(--bg-primary) 72%, transparent);
|
||
--m-glass-blur: saturate(180%) blur(20px);
|
||
/* 顶缘高光:玻璃的"口沿"。浅色下是白线,暗色下换极淡白(见下方覆写) */
|
||
--m-bevel: inset 0 1px 0 rgba(255, 255, 255, 0.55);
|
||
}
|
||
|
||
html[data-theme="dark"] {
|
||
--m-bevel: inset 0 1px 0 rgba(255, 255, 255, 0.07);
|
||
}
|
||
|
||
/* 28.1 环境光画布:整块 app 换底,卡片与栏体从这层透色 */
|
||
.container {
|
||
background:
|
||
radial-gradient(120% 88% at 88% -12%,
|
||
color-mix(in srgb, var(--accent-color) 14%, transparent), transparent 58%),
|
||
radial-gradient(95% 72% at -12% 106%,
|
||
color-mix(in srgb, #8b5cf6 11%, transparent), transparent 60%),
|
||
var(--bg-secondary);
|
||
}
|
||
|
||
html[data-theme="dark"] .container {
|
||
background:
|
||
radial-gradient(120% 88% at 88% -12%,
|
||
color-mix(in srgb, var(--accent-color) 18%, transparent), transparent 58%),
|
||
radial-gradient(95% 72% at -12% 106%,
|
||
color-mix(in srgb, #8b5cf6 13%, transparent), transparent 60%),
|
||
var(--bg-secondary);
|
||
}
|
||
|
||
/* 交还底色:画布负责"底",卡片负责"面" */
|
||
.content-area,
|
||
.chat-messages {
|
||
background: transparent;
|
||
}
|
||
|
||
/* 28.2 底栏补一道顶缘高光,顶栏保持 25 节的发丝线 */
|
||
#m-tabbar {
|
||
border-top-color: var(--m-hairline);
|
||
box-shadow: var(--m-bevel);
|
||
}
|
||
|
||
/* 28.3 卡片玻璃:半透明表面 + 发丝边 + 顶缘高光;投影保持 26 节的"几乎看不见" */
|
||
:is(.card, .stat-card, .metric-card, .dashboard-card, .panel,
|
||
.settings-section, .info-card) {
|
||
background: var(--m-glass-card);
|
||
border-color: var(--m-hairline);
|
||
box-shadow: var(--m-bevel), 0 1px 2px rgba(0, 0, 0, 0.03);
|
||
}
|
||
|
||
/* 28.4 底部面板:真玻璃(透色 + 模糊),只在打开时绘制 */
|
||
#m-sheet {
|
||
background: var(--m-glass-panel);
|
||
border-color: color-mix(in srgb, var(--border-color) 50%, transparent);
|
||
box-shadow: var(--m-bevel), var(--m-shadow-panel);
|
||
}
|
||
|
||
/* 28.5 抽屉(主导航 / 会话列表):同面板材质的真玻璃。
|
||
两套选择器:不带属性的管浅色与初始绘制,html[data-theme] 的管暗色
|
||
(style.css 的暗色抽屉是 (0,2,0) 特异性的不透明渐变,必须同形压回)。 */
|
||
.main-sidebar,
|
||
.conversation-sidebar,
|
||
html[data-theme] .main-sidebar,
|
||
html[data-theme] .conversation-sidebar {
|
||
background: var(--m-glass-panel);
|
||
}
|
||
|
||
.m-chat-drawer-head {
|
||
background: transparent;
|
||
}
|
||
|
||
.m-drawer-search input {
|
||
background: color-mix(in srgb, var(--input-bg) 78%, transparent);
|
||
}
|
||
|
||
/* 对话页顶部工具条:在流内、滚动内容不会跑到它后面,纯透色不挂模糊 */
|
||
#m-chat-bar {
|
||
background: color-mix(in srgb, var(--bg-primary) 66%, transparent);
|
||
border-bottom-color: var(--m-hairline);
|
||
}
|
||
|
||
/* 28.6 弹窗:与面板同档的玻璃 */
|
||
.modal-content {
|
||
background-color: var(--m-glass-panel);
|
||
border: 1px solid var(--m-hairline);
|
||
}
|
||
|
||
/* 28.7 登录:遮罩本身得先有"画布"(否则卡片后面只有一块灰),卡片是真玻璃 */
|
||
.login-overlay {
|
||
background:
|
||
radial-gradient(120% 88% at 85% -10%,
|
||
color-mix(in srgb, var(--accent-color) 13%, transparent), transparent 60%),
|
||
radial-gradient(95% 72% at -12% 108%,
|
||
color-mix(in srgb, #8b5cf6 10%, transparent), transparent 62%),
|
||
color-mix(in srgb, var(--bg-secondary) 92%, transparent);
|
||
}
|
||
|
||
html[data-theme="dark"] .login-overlay {
|
||
background:
|
||
radial-gradient(120% 88% at 85% -10%,
|
||
color-mix(in srgb, var(--accent-color) 17%, transparent), transparent 60%),
|
||
radial-gradient(95% 72% at -12% 108%,
|
||
color-mix(in srgb, #8b5cf6 12%, transparent), transparent 62%),
|
||
color-mix(in srgb, #0b1120 92%, transparent);
|
||
}
|
||
|
||
.login-card {
|
||
background: var(--m-glass-panel);
|
||
border-color: var(--m-hairline);
|
||
box-shadow: var(--m-bevel), 0 18px 44px rgba(0, 0, 0, 0.14);
|
||
}
|
||
|
||
/* 28.8 模糊:只给上述瞬时件。@supports 兜底逻辑与 25 节一致 */
|
||
@supports ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
|
||
#m-sheet,
|
||
html[data-theme] .main-sidebar,
|
||
html[data-theme] .conversation-sidebar,
|
||
.login-card,
|
||
.modal-content {
|
||
-webkit-backdrop-filter: var(--m-glass-blur);
|
||
backdrop-filter: var(--m-glass-blur);
|
||
}
|
||
}
|
||
|
||
/* 28.9 降低透明度环境:退回实心材质(含画布) */
|
||
@media (prefers-reduced-transparency: reduce) {
|
||
.container,
|
||
.content-area,
|
||
.chat-messages,
|
||
.login-overlay {
|
||
background: var(--bg-secondary);
|
||
}
|
||
|
||
#m-sheet {
|
||
background: var(--bg-primary);
|
||
}
|
||
|
||
.main-sidebar,
|
||
.conversation-sidebar,
|
||
html[data-theme] .main-sidebar,
|
||
html[data-theme] .conversation-sidebar,
|
||
.login-card,
|
||
.modal-content {
|
||
background: var(--bg-primary);
|
||
}
|
||
|
||
#m-chat-bar {
|
||
background: var(--bg-primary);
|
||
}
|
||
|
||
:is(.card, .stat-card, .metric-card, .dashboard-card, .panel,
|
||
.settings-section, .info-card) {
|
||
background: var(--card-bg);
|
||
}
|
||
|
||
#m-sheet,
|
||
html[data-theme] .main-sidebar,
|
||
html[data-theme] .conversation-sidebar,
|
||
.login-card,
|
||
.modal-content {
|
||
-webkit-backdrop-filter: none;
|
||
backdrop-filter: none;
|
||
}
|
||
}
|
||
}
|