正式 scripts 仅保留 README 自测清单;根目录报告迁入 docs/reports; lab 采样 dump 出库;CSS 注明 btn/toast 所有权并 bump ?v=。
585 lines
21 KiB
CSS
585 lines
21 KiB
CSS
/* ============================================================
|
||
layout.css — 命令栏头部 / 主布局 / 卡片 / 表单 / 按钮 / 侧滑抽屉
|
||
============================================================ */
|
||
|
||
/* ================= HEADER — 命令栏 ================= */
|
||
.header-bar {
|
||
position: relative;
|
||
z-index: 20; /* 高于下方卡片,保证 pill tooltip 不被遮挡 */
|
||
display: flex; align-items: center; gap: 16px;
|
||
padding: 16px 22px; margin-bottom: 26px;
|
||
background:
|
||
radial-gradient(620px 240px at 88% -40%, rgba(47,216,193,.12), transparent 60%),
|
||
linear-gradient(160deg, var(--bg-panel) 0%, var(--bg-card) 70%);
|
||
border: 1px solid var(--border);
|
||
border-radius: var(--radius-lg);
|
||
box-shadow: var(--shadow-card);
|
||
flex-wrap: wrap;
|
||
}
|
||
/* 顶部三色霓虹描边:ESP32 青绿 → BLE 蓝 → GD32 琥珀,一条细线点出子系统谱系 */
|
||
.header-bar::before {
|
||
content: "";
|
||
position: absolute; top: 0; left: 0; right: 0; height: 2px;
|
||
background: linear-gradient(90deg,
|
||
var(--esp32) 0%, var(--ble) 38%, var(--gd32) 78%, transparent 100%);
|
||
opacity: .85;
|
||
border-radius: var(--radius-lg) var(--radius-lg) 0 0;
|
||
}
|
||
|
||
.header-brand {
|
||
display: flex; align-items: center; gap: 12px;
|
||
padding-right: 20px; border-right: 1px solid var(--border);
|
||
white-space: nowrap;
|
||
}
|
||
.brand-logo {
|
||
width: 40px; height: 40px; flex-shrink: 0;
|
||
display: inline-flex; align-items: center; justify-content: center;
|
||
border-radius: 11px;
|
||
background: linear-gradient(145deg, rgba(47,216,193,.16), rgba(95,168,255,.10));
|
||
border: 1px solid rgba(47,216,193,.3);
|
||
box-shadow: 0 0 18px rgba(47,216,193,.18), inset 0 0 12px rgba(47,216,193,.08);
|
||
color: var(--esp32);
|
||
}
|
||
.brand-logo svg { width: 24px; height: 24px; display: block; }
|
||
.brand-text { display: flex; flex-direction: column; line-height: 1.15; }
|
||
.brand-text strong {
|
||
font-family: var(--font-display);
|
||
font-size: 17px; font-weight: 700; letter-spacing: .02em;
|
||
background: linear-gradient(92deg, var(--text) 30%, var(--esp32-hi) 100%);
|
||
-webkit-background-clip: text; background-clip: text;
|
||
-webkit-text-fill-color: transparent;
|
||
}
|
||
.brand-sub {
|
||
font-family: var(--font-mono);
|
||
font-size: 10px; letter-spacing: .22em; text-transform: uppercase;
|
||
color: var(--text-label); margin-top: 2px;
|
||
}
|
||
/* 兼容旧结构:独立 dot-mark(无 brand-logo 时)仍显示为一颗呼吸 LED */
|
||
.header-brand .dot-mark {
|
||
width: 10px; height: 10px; border-radius: 50%;
|
||
background: var(--esp32);
|
||
box-shadow: 0 0 10px var(--esp32-dim);
|
||
flex-shrink: 0;
|
||
}
|
||
.header-brand strong { font-size: 16px; font-weight: 700; }
|
||
|
||
.header-status {
|
||
display: flex; align-items: center; gap: 8px;
|
||
flex-wrap: wrap;
|
||
}
|
||
.header-sub {
|
||
display: flex; gap: 10px; margin-left: auto;
|
||
flex-wrap: wrap;
|
||
}
|
||
|
||
/* ---- 状态胶囊 ---- */
|
||
.pill {
|
||
display: inline-flex; align-items: center; gap: 7px;
|
||
padding: 6px 13px; border-radius: 999px;
|
||
font-size: 12px; font-weight: 500;
|
||
font-family: var(--font-mono);
|
||
background: var(--bg-elevated); border: 1px solid var(--border);
|
||
color: var(--text-dim);
|
||
white-space: nowrap;
|
||
transition: border-color .2s, background .2s, transform .2s;
|
||
}
|
||
.pill .indicator {
|
||
width: 7px; height: 7px; border-radius: 50%; flex-shrink: 0;
|
||
background: var(--text-label);
|
||
}
|
||
.pill.online .indicator { background: var(--green); box-shadow: 0 0 8px rgba(61,220,142,.6); }
|
||
.pill.offline .indicator { background: var(--red); box-shadow: 0 0 8px rgba(255,107,107,.5); }
|
||
.pill.processing .indicator,
|
||
.pill.live .indicator { background: var(--amber); animation: blink 1s infinite; }
|
||
.pill.idle .indicator { background: var(--text-dim); }
|
||
.pill.online { color: var(--can-hi); border-color: rgba(61,220,142,.35); }
|
||
.pill.offline { color: #ffb3b3; border-color: rgba(255,107,107,.3); }
|
||
.pill.processing,
|
||
.pill.live { color: var(--gd32-hi); border-color: rgba(252,191,63,.35); }
|
||
@keyframes blink { 50% { opacity: .3; } }
|
||
|
||
.pill-val {
|
||
font-weight: 700; color: var(--text);
|
||
font-family: var(--font-mono);
|
||
}
|
||
|
||
/* ================= 主布局 ================= */
|
||
.main-layout {
|
||
display: grid;
|
||
grid-template-columns: 400px 1fr;
|
||
gap: var(--gap);
|
||
align-items: start;
|
||
}
|
||
|
||
/* ================= 卡片 ================= */
|
||
.card {
|
||
position: relative;
|
||
background: linear-gradient(170deg, var(--bg-card) 0%, rgba(15,23,38,.92) 100%);
|
||
border: 1px solid var(--border);
|
||
border-radius: var(--radius);
|
||
overflow: hidden;
|
||
box-shadow: var(--shadow-card);
|
||
}
|
||
.card + .card { margin-top: var(--gap); }
|
||
|
||
/* 子系统色带:卡片顶部 2px 渐变,由修饰类决定颜色 */
|
||
.card::before {
|
||
content: "";
|
||
position: absolute; top: 0; left: 0; right: 0; height: 2px;
|
||
background: linear-gradient(90deg, var(--card-accent, var(--esp32)), transparent 85%);
|
||
opacity: .7; pointer-events: none;
|
||
}
|
||
.card--esp32 { --card-accent: var(--esp32); --card-accent-dim: var(--esp32-dim); }
|
||
.card--gd32 { --card-accent: var(--gd32); --card-accent-dim: var(--gd32-dim); }
|
||
.card--ble { --card-accent: var(--ble); --card-accent-dim: var(--ble-dim); }
|
||
.card--can { --card-accent: var(--can); --card-accent-dim: var(--can-dim); }
|
||
.card--motor { --card-accent: var(--motor); --card-accent-dim: var(--motor-dim); }
|
||
.card--mem { --card-accent: var(--mem); --card-accent-dim: var(--mem-dim); }
|
||
.card--status { --card-accent: var(--green); --card-accent-dim: var(--can-dim); }
|
||
|
||
.card-head {
|
||
display: flex; align-items: center; gap: 10px;
|
||
padding: 14px 18px;
|
||
border-bottom: 1px solid var(--border-subtle);
|
||
font-family: var(--font-display);
|
||
font-size: 13px; font-weight: 600;
|
||
color: var(--text);
|
||
letter-spacing: .05em;
|
||
cursor: pointer;
|
||
user-select: none;
|
||
}
|
||
/* 图标芯片:圆角方块底色取自卡片子系统色 */
|
||
.card-head .ico {
|
||
width: 28px; height: 28px; flex-shrink: 0;
|
||
display: inline-flex; align-items: center; justify-content: center;
|
||
font-size: 15px;
|
||
border-radius: 8px;
|
||
background: var(--card-accent-dim, var(--esp32-dim));
|
||
border: 1px solid color-mix(in srgb, var(--card-accent, var(--esp32)) 30%, transparent);
|
||
}
|
||
.card-head-btn { margin-left: auto; padding: 4px 10px; position: relative; z-index: 2; }
|
||
.card-body { padding: 17px 18px; }
|
||
.card.collapsed .card-body { display: none; }
|
||
.card-head .collapse-arrow {
|
||
margin-left: auto; font-size: 10px; color: var(--text-label);
|
||
transition: transform .2s;
|
||
}
|
||
.card.collapsed .collapse-arrow { transform: rotate(-90deg); }
|
||
|
||
/* ================= 表单 ================= */
|
||
.form-row { margin-bottom: 14px; }
|
||
.form-row:last-child { margin-bottom: 0; }
|
||
.form-label {
|
||
display: block;
|
||
font-family: var(--font-display);
|
||
font-size: 11px; color: var(--text-label);
|
||
text-transform: uppercase; letter-spacing: .12em;
|
||
margin-bottom: 7px;
|
||
}
|
||
.input, select, textarea {
|
||
width: 100%; padding: 10px 13px;
|
||
font-size: 13px; font-family: var(--font-mono);
|
||
background: var(--bg-input); color: var(--text);
|
||
border: 1px solid var(--border); border-radius: var(--radius-sm);
|
||
outline: none;
|
||
transition: border-color .18s, box-shadow .18s, background .18s;
|
||
}
|
||
.input::placeholder { color: var(--text-label); }
|
||
.input:focus, select:focus, textarea:focus {
|
||
border-color: var(--esp32);
|
||
background: color-mix(in srgb, var(--esp32) 5%, var(--bg-input));
|
||
box-shadow: 0 0 0 3px var(--esp32-dim);
|
||
}
|
||
select { cursor: pointer; }
|
||
select option { background: var(--bg-panel); color: var(--text); }
|
||
.input-group { display: flex; gap: 8px; }
|
||
.input-group .input { flex: 1; }
|
||
|
||
/* ================= 按钮 ================= */
|
||
/* 共享 .btn chrome(OTA/CAN 等页)。电机页主题按钮在 motor.css,勿互相复制。 */
|
||
.btn {
|
||
|
||
display: inline-flex; align-items: center; justify-content: center; gap: 7px;
|
||
padding: 9px 17px; border: none; border-radius: var(--radius-sm);
|
||
font-family: var(--font-display);
|
||
font-size: 13px; font-weight: 600; letter-spacing: .03em;
|
||
cursor: pointer; white-space: nowrap;
|
||
transition: transform .16s, box-shadow .2s, background .2s, border-color .2s, color .2s, opacity .2s;
|
||
}
|
||
.btn:hover:not(:disabled) { transform: translateY(-1px); }
|
||
.btn:active:not(:disabled) { transform: translateY(0) scale(.97); }
|
||
.btn:disabled { opacity: .38; cursor: not-allowed; transform: none; }
|
||
|
||
/* 主操作 = ESP32 青绿 */
|
||
.btn-primary {
|
||
background: linear-gradient(135deg, var(--esp32) 0%, #14b8a6 100%);
|
||
color: #04231e;
|
||
box-shadow: 0 4px 16px rgba(47,216,193,.28), inset 0 1px 0 rgba(255,255,255,.25);
|
||
}
|
||
.btn-primary:hover:not(:disabled) {
|
||
box-shadow: 0 6px 22px rgba(47,216,193,.4), inset 0 1px 0 rgba(255,255,255,.3);
|
||
}
|
||
.btn-success {
|
||
background: linear-gradient(135deg, var(--green) 0%, #16a374 100%);
|
||
color: #03231a;
|
||
box-shadow: 0 4px 16px rgba(61,220,142,.25), inset 0 1px 0 rgba(255,255,255,.22);
|
||
}
|
||
.btn-danger {
|
||
background: linear-gradient(135deg, var(--red) 0%, #dc4c4c 100%);
|
||
color: #fff;
|
||
box-shadow: 0 4px 16px rgba(255,107,107,.25), inset 0 1px 0 rgba(255,255,255,.2);
|
||
}
|
||
.btn-outline {
|
||
background: rgba(255,255,255,.02); color: var(--text-dim);
|
||
border: 1px solid var(--border-strong);
|
||
}
|
||
.btn-outline:hover:not(:disabled) {
|
||
background: var(--bg-hover); color: var(--text);
|
||
border-color: #3d5a84;
|
||
}
|
||
.btn-ghost { background: transparent; color: var(--text-dim); }
|
||
.btn-ghost:hover:not(:disabled) { background: var(--bg-hover); color: var(--text); }
|
||
.btn-block { width: 100%; justify-content: center; }
|
||
.btn-sm { padding: 6px 12px; font-size: 12px; }
|
||
|
||
/* ---- 多色子系统页签(关键)----
|
||
console-mode.js 用 btn-primary / btn-outline 表达"选中/未选中",
|
||
这里按按钮 id 把"选中态"染成各自子系统色:
|
||
WiFi=青绿 · BLE=蓝 · ESP32=青绿 · GD32=琥珀。 */
|
||
#modeBleBtn.btn-primary {
|
||
background: linear-gradient(135deg, var(--ble) 0%, #3b82f6 100%);
|
||
color: #04142b;
|
||
box-shadow: 0 4px 16px rgba(95,168,255,.3), inset 0 1px 0 rgba(255,255,255,.25);
|
||
}
|
||
#modeEcatBtn.btn-primary {
|
||
background: linear-gradient(135deg, #8b5cf6 0%, #6366f1 100%);
|
||
color: #0f0a1f;
|
||
box-shadow: 0 4px 16px rgba(139,92,246,.3), inset 0 1px 0 rgba(255,255,255,.25);
|
||
}
|
||
#modeWifiBtn.btn-outline {
|
||
border-color: rgba(47,216,193,.45);
|
||
color: var(--esp32);
|
||
}
|
||
#modeBleBtn.btn-outline {
|
||
border-color: rgba(95,168,255,.45);
|
||
color: var(--ble);
|
||
}
|
||
#modeEcatBtn.btn-outline {
|
||
border-color: rgba(139,92,246,.45);
|
||
color: #a78bfa;
|
||
}
|
||
#modeWifiBtn.btn-outline:hover:not(:disabled) {
|
||
border-color: var(--esp32);
|
||
background: rgba(47,216,193,.08);
|
||
color: var(--esp32);
|
||
}
|
||
#modeBleBtn.btn-outline:hover:not(:disabled) {
|
||
border-color: var(--ble);
|
||
background: rgba(95,168,255,.08);
|
||
color: var(--ble);
|
||
}
|
||
#modeEcatBtn.btn-outline:hover:not(:disabled) {
|
||
border-color: #8b5cf6;
|
||
background: rgba(139,92,246,.08);
|
||
color: #a78bfa;
|
||
}
|
||
|
||
/* 升级目标:左右两个等宽扁按钮(GD32 琥珀 · ESP32 青绿) */
|
||
.target-tab-row {
|
||
display: flex;
|
||
gap: 8px;
|
||
margin-bottom: 14px;
|
||
}
|
||
.target-tab-btn {
|
||
flex: 1 1 0;
|
||
min-width: 0;
|
||
min-height: 40px;
|
||
padding: 10px 14px;
|
||
font-size: 14px;
|
||
font-weight: 700;
|
||
letter-spacing: .04em;
|
||
flex-direction: row;
|
||
gap: 8px;
|
||
border-radius: var(--radius-sm);
|
||
}
|
||
.target-tab-btn .target-tab-ico {
|
||
font-size: 15px;
|
||
line-height: 1;
|
||
opacity: .9;
|
||
}
|
||
.target-tab-btn .target-tab-txt {
|
||
line-height: 1.1;
|
||
}
|
||
.target-tab-btn.btn-outline {
|
||
border-width: 1.5px;
|
||
background: rgba(255,255,255,.03);
|
||
}
|
||
#targetGd32Tab.btn-primary {
|
||
background: linear-gradient(135deg, var(--gd32) 0%, #f59e0b 100%);
|
||
color: #2b1d02;
|
||
box-shadow: 0 4px 16px rgba(252,191,63,.3), inset 0 1px 0 rgba(255,255,255,.3);
|
||
}
|
||
#targetEsp32Tab.btn-primary {
|
||
background: linear-gradient(135deg, var(--esp32) 0%, #14b8a6 100%);
|
||
color: #04231e;
|
||
box-shadow: 0 4px 16px rgba(47,216,193,.28), inset 0 1px 0 rgba(255,255,255,.25);
|
||
}
|
||
/* 未选中时用各自子系统的淡描边,避免两个灰按钮看不出身份 */
|
||
#targetGd32Tab.btn-outline {
|
||
border-color: rgba(252,191,63,.45);
|
||
color: var(--gd32);
|
||
}
|
||
#targetEsp32Tab.btn-outline {
|
||
border-color: rgba(47,216,193,.45);
|
||
color: var(--esp32);
|
||
}
|
||
#targetGd32Tab.btn-outline:hover:not(:disabled) {
|
||
border-color: var(--gd32);
|
||
background: rgba(252,191,63,.08);
|
||
color: var(--gd32);
|
||
}
|
||
#targetEsp32Tab.btn-outline:hover:not(:disabled) {
|
||
border-color: var(--esp32);
|
||
background: rgba(47,216,193,.08);
|
||
color: var(--esp32);
|
||
}
|
||
#ppEcatOta.active {
|
||
color: #2b1d02;
|
||
background: linear-gradient(135deg, var(--gd32), #f59e0b);
|
||
box-shadow: 0 2px 12px rgba(252,191,63,.35);
|
||
}
|
||
|
||
/* EtherCAT 连接说明 + 探测:与卡片内其他控件同一套字重/字距 */
|
||
.ecat-mode-note {
|
||
margin: 0 0 12px;
|
||
padding: 10px 12px;
|
||
border-radius: var(--radius-sm);
|
||
border: 1px solid var(--border-subtle);
|
||
background: rgba(252,191,63,.06);
|
||
font-size: 12px;
|
||
line-height: 1.7;
|
||
color: var(--text-dim);
|
||
}
|
||
.ecat-mode-note b {
|
||
color: var(--gd32);
|
||
font-weight: 600;
|
||
}
|
||
#bootEcatProbeBtn {
|
||
margin-bottom: 10px;
|
||
border-color: rgba(252,191,63,.4);
|
||
color: var(--gd32);
|
||
background: rgba(252,191,63,.05);
|
||
}
|
||
#bootEcatProbeBtn:hover:not(:disabled) {
|
||
border-color: var(--gd32);
|
||
background: rgba(252,191,63,.12);
|
||
color: var(--gd32-hi);
|
||
}
|
||
|
||
/* ---- APP ↔ BOOT 跳转控制台 ---- */
|
||
.jump-role-panel {
|
||
display: grid;
|
||
grid-template-columns: 1fr;
|
||
gap: 10px;
|
||
margin-bottom: 12px;
|
||
}
|
||
@media (min-width: 420px) {
|
||
.jump-role-panel { grid-template-columns: 140px 1fr; align-items: stretch; }
|
||
}
|
||
.jump-role-badge {
|
||
display: flex; flex-direction: column; justify-content: center; align-items: center;
|
||
gap: 2px; min-height: 92px; padding: 12px 10px;
|
||
border-radius: 12px; border: 1px solid var(--border);
|
||
background: var(--bg-elevated); text-align: center;
|
||
transition: border-color .2s, background .2s, box-shadow .2s;
|
||
cursor: pointer; user-select: none;
|
||
}
|
||
.jump-role-badge:hover {
|
||
border-color: var(--gd32);
|
||
box-shadow: 0 0 0 3px rgba(252,191,63,.12);
|
||
}
|
||
.jump-role-badge:active { transform: scale(0.98); }
|
||
.jump-role-badge .jump-role-label {
|
||
font-family: var(--font-display); font-size: 10px; letter-spacing: .12em;
|
||
text-transform: uppercase; color: var(--text-label);
|
||
}
|
||
.jump-role-badge strong {
|
||
font-family: var(--font-display); font-size: 18px; font-weight: 700;
|
||
letter-spacing: .04em; color: var(--text);
|
||
}
|
||
.jump-role-badge .jump-role-sw {
|
||
font-family: var(--font-mono); font-size: 11px; color: var(--text-dim);
|
||
}
|
||
.jump-role-badge[data-role="app"] {
|
||
border-color: rgba(47,216,193,.55);
|
||
background: rgba(47,216,193,.1);
|
||
box-shadow: 0 0 0 3px rgba(47,216,193,.08);
|
||
}
|
||
.jump-role-badge[data-role="app"] strong { color: var(--esp32); }
|
||
.jump-role-badge[data-role="boot"] {
|
||
border-color: rgba(252,191,63,.6);
|
||
background: rgba(252,191,63,.12);
|
||
box-shadow: 0 0 0 3px rgba(252,191,63,.1);
|
||
}
|
||
.jump-role-badge[data-role="boot"] strong { color: var(--gd32); }
|
||
.jump-role-badge[data-role="unknown"] strong { color: var(--text-dim); font-size: 15px; }
|
||
.jump-role-meta {
|
||
display: grid; grid-template-columns: 1fr 1fr; gap: 6px 10px;
|
||
font-size: 12px;
|
||
}
|
||
.jump-role-meta > div {
|
||
display: flex; flex-direction: column; gap: 2px; min-width: 0;
|
||
}
|
||
.jump-role-meta span {
|
||
color: var(--text-label); font-family: var(--font-display);
|
||
font-size: 10px; letter-spacing: .08em; text-transform: uppercase;
|
||
}
|
||
.jump-role-meta b {
|
||
font-family: var(--font-mono); font-weight: 600; color: var(--text);
|
||
overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
|
||
}
|
||
.jump-action-row {
|
||
display: grid; grid-template-columns: 88px 1fr; gap: 8px; margin-top: 4px;
|
||
}
|
||
.jump-btn-primary {
|
||
min-height: 44px;
|
||
background: linear-gradient(135deg, var(--gd32) 0%, #f59e0b 100%);
|
||
color: #2b1d02 !important; font-weight: 700;
|
||
box-shadow: 0 4px 14px rgba(252,191,63,.28);
|
||
}
|
||
.jump-btn-primary:hover:not(:disabled) {
|
||
filter: brightness(1.05);
|
||
color: #2b1d02 !important;
|
||
}
|
||
.jump-btn-secondary { min-height: 44px; }
|
||
.jump-btn-test {
|
||
margin-top: 8px; min-height: 40px;
|
||
border-color: rgba(252,191,63,.35); color: var(--gd32);
|
||
background: transparent;
|
||
}
|
||
.jump-btn-test:hover:not(:disabled) {
|
||
background: rgba(252,191,63,.1); border-color: var(--gd32);
|
||
}
|
||
.jump-btn-test:disabled { opacity: .45; cursor: not-allowed; }
|
||
|
||
.jump-history {
|
||
margin-top: 12px; border: 1px solid var(--border-subtle);
|
||
border-radius: var(--radius-sm); background: var(--bg-card);
|
||
overflow: hidden;
|
||
}
|
||
.jump-history-head {
|
||
padding: 8px 12px; border-bottom: 1px solid var(--border-subtle);
|
||
font-family: var(--font-display); font-size: 11px; letter-spacing: .1em;
|
||
text-transform: uppercase; color: var(--text-label);
|
||
}
|
||
.jump-history-list {
|
||
max-height: 148px; overflow-y: auto; padding: 6px 0;
|
||
}
|
||
.jump-history-empty {
|
||
padding: 14px 12px; font-size: 12px; color: var(--text-dim); text-align: center;
|
||
}
|
||
.jump-history-item {
|
||
display: flex; align-items: flex-start; gap: 8px;
|
||
padding: 6px 12px; font-size: 12px; line-height: 1.45;
|
||
font-family: var(--font-mono);
|
||
}
|
||
.jump-history-item + .jump-history-item { border-top: 1px dashed var(--border-subtle); }
|
||
.jump-history-item .jh-tag {
|
||
flex-shrink: 0; min-width: 42px; text-align: center;
|
||
padding: 1px 6px; border-radius: 999px; font-size: 10px; font-weight: 700;
|
||
background: var(--bg-input); color: var(--text-dim);
|
||
}
|
||
.jump-history-item.ok .jh-tag { background: rgba(61,220,142,.18); color: var(--can-hi); }
|
||
.jump-history-item.err .jh-tag { background: rgba(255,107,107,.16); color: var(--red); }
|
||
.jump-history-item.info .jh-tag { background: rgba(47,216,193,.14); color: var(--esp32); }
|
||
.jump-history-item .jh-msg { flex: 1; color: var(--text); word-break: break-all; }
|
||
.jump-history-item .jh-time {
|
||
flex-shrink: 0; color: var(--text-dim); font-size: 10px;
|
||
}
|
||
|
||
/* GD32 OTA 大按钮 = 琥珀(区别于 ESP32 青绿) */
|
||
#uploadGd32Btn {
|
||
background: linear-gradient(135deg, var(--gd32) 0%, #f59e0b 100%);
|
||
color: #2b1d02;
|
||
box-shadow: 0 6px 20px rgba(252,191,63,.3), inset 0 1px 0 rgba(255,255,255,.3);
|
||
}
|
||
#bootEcatRunBtn {
|
||
background: linear-gradient(135deg, var(--gd32) 0%, #f59e0b 100%);
|
||
color: #2b1d02;
|
||
box-shadow: 0 6px 20px rgba(252,191,63,.3), inset 0 1px 0 rgba(255,255,255,.3);
|
||
}
|
||
#bootEcatRunBtn:disabled {
|
||
opacity: .38;
|
||
}
|
||
#uploadEsp32Btn {
|
||
box-shadow: 0 6px 20px rgba(47,216,193,.32), inset 0 1px 0 rgba(255,255,255,.28);
|
||
}
|
||
|
||
/* ================= 连接状态条 / 提示 ================= */
|
||
.conn-indicator {
|
||
display: flex; align-items: center; gap: 10px;
|
||
padding: 12px 16px; border-radius: var(--radius-sm);
|
||
background: var(--bg-elevated); border: 1px solid var(--border);
|
||
font-size: 13px; font-weight: 500;
|
||
}
|
||
.conn-indicator .light { width: 10px; height: 10px; border-radius: 50%; flex-shrink: 0; background: var(--text-label); }
|
||
.conn-indicator.ok .light { background: var(--green); box-shadow: 0 0 8px rgba(61,220,142,.6); }
|
||
.conn-indicator.err .light { background: var(--red); box-shadow: 0 0 8px rgba(255,107,107,.5); }
|
||
.conn-indicator.warn .light { background: var(--amber); box-shadow: 0 0 8px rgba(252,191,63,.45); }
|
||
|
||
.helper-note {
|
||
margin-top: 10px; padding: 10px 13px;
|
||
border-radius: var(--radius-sm);
|
||
border: 1px solid var(--border);
|
||
background: var(--bg-elevated);
|
||
font-size: 12px; line-height: 1.65; color: var(--text-dim);
|
||
}
|
||
.helper-note.ok { border-color: rgba(61,220,142,.3); background: rgba(61,220,142,.07); color: #a9f0c6; }
|
||
.helper-note.warn { border-color: rgba(252,191,63,.3); background: rgba(252,191,63,.07); color: #fbe3ae; }
|
||
.helper-note.err { border-color: rgba(255,107,107,.3); background: rgba(255,107,107,.07); color: #ffc4c4; }
|
||
.helper-note code { color: var(--esp32-hi); font-family: var(--font-mono); }
|
||
|
||
/* ================= 右侧滑出抽屉:堆与任务栈 ================= */
|
||
.sys-drawer {
|
||
--sys-drawer-panel-w: min(390px, calc(100vw - 48px));
|
||
--sys-drawer-peek: 38px;
|
||
position: fixed; top: 76px; right: 0; z-index: 80;
|
||
width: calc(var(--sys-drawer-panel-w) + var(--sys-drawer-peek));
|
||
height: calc(100vh - 92px); max-height: calc(100vh - 92px);
|
||
display: flex; flex-direction: row; align-items: stretch;
|
||
transform: translateX(var(--sys-drawer-panel-w));
|
||
transition: transform .3s cubic-bezier(.22, 1, .36, 1);
|
||
filter: drop-shadow(-8px 0 24px rgba(2,5,12,.5));
|
||
}
|
||
.sys-drawer:hover, .sys-drawer:focus-within { transform: translateX(0); }
|
||
.sys-drawer-rail {
|
||
flex: 0 0 var(--sys-drawer-peek); width: var(--sys-drawer-peek);
|
||
display: flex; flex-direction: column; align-items: center; justify-content: center;
|
||
gap: 12px; padding: 14px 4px;
|
||
background: linear-gradient(180deg, var(--bg-elevated) 0%, var(--bg-card) 100%);
|
||
border: 1px solid var(--border); border-right: none;
|
||
border-radius: var(--radius) 0 0 var(--radius);
|
||
cursor: default;
|
||
}
|
||
.sys-drawer-rail-ico { font-size: 16px; line-height: 1; }
|
||
.sys-drawer-rail-text {
|
||
writing-mode: vertical-rl; text-orientation: mixed;
|
||
font-family: var(--font-display);
|
||
font-size: 11px; font-weight: 600; letter-spacing: .18em;
|
||
color: var(--text-dim);
|
||
}
|
||
.sys-drawer:hover .sys-drawer-rail-text,
|
||
.sys-drawer:focus-within .sys-drawer-rail-text { color: var(--mem-hi); }
|
||
.sys-drawer-panel {
|
||
flex: 1 1 var(--sys-drawer-panel-w);
|
||
width: var(--sys-drawer-panel-w); min-width: 0; height: 100%;
|
||
margin: 0 !important;
|
||
display: flex; flex-direction: column;
|
||
border-radius: 0; overflow: hidden;
|
||
background: var(--bg-card);
|
||
border: 1px solid var(--border); border-left: none; border-right: none;
|
||
}
|
||
.sys-drawer-head { cursor: default; flex-shrink: 0; }
|
||
.sys-drawer-head .card-head-btn { margin-left: auto; }
|
||
.sys-drawer-body { flex: 1; min-height: 0; overflow-y: auto; overscroll-behavior: contain; }
|