:root{
  --bg:#0f1419; --panel:#171d25; --line:#2a3441; --fg:#e6edf3; --muted:#8b98a5;
  --accent:#3b82f6; --ok:#22c55e; --warn:#f59e0b; --danger:#ef4444;
}
*{box-sizing:border-box}
body{
  margin:0; background:var(--bg); color:var(--fg);
  font:14px/1.5 -apple-system,"Segoe UI","Microsoft YaHei",system-ui,sans-serif;
}
header{
  display:flex; align-items:center; justify-content:space-between; gap:16px;
  padding:14px 20px; border-bottom:1px solid var(--line); background:var(--panel);
}
h1{font-size:17px; margin:0; font-weight:600}
h2{font-size:14px; margin:22px 0 10px; color:var(--muted); font-weight:600}
.muted{color:var(--muted); font-size:12px}
.badge{padding:2px 9px; border-radius:999px; font-size:12px}
.badge.ok{background:rgba(34,197,94,.15); color:var(--ok)}
.badge.bad{background:rgba(239,68,68,.15); color:var(--danger)}

/* 右上角语言切换 */
.lang-switch{display:flex; gap:2px; margin-left:10px}
.lang-switch button{
  background:transparent; border:1px solid var(--line); color:var(--muted);
  padding:3px 10px; border-radius:6px; cursor:pointer; font-size:12px; line-height:1.4;
}
.lang-switch button.active{
  border-color:var(--accent); color:var(--accent); background:rgba(59,130,246,.12);
}

.tabs{display:flex; gap:2px; padding:10px 20px 0}
.tab{
  background:transparent; border:1px solid var(--line); border-bottom:none;
  color:var(--muted); padding:8px 18px; border-radius:8px 8px 0 0; cursor:pointer;
}
.tab.active{background:var(--panel); color:var(--fg); border-color:var(--line)}

/* 串口栏 */
.port-bar{
  display:flex; align-items:center; gap:8px; flex-wrap:wrap;
  padding:10px 20px; border-bottom:1px solid var(--line); background:#131922;
}
.port-bar > .muted{white-space:nowrap; flex-shrink:0}
.port-bar select{
  background:var(--panel); color:var(--fg); border:1px solid var(--line);
  border-radius:8px; padding:6px 10px; font-size:13px; min-width:240px; max-width:420px;
  font-family:ui-monospace,monospace;
}
.port-bar select:disabled{opacity:.6}
.port-bar button{
  background:transparent; border:1px solid var(--line); color:var(--fg);
  padding:6px 14px; border-radius:8px; cursor:pointer; font-size:13px; white-space:nowrap;
}
.port-bar button.primary{border-color:var(--accent); color:var(--accent)}
.port-bar button.warn{border-color:var(--warn); color:var(--warn)}
.port-bar button.ghost{color:var(--muted)}
.port-bar button:disabled{opacity:.4; cursor:not-allowed}
.port-bar #port-state{font-size:12px}
/* 串口栏里给「控制对象」分个段 */
.bar-sep{ width:1px; height:20px; background:var(--line); margin:0 4px }

.panel{
  margin:0 20px 20px; padding:18px; background:var(--panel);
  border:1px solid var(--line); border-radius:0 10px 10px 10px;
}
.hidden{display:none}

.hand-switch{display:flex; align-items:center; gap:10px; margin-bottom:18px; flex-wrap:wrap}
.targets{display:flex; gap:6px}
.targets .target{
  background:transparent; border:1px solid var(--line); color:var(--muted);
  padding:6px 18px; border-radius:8px; cursor:pointer;
  white-space:nowrap; flex-shrink:0; font-size:13px;
}
.targets .target.active{
  background:rgba(59,130,246,.15); color:var(--accent); border-color:var(--accent);
}
.hand-switch > .muted{white-space:nowrap; flex-shrink:0}
.hand-switch #hand-meta{white-space:normal; min-width:0}

.fingers{display:grid; grid-template-columns:repeat(auto-fit,minmax(240px,1fr)); gap:16px}
.finger{border:1px solid var(--line); border-radius:10px; padding:12px}
.finger h3{margin:0 0 10px; font-size:13px; display:flex; justify-content:space-between}
.finger h3 .ids{color:var(--muted); font-weight:400; font-size:11px; font-family:ui-monospace,monospace}
.joint{margin-bottom:10px}
.joint label{display:flex; justify-content:space-between; font-size:12px; color:var(--muted)}
.joint label b{color:var(--fg); font-family:ui-monospace,monospace}
.joint input[type=range]{width:100%; accent-color:var(--accent); margin-top:2px}

.gestures{display:flex; flex-wrap:wrap; gap:8px}
.gestures button{
  background:transparent; border:1px solid var(--line); color:var(--fg);
  padding:7px 14px; border-radius:8px; cursor:pointer;
}
.gestures button:hover{border-color:var(--accent); color:var(--accent)}

