Files
OnebotCatalog/web/style.css
wangruiguo f343b26444 v2.4: 网页版适配 Odoo 网站嵌入
- URL 深度链接:?series= 打开系列 / ?model= 定位型号 / ?embed=1 隐藏自身顶栏 / ?nav=0 隐藏侧边栏 / ?lang= 切语言
- 路径自适应:VIEWER_BASE 与模型路径从 location.pathname 推导,支持子路径部署(原来硬编码 /viewer/ 和 /step/ 会在子路径下 404)
- embed 模式样式:隐藏 header/footer,让 iframe 内更干净
- 手册页图片点击放大:全屏弹窗,← → 翻页,Esc/点遮罩关闭
- 数据表 PDF 弹窗预览:原为直接下载,改为内联预览(弹窗内保留下载入口)
- 数据表按钮加内联 SVG 图标(PDF + 放大镜),区别于纯下载按钮
- 隐藏「返回系列总览」按钮(嵌入模式下属多余)

注:本次改动服务于 OneBot 官网产品页的选型 tab 嵌入。

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-17 02:57:34 +08:00

773 lines
32 KiB
CSS
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/* 欧霓博在线目录 - 现代柔和卡片风
* 视觉参照 bom-viewer (D:\开发\bom-viewer):青/teal 主色 + 大圆角 + 柔和阴影 + 玻璃顶栏。
* 保留既有类名 (tree/params/content/tab/split/cart/...) 以免破坏 app.js 引用,仅重新配色。
*/
/* ------------------------------------------------------------ 设计令牌 */
:root {
--primary-50: #f0fdfa;
--primary-100: #ccfbf1;
--primary-200: #99f6e4;
--primary-300: #5eead4;
--primary-400: #2dd4bf;
--primary-500: #14b8a6;
--primary-600: #0d9488;
--primary-700: #0f766e;
--primary-800: #115e59;
--primary-900: #134e4a;
--gray-50: #f9fafb;
--gray-100: #f3f4f6;
--gray-200: #e5e7eb;
--gray-300: #d1d5db;
--gray-400: #9ca3af;
--gray-500: #6b7280;
--gray-600: #4b5563;
--gray-700: #374151;
--gray-800: #1f2937;
--gray-900: #111827;
--surface: #ffffff;
--bg: var(--gray-50);
--border: var(--gray-200);
--border-soft: var(--gray-100);
--text: var(--gray-900);
--text-dim: var(--gray-500);
--text-faint: var(--gray-400);
--shadow-card: 0 1px 3px rgba(0,0,0,.04), 0 1px 2px rgba(0,0,0,.06);
--shadow-hover: 0 10px 40px rgba(0,0,0,.08);
--shadow-glass: 0 8px 32px rgba(0,0,0,.06);
--shadow-btn: 0 4px 12px rgba(20,184,166,.25);
--radius: 16px;
--radius-sm: 10px;
--radius-xs: 8px;
}
* { box-sizing: border-box; margin: 0; padding: 0; }
body {
font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI",
Roboto, "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", sans-serif;
display: flex; flex-direction: column; height: 100vh;
font-size: 13px; color: var(--text); background: var(--bg);
-webkit-font-smoothing: antialiased;
}
/* 纤细滚动条,悬停才显形 */
::-webkit-scrollbar { width: 8px; height: 8px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb { background: transparent; border-radius: 999px; transition: background .2s; }
*:hover::-webkit-scrollbar-thumb { background: rgba(156,163,175,.5); }
*:hover::-webkit-scrollbar-thumb:hover { background: rgba(107,114,128,.7); }
::selection { background: rgba(20,184,166,.2); }
/* ------------------------------------------------------------ 顶栏(玻璃) */
header {
height: 58px; display: flex; justify-content: space-between; align-items: center;
gap: 14px; padding: 0 18px;
background: rgba(255,255,255,.8);
backdrop-filter: blur(20px); -webkit-backdrop-filter: blur(20px);
border-bottom: 1px solid var(--border-soft);
box-shadow: var(--shadow-glass);
position: relative; z-index: 20;
}
.brand {
font-size: 15px; font-weight: 700; white-space: nowrap;
color: var(--gray-900); letter-spacing: -.2px;
display: flex; align-items: center;
}
.brand .logo { height: 26px; margin-right: 9px; }
.brand-en { font-weight: 500; font-size: 12px; color: var(--text-dim); margin-left: 7px; }
.ver {
font-weight: 500; margin-left: 8px; font-size: 10.5px;
font-family: ui-monospace, Consolas, monospace;
color: var(--primary-600); background: var(--primary-50);
border: 1px solid var(--primary-200);
padding: 1.5px 6px; border-radius: 999px; vertical-align: 1px;
}
/* 搜索框:整体一个圆角容器,输入 + 按钮分段 */
.toolbar { display: flex; align-items: center; gap: 10px; }
.toolbar input {
height: 36px; width: 260px; padding: 0 13px; font-size: 13px;
background: var(--surface); color: var(--text);
border: 1px solid var(--border); border-radius: var(--radius-sm);
outline: none; transition: border-color .2s, box-shadow .2s;
}
.toolbar input:focus {
border-color: var(--primary-500);
box-shadow: 0 0 0 3px rgba(20,184,166,.15);
}
.toolbar button {
height: 36px; padding: 0 16px; border: 1px solid var(--border);
background: var(--surface); color: var(--gray-700);
border-radius: var(--radius-sm); font-size: 12.5px; font-weight: 500;
cursor: pointer; transition: all .18s; box-shadow: var(--shadow-card);
}
.toolbar button:hover {
color: var(--primary-700); border-color: var(--primary-300); background: var(--primary-50);
}
#btnSearch {
background: linear-gradient(135deg, var(--primary-500), var(--primary-600));
border-color: transparent; color: #fff; font-weight: 600;
}
#btnSearch:hover { filter: brightness(.94); background: linear-gradient(135deg, var(--primary-500), var(--primary-600)); color: #fff; }
.srv-status { display: flex; align-items: center; gap: 6px; font-size: 11.5px; color: var(--text-dim); flex: none; }
.srv-status .dot { width: 9px; height: 9px; border-radius: 50%; background: var(--gray-400); flex: none; transition: background .2s; }
.srv-status .text { white-space: nowrap; }
.srv-status.ready .dot { background: #059669; }
.srv-status.no-worker .dot { background: #d97706; }
.srv-status.idle .dot { background: #059669; }
.srv-status.down .dot { background: #dc2626; }
/* ------------------------------------------------------------ 主区 */
main { flex: 1; display: flex; min-height: 0; }
/* 分隔条: 视觉 5px, 实际 11px 热区 (负外边距, 不占布局) — 更好抓 */
.split {
width: 5px; cursor: col-resize; background: var(--gray-100); flex: none;
transition: background .2s; position: relative;
}
.split::after {
content: ''; position: absolute; top: 0; bottom: 0; left: -3px; right: -3px;
}
.split:hover, .split.dragging { background: var(--primary-400); }
.split.dragging { z-index: 5; }
/* 左侧树: 外层可滚动, 内层按剩余高度均匀分布 (按钮不被拉伸, 间隙随高度变化) */
.tree {
width: 250px; background: var(--surface);
border-right: 1px solid var(--border-soft);
padding: 8px; overflow-y: auto;
transition: width .25s cubic-bezier(.2,.8,.3,1);
}
.tree.rail { width: 60px; padding: 8px 6px; }
/* 内层: min-height 100% + space-evenly —— 有富余高度时均匀留白;
内容超高时自动退化为普通排列 (不会像直接对滚动容器用 space-evenly 那样裁掉顶部) */
.tree-inner {
min-height: 100%; display: flex; flex-direction: column;
justify-content: space-evenly; gap: 8px;
}
/* 大类标题: 图标 + 文字; 悬停放大动画 (与缩略图卡片同款手感) */
.tree .cat {
display: flex; align-items: center; gap: 9px;
flex: none; min-height: 44px;
font-size: 12px; font-weight: 800; letter-spacing: .2px;
color: var(--gray-900);
background: var(--gray-100);
border-left: 3px solid var(--primary-500);
padding: 8px 12px; border-radius: var(--radius-sm);
cursor: pointer; user-select: none;
box-shadow: var(--shadow-card);
transition: transform .32s cubic-bezier(.2,.8,.3,1),
box-shadow .32s cubic-bezier(.2,.8,.3,1),
background .2s, color .2s, border-color .2s;
will-change: transform;
}
/* 悬停: 抬升 + 放大 + 青色投影 (与 .sf-card 一致) */
.tree .cat:hover {
transform: translateY(-3px) scale(1.035);
box-shadow: 0 10px 26px rgba(20,184,166,.22), 0 3px 10px rgba(0,0,0,.08);
background: var(--primary-100); color: var(--primary-800);
border-left-color: var(--primary-600);
z-index: 2;
}
.tree .cat:active { transform: translateY(-1px) scale(1.01); }
.tree .cat.open {
background: linear-gradient(135deg, var(--primary-500), var(--primary-600));
color: #fff; border-left-color: var(--primary-700);
}
.tree .cat.open:hover {
box-shadow: 0 10px 26px rgba(20,184,166,.35), 0 3px 10px rgba(0,0,0,.10);
background: linear-gradient(135deg, var(--primary-500), var(--primary-600));
color: #fff;
}
/* 图标: 24x24 线性 SVG, 随 currentColor 变色 */
.tree .cat-ico {
flex: none; width: 22px; height: 22px;
display: flex; align-items: center; justify-content: center;
transition: transform .32s cubic-bezier(.2,.8,.3,1);
}
.tree .cat-ico svg { width: 22px; height: 22px; display: block; }
.tree .cat:hover .cat-ico { transform: scale(1.12); }
.tree .cat-name {
flex: 1; min-width: 0;
overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.tree .cat-arrow {
font-size: 9px; flex: none; opacity: .7;
transition: transform .2s;
}
/* 收起态 (rail): 只留图标, 文字与箭头隐藏; 子级一并收起 */
.tree.rail .cat {
flex: none; justify-content: center;
padding: 8px; border-left-width: 0;
border-radius: var(--radius-sm); width: 100%;
}
.tree.rail .cat-name,
.tree.rail .cat-arrow { display: none; }
.tree.rail .cat-kids { display: none !important; }
.tree.rail .cat-ico svg { width: 24px; height: 24px; }
/* 折叠动画 (展开子级时淡入上滑) */
.tree .cat-kids { margin: 0 0 4px; animation: kidsIn .22s ease-out; }
@keyframes kidsIn {
from { opacity: 0; transform: translateY(-4px); }
to { opacity: 1; transform: translateY(0); }
}
.tree .series {
padding: 9px 12px; margin: 1px 0; border-radius: var(--radius-xs);
cursor: pointer; font-size: 13px; color: var(--gray-700);
border-left: 3px solid transparent;
transition: background .15s, color .15s, border-color .15s;
}
.tree .series:hover { background: var(--primary-50); color: var(--primary-700); }
.tree .series.active {
background: var(--primary-50); color: var(--primary-700);
border-left-color: var(--primary-500); font-weight: 600;
}
/* 参数列 */
.params {
width: 330px; background: var(--surface);
border-right: 1px solid var(--border-soft);
padding: 16px; overflow-y: auto;
}
.model-title {
font-size: 16px; font-weight: 700; margin-bottom: 12px;
color: var(--gray-900); letter-spacing: -.3px; line-height: 1.4;
}
.param-row { margin-bottom: 14px; }
.param-row label {
display: flex; align-items: baseline; gap: 7px;
font-size: 11px; font-weight: 700; color: var(--text-faint);
text-transform: uppercase; letter-spacing: .5px; margin-bottom: 7px;
}
/* 维度已选值回显在其后 */
.param-row label .picked {
text-transform: none; letter-spacing: 0; font-weight: 600;
color: var(--primary-700); font-size: 11.5px;
}
.param-row select, .param-input {
width: 100%; height: 36px; padding: 0 10px; font-size: 13px;
border: 1px solid var(--border); border-radius: var(--radius-sm);
background: var(--surface); color: var(--text); outline: none;
transition: border-color .2s, box-shadow .2s;
}
.param-row select:focus, .param-input:focus {
border-color: var(--primary-500); box-shadow: 0 0 0 3px rgba(20,184,166,.15);
}
/* #actions 原在左侧参数面板底部,现移到 tab 行右侧(与 3D/尺寸图 等同一行)。
元素 id 未变,JS 按 id 取用,位置移动不影响逻辑。 */
#actions { display: flex; gap: 8px; flex-wrap: wrap; align-items: center; }
/* tab 行的弹性占位:把 #actions 推到最右 */
.tabs-spacer { flex: 1; min-width: 8px; }
/* 窄屏时按钮换行到下一行,避免挤压 tab */
@media (max-width: 1100px) {
.tabs { flex-wrap: wrap; }
.tabs-spacer { flex-basis: 100%; height: 0; }
}
/* ============================================================ 零件号实时条 (DESTACO 风)
* 边选边拼: 已确定部分实心高亮, 未定部分虚化占位。 */
/* ============================================================ 零件号实时条
* 边选边拼: 已确定片段的实心高亮, 未定片段虚化占位。
* 配色走浅色主调 (与整体卡片风格一致), 不用深色块。 */
.sku-bar {
background: linear-gradient(135deg, var(--primary-50), #ffffff 70%);
border: 1px solid var(--primary-200);
border-radius: var(--radius); padding: 13px 15px; margin-bottom: 14px;
box-shadow: var(--shadow-card);
}
.sku-bar .sku-label {
font-size: 10px; text-transform: uppercase; letter-spacing: .7px;
color: var(--text-faint); margin-bottom: 5px;
}
.sku-bar .sku-code {
font-family: ui-monospace, Consolas, monospace;
font-size: 20px; font-weight: 700; letter-spacing: -.4px;
word-break: break-all; line-height: 1.25; min-height: 25px;
}
.sku-bar .sku-fixed { color: var(--primary-700); } /* 已确定片段 */
.sku-bar .sku-tbd { color: var(--gray-300); } /* 待定占位 */
.sku-bar .sku-prog {
margin-top: 9px; height: 3px; border-radius: 999px;
background: var(--primary-100); overflow: hidden;
}
.sku-bar .sku-prog > i {
display: block; height: 100%; width: 0;
background: linear-gradient(90deg, var(--primary-400), var(--primary-600));
border-radius: 999px; transition: width .3s cubic-bezier(.2,.8,.3,1);
}
/* 零件号完整: 整块转为实心青色, 作为"完成"的强反馈 */
.sku-bar.done {
background: linear-gradient(135deg, var(--primary-500), var(--primary-600));
border-color: transparent;
box-shadow: var(--shadow-btn);
}
.sku-bar.done .sku-label { color: rgba(255,255,255,.72); }
.sku-bar.done .sku-fixed { color: #fff; }
.sku-bar.done .sku-tbd { color: rgba(255,255,255,.5); }
.sku-bar.done .sku-prog { background: rgba(255,255,255,.28); }
.sku-bar.done .sku-prog > i { background: #fff; }
.sku-bar.done .sku-hint { color: rgba(255,255,255,.85); }
.sku-bar .sku-hint {
margin-top: 8px; font-size: 11px; color: var(--text-dim);
}
/* ============================================================ 选项块 (替代下拉)
* 有图用卡片, 无图用文字块; 一行多个, 自动换行。 */
.opt-grid {
display: grid; gap: 7px;
grid-template-columns: repeat(auto-fill, minmax(72px, 1fr));
}
.opt-grid.wide { grid-template-columns: repeat(auto-fill, minmax(96px, 1fr)); }
.opt {
position: relative; cursor: pointer; user-select: none;
border: 1.5px solid var(--border); border-radius: var(--radius-sm);
background: var(--surface); padding: 8px 9px;
display: flex; flex-direction: column; align-items: center; gap: 3px;
min-height: 46px; justify-content: center;
transition: transform .18s cubic-bezier(.2,.8,.3,1),
border-color .18s, background .18s, box-shadow .18s;
}
.opt:hover {
transform: translateY(-2px); border-color: var(--primary-400);
box-shadow: 0 6px 16px rgba(20,184,166,.18);
}
.opt .opt-k {
font-family: ui-monospace, Consolas, monospace;
font-size: 13px; font-weight: 700; color: var(--gray-900);
line-height: 1.2; text-align: center; word-break: break-word;
}
.opt .opt-d {
font-size: 10px; color: var(--text-faint); text-align: center;
line-height: 1.25; word-break: break-word;
}
/* 选中态: 青色填充 */
.opt.on {
border-color: var(--primary-500);
background: var(--primary-50);
box-shadow: 0 0 0 2px rgba(20,184,166,.22);
}
.opt.on .opt-k { color: var(--primary-700); }
.opt.on::after {
content: '✓'; position: absolute; top: 3px; right: 5px;
font-size: 10px; color: var(--primary-600); font-weight: 700;
}
/* 不可选 (被联动规则排除): 置灰 + 划线 + 不可点 */
.opt.off {
opacity: .32; cursor: not-allowed; background: var(--gray-50);
border-style: dashed;
}
.opt.off .opt-k { text-decoration: line-through; }
.opt.off:hover { transform: none; box-shadow: none; border-color: var(--border); }
/* 无图时的纯文字块: 更紧凑 */
.opt.txt { min-height: 38px; padding: 7px 8px; }
.opt.txt .opt-k { font-size: 12.5px; }
/* ------------------------------------------------------------ 按钮 */
.btn {
display: inline-flex; align-items: center; justify-content: center;
height: 38px; padding: 0 18px; border-radius: var(--radius-sm);
text-decoration: none; font-size: 13px; font-weight: 500; cursor: pointer;
background: var(--surface); color: var(--gray-700);
border: 1px solid var(--border); box-shadow: var(--shadow-card);
transition: all .18s;
}
.btn:hover { color: var(--primary-700); border-color: var(--primary-300); background: var(--primary-50); }
.btn.primary {
background: linear-gradient(135deg, var(--primary-500), var(--primary-600));
border-color: transparent; color: #fff; font-weight: 600;
box-shadow: var(--shadow-btn);
}
.btn.primary:hover { filter: brightness(.94); color: #fff; }
.btn[disabled] { opacity: .5; cursor: not-allowed; box-shadow: none; }
.btn[disabled]:hover { filter: none; border-color: var(--border); background: var(--surface); color: var(--gray-700); }
.btn.primary[disabled]:hover { background: linear-gradient(135deg, var(--primary-500), var(--primary-600)); color: #fff; }
.hidden { display: none !important; }
/* ------------------------------------------------------------ 嵌入模式
供 Odoo 产品页 iframe 使用 (?embed=1):隐藏工具自身的顶栏与底栏,
避免在网站页面里出现"页中页",同时把高度让给内容区。
由 app.js 的 applyDeepLink() 给 body 加 .embed-mode 触发。 */
body.embed-mode header,
body.embed-mode footer { display: none !important; }
body.embed-mode { height: 100vh; }
/* 隐藏模式 (?nav=0):嵌入 Odoo 产品页时用。
产品页已经决定了是哪个系列,左侧系列树、分隔条、「返回系列总览」纯属多余,
隐藏后让参数面板 + 内容区铺满整宽,观感更干净。 */
body.nav-off #tree,
body.nav-off #split1,
body.nav-off .content-back { display: none !important; }
/* 隐藏侧栏后,参数面板适当加宽(原来 330px 是因为旁边还有树+主区抢空间) */
body.nav-off .params { width: 300px; }
/* ------------------------------------------------------------ 内容区 / 标签页 */
.content { flex: 1; display: flex; flex-direction: column; min-width: 0; padding: 14px; }
.tabs { display: flex; gap: 6px; flex: none; align-items: center; }
.content-back { flex: none; margin: 10px 0 0; }
/* ------------------------------------------------------------ 手册页图片放大
点击手册页图片 → 全屏遮罩显示大图。点遮罩任意处 / 按 Esc 关闭。
用 position:fixed 覆盖整个视口(含 iframe 内嵌场景)。 */
.manual-img { cursor: zoom-in; }
/* 数据表按钮图标(内联 SVG,工具无图标字体) */
.ds-ico { width: 15px; height: 15px; flex: none; vertical-align: -3px; }
.ds-ico-eye { opacity: .65; }
#btnDatasheet { display: inline-flex; align-items: center; gap: 6px; }
#btnDatasheet:hover .ds-ico-eye { opacity: 1; }
#btnDatasheet .ds-txt { white-space: nowrap; }
.img-zoom-overlay {
position: fixed; inset: 0; z-index: 900;
background: rgba(17, 24, 39, .88);
display: flex; align-items: center; justify-content: center;
padding: 24px; cursor: zoom-out;
animation: imgZoomIn .16s ease-out;
}
@keyframes imgZoomIn { from { opacity: 0; } to { opacity: 1; } }
.img-zoom-overlay img {
max-width: 100%; max-height: 100%;
object-fit: contain; border-radius: 6px;
box-shadow: 0 12px 48px rgba(0, 0, 0, .5);
}
.img-zoom-close {
position: absolute; top: 14px; right: 18px;
width: 40px; height: 40px; border: 0; border-radius: 50%;
background: rgba(255, 255, 255, .16); color: #fff;
font-size: 22px; line-height: 1; cursor: pointer;
display: flex; align-items: center; justify-content: center;
transition: background .18s;
}
.img-zoom-close:hover { background: rgba(255, 255, 255, .3); }
.img-zoom-cap {
position: absolute; bottom: 14px; left: 0; right: 0;
text-align: center; color: rgba(255, 255, 255, .75); font-size: 12.5px;
pointer-events: none;
}
/* ------------------------------------------------------------ 数据表 PDF 弹窗预览
点击「数据表」→ 弹窗内用浏览器内置 PDF 阅读器打开,标题栏含下载入口。 */
.pdf-zoom-overlay {
position: fixed; inset: 0; z-index: 910;
background: rgba(17, 24, 39, .72);
display: flex; align-items: center; justify-content: center;
padding: 24px;
animation: imgZoomIn .16s ease-out;
}
.pdf-zoom-box {
width: min(1100px, 100%); height: min(92vh, 100%);
display: flex; flex-direction: column;
background: var(--surface, #fff);
border-radius: 10px; overflow: hidden;
box-shadow: 0 16px 56px rgba(0, 0, 0, .45);
}
.pdf-zoom-head {
flex: none; display: flex; align-items: center; gap: 12px;
padding: 10px 12px 10px 16px;
border-bottom: 1px solid var(--border, #e5e7eb);
background: var(--surface, #fff);
}
.pdf-zoom-title {
flex: 1; font-size: 13px; font-weight: 600; color: var(--gray-900, #111827);
overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.pdf-zoom-dl {
flex: none; font-size: 12.5px; text-decoration: none;
padding: 6px 14px; border-radius: 6px;
background: var(--primary, #14b8a6); color: #fff;
transition: filter .18s;
}
.pdf-zoom-dl:hover { filter: brightness(.94); }
.pdf-zoom-close {
position: static; flex: none;
width: 32px; height: 32px; font-size: 18px;
background: var(--gray-100, #f3f4f6); color: var(--gray-700, #374151);
}
.pdf-zoom-close:hover { background: var(--gray-200, #e5e7eb); }
.pdf-zoom-frame {
flex: 1; width: 100%; border: 0; background: #525659;
}
@media (max-width: 767.98px) {
.pdf-zoom-overlay { padding: 0; }
.pdf-zoom-box { width: 100%; height: 100%; border-radius: 0; }
}
.tab {
height: 36px; padding: 0 16px; border: 1px solid var(--border);
border-radius: var(--radius-sm); background: var(--surface);
color: var(--gray-700); cursor: pointer; font-size: 12.5px; font-weight: 500;
transition: all .18s; box-shadow: var(--shadow-card);
}
.tab:hover { color: var(--primary-700); border-color: var(--primary-300); background: var(--primary-50); }
.tab.active {
background: linear-gradient(135deg, var(--primary-500), var(--primary-600));
border-color: transparent; color: #fff;
}
.tab-body {
flex: 1; overflow: auto; background: var(--surface);
border: 1px solid var(--border-soft); border-radius: var(--radius);
padding: 14px; box-shadow: var(--shadow-card); margin-top: 10px;
}
.tab-body iframe { width: 100%; height: 100%; border: none; display: block; }
#viewer3d { display: block; }
#dimImage { max-width: 100%; max-height: 100%; }
/* 3D + 尺寸图同页布局 (左右分栏, 中间分隔条可拖拽) */
#tab-3d { display: flex; overflow: hidden; padding: 0; }
.hsplit { flex: 1; display: flex; min-width: 0; min-height: 0; }
/* max-width 与 JS 的 minRight 护栏对齐 (185 = 5px 分隔条 + 180px 右栏下限):
否则拖拽写进的 inline width 会把分隔条挤到容器外, 再也抓不回来 */
.hsplit-left {
width: 62%; flex: none; min-width: 0;
max-width: calc(100% - 185px);
position: relative; overflow: auto; padding: 14px;
}
.hsplit-right { flex: 1; min-width: 160px; overflow-y: auto; padding: 14px; border-left: none; }
.split.v { cursor: col-resize; touch-action: none; }
/* 表格标签页: 筛选栏固定顶部, 表格独立滚动 (表头 sticky 不露缝) */
#tab-table, #tab-search, #tab-cross { display: flex; flex-direction: column; overflow: hidden; }
#tab-table .range-row, #tab-cross .range-row { flex: none; margin-bottom: 8px; }
.table-scroll { flex: 1; overflow: auto; min-height: 0; border-radius: var(--radius-sm); }
/* 参数表列筛选: 表头可点 + 取值下拉 */
th.col-filter { cursor: pointer; user-select: none; }
th.col-filter:hover { background: var(--primary-100); }
.col-filter-pop {
position: absolute; background: var(--surface); border: 1px solid var(--border);
border-radius: var(--radius-sm);
box-shadow: 0 12px 32px rgba(0,0,0,.14); z-index: 1000; max-height: 260px;
overflow-y: auto; min-width: 140px; padding: 4px;
}
.col-filter-item { padding: 7px 11px; font-size: 12.5px; cursor: pointer; white-space: nowrap; border-radius: 7px; }
.col-filter-item:hover { background: var(--primary-50); color: var(--primary-700); }
.col-filter-item.sel { background: var(--primary-50); color: var(--primary-700); font-weight: 600; }
.manual-cap { margin: 14px 0 5px; font-weight: 600; font-size: 12.5px; color: var(--text-dim); }
/* 手册页: 限制高度避免超高图把面板撑破; 禁用拖拽与选中, 拖不动也就不会误触原生拖拽 */
.manual-img {
max-width: 100%; max-height: 78vh; object-fit: contain;
border: 1px solid var(--border); border-radius: var(--radius-sm);
-webkit-user-drag: none; user-select: none;
display: block;
}
.hint { color: var(--text-faint); font-size: 12.5px; line-height: 1.6; }
table { width: 100%; border-collapse: collapse; font-size: 12.5px; }
th, td { border: 1px solid var(--border-soft); padding: 7px 9px; text-align: left; }
th {
background: var(--gray-50); position: sticky; top: 0; z-index: 1;
font-size: 11px; font-weight: 700; color: var(--text-dim);
text-transform: uppercase; letter-spacing: .4px;
}
tr:hover td { background: var(--primary-50); cursor: pointer; }
.range-row {
margin-bottom: 8px; display: flex; gap: 12px; flex-wrap: wrap;
align-items: center; font-size: 12.5px; color: var(--text-dim);
}
.range-row input {
width: 66px; height: 32px; padding: 0 9px; font-size: 12.5px;
border: 1px solid var(--border); border-radius: var(--radius-xs); outline: none;
}
.range-row input:focus { border-color: var(--primary-500); box-shadow: 0 0 0 3px rgba(20,184,166,.15); }
.range-row select {
height: 32px; padding: 0 9px; font-size: 12.5px;
border: 1px solid var(--border); border-radius: var(--radius-xs); background: var(--surface);
}
/* ------------------------------------------------------------ 底栏 */
footer {
height: 34px; padding: 0 18px; font-size: 12px; color: var(--text-dim);
background: var(--surface); border-top: 1px solid var(--border-soft);
display: flex; align-items: center; gap: 12px;
}
footer #statusMsg { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* 侧边栏折叠按钮 (底部左侧) */
.tree-toggle {
flex: none; height: 24px; padding: 0 11px;
border: 1px solid var(--border); border-radius: 999px;
background: var(--surface); color: var(--gray-700);
font-size: 11.5px; font-weight: 500; cursor: pointer;
transition: all .18s;
}
.tree-toggle:hover {
color: var(--primary-700); border-color: var(--primary-300); background: var(--primary-50);
}
/* ============================================================ 首页:系列缩略图网格 */
.home { flex: 1; overflow-y: auto; padding: 18px 20px 24px; min-width: 0; }
.sf-head { display: flex; align-items: baseline; gap: 10px; margin: 0 0 18px 2px; }
.sf-head h2 {
margin: 0; font-size: 18px; font-weight: 700; color: var(--gray-900);
letter-spacing: -.3px;
}
.sf-head .n { font-size: 12px; color: var(--text-faint); font-variant-numeric: tabular-nums; }
.sf-head .grow { flex: 1; }
/* 首页按大类分组: 父标题 + 该类的系列缩略图网格 */
.home-sec { margin-bottom: 26px; }
.home-sec-head {
display: flex; align-items: baseline; gap: 10px;
margin: 0 0 12px 2px; padding-bottom: 8px;
border-bottom: 2px solid var(--border-soft);
}
.home-sec-head h3 {
margin: 0; font-size: 15px; font-weight: 800; color: var(--gray-900);
letter-spacing: -.2px;
border-left: 3px solid var(--primary-500); padding-left: 9px; line-height: 1.25;
}
.home-sec-head .n { font-size: 11.5px; color: var(--text-faint); font-variant-numeric: tabular-nums; }
.sf-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(196px, 1fr));
gap: 16px;
}
/* 卡片:大圆角,接近小米那种圆润感 */
.sf-card {
position: relative; cursor: pointer; overflow: hidden;
border-radius: 20px;
background: var(--surface);
border: 1px solid var(--border-soft);
box-shadow: var(--shadow-card);
transition: transform .32s cubic-bezier(.2,.8,.3,1),
box-shadow .32s cubic-bezier(.2,.8,.3,1),
border-color .32s;
display: flex; flex-direction: column; align-items: center;
padding: 16px 14px 14px;
will-change: transform;
}
/* 悬停:抬升 + 放大一点点 + 阴影加深 + 青色描边 */
.sf-card:hover {
transform: translateY(-7px) scale(1.028);
box-shadow: 0 18px 44px rgba(20,184,166,.20), 0 6px 18px rgba(0,0,0,.09);
border-color: var(--primary-300);
z-index: 2;
}
.sf-card:active { transform: translateY(-3px) scale(1.01); }
/* 悬停时卡片底部泛出的青色渐变 */
.sf-card::after {
content: ''; position: absolute; inset: auto 0 0 0; height: 44%;
background: linear-gradient(180deg, transparent, rgba(20,184,166,.10));
opacity: 0; transition: opacity .32s; pointer-events: none;
}
.sf-card:hover::after { opacity: 1; }
.sf-fig {
width: 100%; height: 150px; display: flex; align-items: center;
justify-content: center; overflow: hidden;
border-radius: 14px; background: #fff;
margin-bottom: 11px;
}
.sf-fig img {
max-width: 100%; max-height: 100%; object-fit: contain;
transition: transform .42s cubic-bezier(.2,.8,.3,1);
}
.sf-card:hover .sf-fig img { transform: scale(1.13) rotate(-1.2deg); }
.sf-code {
font-family: ui-monospace, Consolas, monospace; font-weight: 700;
font-size: 15.5px; color: var(--primary-700); letter-spacing: -.3px;
transition: color .2s;
}
.sf-card:hover .sf-code { color: var(--primary-600); }
.sf-name {
font-size: 11.5px; color: var(--text-dim); margin-top: 4px;
text-align: center; line-height: 1.35;
overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
max-width: 100%;
}
/* 选中态 */
.sf-card.on {
border-color: var(--primary-500);
box-shadow: 0 0 0 2px rgba(20,184,166,.28), var(--shadow-card);
}
/* ------------------------------------------------------------ 购物车 */
.cart-badge {
height: 36px; padding: 0 15px; border: 1px solid var(--border);
background: var(--surface); color: var(--gray-700);
font-size: 12.5px; font-weight: 500; cursor: pointer;
border-radius: var(--radius-sm); transition: all .18s; box-shadow: var(--shadow-card);
}
.cart-badge:hover { color: var(--primary-700); border-color: var(--primary-300); background: var(--primary-50); }
.cart-overlay { position: fixed; inset: 0; background: rgba(17,24,39,.35); backdrop-filter: blur(2px); z-index: 500; }
.cart-panel {
position: fixed; top: 0; right: 0; bottom: 0; width: 430px; max-width: 92vw;
background: var(--surface); z-index: 501; display: flex; flex-direction: column;
box-shadow: -12px 0 40px rgba(0,0,0,.18);
}
.cart-head {
display: flex; justify-content: space-between; align-items: center;
padding: 16px 20px; border-bottom: 1px solid var(--border-soft);
font-size: 15px; font-weight: 700; color: var(--gray-900);
}
.cart-close { border: none; background: transparent; font-size: 16px; cursor: pointer; color: var(--text-dim); }
.cart-close:hover { color: var(--gray-900); }
.cart-list { flex: 1; overflow-y: auto; padding: 12px 20px; }
.cart-item { border-bottom: 1px solid var(--border-soft); padding: 11px 0; font-size: 12.5px; }
.cart-item .ci-model { font-weight: 700; font-size: 13.5px; color: var(--primary-700); font-family: ui-monospace, Consolas, monospace; }
.cart-item .ci-sub { color: var(--text-dim); margin-top: 3px; word-break: break-all; line-height: 1.45; }
.cart-item .ci-ops { display: flex; align-items: center; gap: 10px; margin-top: 8px; color: var(--text-dim); }
.cart-item .ci-ops input {
width: 60px; height: 30px; padding: 0 8px; font-size: 12.5px;
border: 1px solid var(--border); border-radius: var(--radius-xs); outline: none;
}
.cart-item .ci-ops input:focus { border-color: var(--primary-500); box-shadow: 0 0 0 3px rgba(20,184,166,.15); }
.cart-item .ci-del {
height: 30px; padding: 0 12px; border: 1px solid var(--border); background: var(--surface);
color: #dc2626; border-radius: var(--radius-xs); cursor: pointer; font-size: 12px;
transition: all .15s;
}
.cart-item .ci-del:hover { background: #fef2f2; border-color: #fca5a5; }
.cart-foot { display: flex; gap: 10px; padding: 16px 20px; border-top: 1px solid var(--border-soft); }
.cart-foot .btn { flex: 1; }
.add-cart-btn {
height: 30px; padding: 0 12px; border: 1px solid var(--border);
background: var(--surface); color: var(--primary-700);
border-radius: var(--radius-xs); cursor: pointer; font-size: 12px;
transition: all .15s;
}
.add-cart-btn:hover { background: var(--primary-50); border-color: var(--primary-300); }
/* ------------------------------------------------------------ 参数化选型 */
.nonstd-badge {
display: inline-block; margin-left: 8px; padding: 2px 9px;
background: #fffbeb; color: #b45309; border: 1px solid #fde68a;
border-radius: 999px; font-size: 11.5px; font-weight: normal; vertical-align: middle;
}
/* ------------------------------------------------------------ 响应式 */
@media (max-width: 860px) {
.tree { width: 200px; }
.params { width: 280px; }
.toolbar input { width: 180px; }
.home { padding: 12px; }
.sf-grid { grid-template-columns: repeat(2, 1fr); gap: 12px; }
.sf-fig { height: 118px; margin-bottom: 9px; }
.sf-card { border-radius: 16px; padding: 12px 10px 11px; }
.sf-card:hover { transform: none; } /* 触屏无悬停,别留悬浮态 */
.sf-code { font-size: 14px; }
}
@media (max-width: 420px) {
.sf-fig { height: 104px; }
}