.actions{display:flex; flex-wrap:wrap; gap:10px}
button.primary,.gestures button,.actions button{
  background:transparent; border:1px solid var(--line); color:var(--fg);
  padding:8px 16px; border-radius:8px; cursor:pointer; font-size:13px;
}
button.primary{border-color:var(--accent); color:var(--accent)}
button.warn{border-color:var(--warn); color:var(--warn)}
button.danger{border-color:var(--danger); color:var(--danger)}
button:disabled{opacity:.45; cursor:not-allowed}

/* 摄像头面板 */
.cam-toolbar{
  display:flex; align-items:center; gap:8px; flex-wrap:wrap; margin:14px 0 12px;
}
.cam-toolbar > .muted{white-space:nowrap; flex-shrink:0}
.cam-toolbar .nowrap{white-space:nowrap}
.cam-toolbar select{
  background:var(--panel); color:var(--fg); border:1px solid var(--line);
  border-radius:8px; padding:6px 10px; font-size:13px; min-width:200px; max-width:340px;
}
.cam-toolbar button{
  background:transparent; border:1px solid var(--line); color:var(--fg);
  padding:6px 16px; border-radius:8px; cursor:pointer; font-size:13px; white-space:nowrap;
}
.cam-toolbar button.primary{border-color:var(--accent); color:var(--accent)}
.cam-toolbar button.warn{border-color:var(--warn); color:var(--warn)}
.cam-toolbar button.ghost{color:var(--muted)}
.cam-toolbar button:disabled{opacity:.4; cursor:not-allowed}
.cam-toolbar input[type=range]{ width:130px; accent-color:var(--accent) }
/* 骨骼颜色图例 */
.legend{ display:flex; align-items:center; gap:9px }
.legend > span{ display:flex; align-items:center; gap:4px }
.legend i{ width:14px; height:3px; border-radius:2px }
/* 不设 max-width：跟着面板走，窄窗口自然换行，宽窗口不白白留一片空 */
.cam-hint{ margin:-4px 0 12px; line-height:1.6 }

/* 采集：三个姿势各一个按钮 + 进度条 */
.cal-buttons{ display:flex; gap:6px; flex-wrap:wrap }
.cal-buttons button{
  background:transparent; border:1px solid var(--line); color:var(--muted);
  padding:5px 12px; border-radius:8px; cursor:pointer; font-size:12px; white-space:nowrap;
}
.cal-buttons button.done{ border-color:var(--ok); color:var(--ok) }
.cal-buttons button.busy{ border-color:var(--warn); color:var(--warn) }
.cal-buttons button:disabled{ opacity:.45; cursor:not-allowed }
.cal-step{ color:var(--fg); font-size:13px }
.cal-bar{
  flex:1 1 140px; min-width:100px; height:6px; border-radius:999px;
  background:#0b0f14; border:1px solid var(--line); overflow:hidden;
}
.cal-bar > i{ display:block; height:100%; width:0%; background:var(--accent); transition:width .12s linear }

.cam-stage{display:grid; grid-template-columns:minmax(0,720px) minmax(180px,1fr); gap:18px; align-items:start}
@media (max-width:900px){ .cam-stage{grid-template-columns:1fr} }

.video-wrap{
  position:relative; width:100%; aspect-ratio:4/3; border-radius:10px;
  background:#0b0f14; border:1px solid var(--line); overflow:hidden;
}
.video-wrap video, .video-wrap canvas{
  position:absolute; inset:0; width:100%; height:100%; display:block;
}
.video-wrap canvas{ pointer-events:none }
/* 未启动时藏掉视频，免得留一块黑框让人以为坏了 */
.video-wrap.idle video, .video-wrap.idle canvas{ visibility:hidden }

.cam-placeholder{
  position:absolute; inset:0; display:none;
  flex-direction:column; align-items:center; justify-content:center; gap:6px;
  color:var(--muted); text-align:center; padding:20px;
}
.video-wrap.idle .cam-placeholder{ display:flex }
.cam-placeholder svg{ width:46px; height:46px; opacity:.5; margin-bottom:4px }
.cam-placeholder p{ margin:0; font-size:13px }

.cam-status{
  border:1px solid var(--line); border-radius:10px; padding:12px 14px;
  font-size:13px; min-width:0;
}
.cam-status .row{ display:flex; justify-content:space-between; gap:10px; padding:5px 0 }
.cam-status .row span{ color:var(--muted); white-space:nowrap }
.cam-status .row b{
  font-weight:500; font-family:ui-monospace,monospace; text-align:right;
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap;
}

.track-out{
  font-family:ui-monospace,monospace; font-size:12px; color:var(--muted);
  white-space:pre-wrap; margin:14px 0 0; min-height:1.5em;
}
footer{padding:0 20px 28px}
footer .muted{line-height:1.7}
