:root { --bg: #0a0c0e; --panel: #111417; --panel2: #0d1013; --border: #1f2428; --accent: #00e5ff; --accent2: #ff3d71; --warn: #ffaa00; --ok: #00e096; /* updated to match theme-dark overrides, so auto:dark equals manual dark */ --dim: #7a8490; --text: #f0f2f5; --label: #9faab7; --mono: 'Share Tech Mono', monospace; --sans: 'Barlow Condensed', sans-serif; --logo-color: #ffffff; /* Component tokens */ --header-bg: rgba(10,12,14,0.96); --scanline: rgba(0,0,0,0.07); --hover-desc-color: rgba(10,12,14,0.65); /* Canvas */ --canvas-bg: #0d1013; --canvas-fade: rgba(13,16,19,0.25); --canvas-grid: rgba(31,36,40,0.6); --canvas-center: rgba(58,64,80,0.5); --canvas-idle-text: rgba(90,100,128,0.7); --trail-rgb: 0,229,255; --trail-idle-rgb: 58,64,80; --canvas-dot: #00e5ff; --canvas-dot-idle: #3a4050; --canvas-dot-glow: rgba(0,229,255,0.35); /* Tap flashes */ --tap-left: rgba(0,229,255,0.35); --tap-right: rgba(255,61,113,0.35); } /* ── Light theme (explicit) ──────────────────────────────────────────────── */ :root.theme-light { --bg: #f0f2f5; --panel: #ffffff; --panel2: #e8eaed; --border: #b8bec8; --accent: #006699; --accent2: #c01a50; --warn: #b36a00; --ok: #007040; --dim: #848ea4; --text: #0f1118; --label: #4e566e; --logo-color: #0f1118; --header-bg: rgba(240,242,245,0.96); --scanline: rgba(0,0,0,0.03); --hover-desc-color: rgba(240,242,245,0.7); --canvas-bg: #e8eaed; --canvas-fade: rgba(232,234,237,0.35); --canvas-grid: rgba(195,200,210,0.7); --canvas-center: rgba(155,162,178,0.6); --canvas-idle-text: rgba(100,112,140,0.8); --trail-rgb: 0,100,170; --trail-idle-rgb: 155,162,178; --canvas-dot: #0077aa; --canvas-dot-idle: #a8b0c0; --canvas-dot-glow: rgba(0,100,170,0.3); --tap-left: rgba(0,100,170,0.35); --tap-right: rgba(200,30,80,0.35); } /* ── Auto light (OS hint; explicit class overrides) ──────────────────────── */ @media (prefers-color-scheme: light) { :root:not(.theme-dark) { --bg: #f0f2f5; --panel: #ffffff; --panel2: #e8eaed; --border: #b8bec8; --accent: #006699; --accent2: #c01a50; --warn: #b36a00; --ok: #007040; --dim: #848ea4; --text: #0f1118; --label: #4e566e; --logo-color: #0f1118; --header-bg: rgba(240,242,245,0.96); --scanline: rgba(0,0,0,0.03); --hover-desc-color: rgba(240,242,245,0.7); --canvas-bg: #e8eaed; --canvas-fade: rgba(232,234,237,0.35); --canvas-grid: rgba(195,200,210,0.7); --canvas-center: rgba(155,162,178,0.6); --canvas-idle-text: rgba(100,112,140,0.8); --trail-rgb: 0,100,170; --trail-idle-rgb: 155,162,178; --canvas-dot: #0077aa; --canvas-dot-idle: #a8b0c0; --canvas-dot-glow: rgba(0,100,170,0.3); --tap-left: rgba(0,100,170,0.35); --tap-right: rgba(200,30,80,0.35); } } * { box-sizing:border-box; margin:0; padding:0; } body { background:var(--bg); color:var(--text); font-family:var(--mono); min-height:100vh; overflow-x:hidden; } body::before { content:''; position:fixed; inset:0; pointer-events:none; z-index:9999; background:repeating-linear-gradient(0deg,transparent,transparent 2px,var(--scanline) 2px,var(--scanline) 4px); } header { border-bottom:1px solid var(--border); padding:16px 28px; display:flex; align-items:center; gap:20px; position:sticky; top:0; background:var(--header-bg); backdrop-filter:blur(10px); z-index:100; } .logo { font-family:var(--sans); font-weight:900; font-size:22px; letter-spacing:0.08em; color:var(--logo-color); text-transform:uppercase; line-height:1; } .logo span { color:var(--accent); } .logo-sub { font-size:10px; color:var(--label); letter-spacing:0.25em; text-transform:uppercase; margin-top:3px; } .header-right { margin-left:auto; display:flex; align-items:center; gap:10px; flex-wrap:wrap; justify-content:flex-end; } .status-pill { display:flex; align-items:center; gap:8px; height:34px; padding:0 14px; border:1px solid var(--border); font-size:11px; letter-spacing:0.15em; text-transform:uppercase; color:var(--label); transition:all 0.3s; white-space:nowrap; } .status-pill.connected { border-color:var(--ok); color:var(--ok); } .status-pill.connecting { border-color:var(--warn); color:var(--warn); } .dot { width:7px; height:7px; border-radius:50%; background:var(--dim); flex-shrink:0; } .connected .dot { background:var(--ok); box-shadow:0 0 8px var(--ok); animation:pulse 2s infinite; } .connecting .dot { background:var(--warn); box-shadow:0 0 8px var(--warn); animation:pulse 0.8s infinite; } @keyframes pulse { 0%,100%{opacity:1}50%{opacity:0.3} } @keyframes chgpulse { 0%,100%{opacity:1}50%{opacity:0.5} } .btn { font-family:var(--sans); font-weight:700; font-size:13px; letter-spacing:0.15em; text-transform:uppercase; background:transparent; padding:8px 18px; cursor:pointer; transition:all 0.2s; position:relative; overflow:hidden; white-space:nowrap; } .btn-connect { border:1px solid var(--accent); color:var(--accent); } .btn-disconnect { border:1px solid var(--accent2); color:var(--accent2); } .btn::before { content:''; position:absolute; inset:0; transform:scaleX(0); transform-origin:left; transition:transform 0.2s; } .btn-connect::before { background:var(--accent); } .btn-disconnect::before { background:var(--accent2); } .btn:hover::before { transform:scaleX(1); } .btn:hover { color:var(--bg); } .btn span { position:relative; z-index:1; } .btn:disabled { border-color:var(--dim); color:var(--dim); cursor:not-allowed; } .btn:disabled::before { display:none; } .btn:disabled:hover { color:var(--dim); } .btn-debug { border:1px solid var(--dim); color:var(--label); min-width:52px; text-align:center; font-size:10px; height:34px; padding:0 10px; } .btn-debug::before { background:var(--accent); } .btn-theme { border:1px solid var(--dim); color:var(--label); min-width:72px; text-align:center; } .btn-theme::before { background:var(--text); } .batt-bar { display:flex; align-items:center; gap:8px; font-size:11px; color:var(--label); } .batt-cells { display:flex; gap:2px; } .batt-cell { width:9px; height:15px; border:1px solid var(--dim); background:transparent; transition:background 0.3s; } .batt-cell.f { background:var(--ok); border-color:var(--ok); } .batt-cell.f.warn { background:var(--warn); border-color:var(--warn); } .batt-cell.f.crit { background:var(--accent2); border-color:var(--accent2); } .batt-cell.f.charging { background:var(--accent); border-color:var(--accent); animation:chgpulse 1.2s ease-in-out infinite; } .chg-badge { display:none; align-items:center; gap:4px; padding:3px 8px; font-size:10px; letter-spacing:0.15em; text-transform:uppercase; white-space:nowrap; border:1px solid; } .chg-badge.charging { border-color:var(--accent); color:var(--accent); animation:chgpulse 1.6s ease-in-out infinite; } .chg-badge.full { border-color:var(--ok); color:var(--ok); } .chg-badge.show { display:flex; } main { max-width:1440px; margin:0 auto; padding:32px 20px 80px; display:grid; grid-template-columns:1fr 1fr 380px; gap:16px; align-items:start; } .col-left { display:grid; gap:12px; } .col-mid { display:grid; gap:12px; } .col-right { display:grid; gap:12px; position:sticky; top:80px; } /* ── XIAO pin diagram ─────────────────────────────────────── */ .xiao-wrap { display:flex; flex-direction:column; align-items:center; padding:8px 0 14px; } .pin-legend { display:flex; gap:20px; justify-content:center; font-family:var(--mono); font-size:9px; margin-top:10px; letter-spacing:0.08em; } .pleg.left { color:var(--ok); } .pleg.right { color:var(--accent2); } .pleg.mid { color:var(--accent); } .xiao-divider { border:none; border-top:1px solid var(--border); margin:0 -20px 12px; } /* ── Responsive ───────────────────────────────────────────── */ @media (max-width:1100px) { main { grid-template-columns:1fr 380px; grid-template-rows:auto auto; } .col-left { grid-column:1; grid-row:1; } .col-mid { grid-column:1; grid-row:2; } .col-right { grid-column:2; grid-row:1/3; } } @media (max-width:700px) { main { grid-template-columns:1fr; } .col-left, .col-mid, .col-right { grid-column:1; grid-row:auto; } .col-right { position:static; } } .section-label { font-family:var(--sans); font-size:11px; font-weight:600; letter-spacing:0.3em; text-transform:uppercase; color:var(--label); padding:4px 0; border-bottom:1px solid var(--border); margin-bottom:4px; display:flex; align-items:center; gap:8px; } .section-label::before { content:'//'; color:var(--accent); font-family:var(--mono); font-size:10px; } .card { background:var(--panel); border:1px solid var(--border); padding:20px; position:relative; } .card::before { content:''; position:absolute; top:0; left:0; width:3px; height:100%; background:var(--accent); opacity:0; transition:opacity 0.3s; } .card:focus-within::before { opacity:1; } .param { display:grid; grid-template-columns:190px 1fr auto; align-items:center; gap:14px; padding:12px 0; border-bottom:1px solid var(--border); } .param:last-child { border-bottom:none; padding-bottom:0; } .param:first-child { padding-top:0; } .param-label { font-family:var(--sans); font-size:13px; font-weight:600; letter-spacing:0.05em; text-transform:uppercase; } .param-desc { font-size:10px; color:var(--label); margin-top:3px; } .param-value { font-size:13px; color:var(--accent); min-width:52px; text-align:right; } input[type=range] { -webkit-appearance:none; appearance:none; width:100%; height:2px; background:var(--border); outline:none; cursor:pointer; } input[type=range]::-webkit-slider-thumb { -webkit-appearance:none; width:13px; height:13px; border-radius:0; background:var(--accent); cursor:pointer; transition:transform 0.15s; } input[type=range]::-webkit-slider-thumb:hover { transform:scale(1.4); } input[type=range]:disabled { opacity:0.35; } input[type=range]:disabled::-webkit-slider-thumb { background:var(--dim); cursor:not-allowed; } .segmented { display:flex; border:1px solid var(--border); } .seg-btn { flex:1; padding:7px 8px; background:transparent; border:none; border-right:1px solid var(--border); font-family:var(--mono); font-size:10px; letter-spacing:0.1em; color:var(--label); cursor:pointer; text-transform:uppercase; transition:all 0.15s; } .seg-btn:last-child { border-right:none; } .seg-btn.active { background:var(--accent); color:var(--bg); font-weight:bold; } .seg-btn:disabled { cursor:not-allowed; opacity:0.35; } .charge-seg .seg-btn.active.off { background:var(--dim); color:#fff; } .charge-seg .seg-btn.active.slow { background:var(--warn); color:var(--bg); } .charge-seg .seg-btn.active.fast { background:var(--accent2);color:#fff; } .flip-row { display:flex; gap:16px; padding:12px 0; border-bottom:1px solid var(--border); align-items:center; } .flip-row:last-child { border-bottom:none; } .flip-label { font-family:var(--sans); font-size:13px; font-weight:600; text-transform:uppercase; flex:1; } .toggle { position:relative; width:40px; height:22px; flex-shrink:0; } .toggle input { display:none; } .toggle-track { position:absolute; inset:0; background:var(--border); cursor:pointer; transition:background 0.2s; } .toggle input:checked + .toggle-track { background:var(--accent); } .toggle-thumb { position:absolute; top:3px; left:3px; width:16px; height:16px; background:#fff; transition:transform 0.2s; pointer-events:none; } .toggle input:checked ~ .toggle-thumb { transform:translateX(18px); } .toggle input:disabled + .toggle-track { cursor:not-allowed; opacity:0.4; } .cmd-grid { display:grid; grid-template-columns:1fr 1fr; gap:10px; } .cmd-btn { font-family:var(--sans); font-weight:700; font-size:13px; letter-spacing:0.12em; text-transform:uppercase; background:transparent; border:1px solid var(--border); color:var(--text); padding:14px; cursor:pointer; transition:all 0.2s; position:relative; overflow:hidden; text-align:left; display:flex; flex-direction:column; gap:5px; } .cmd-btn .cmd-icon { font-size:20px; } .cmd-btn .cmd-desc { font-family:var(--mono); font-size:9px; color:var(--label); letter-spacing:0.04em; text-transform:none; font-weight:400; } .cmd-btn::before { content:''; position:absolute; inset:0; opacity:0; transition:opacity 0.2s; } .cmd-btn:hover::before { opacity:1; } .cmd-btn:hover { color:var(--bg); } .cmd-btn:hover .cmd-desc { color:var(--hover-desc-color); } .cmd-btn.calibrate::before { background:var(--accent); } .cmd-btn.calibrate:hover { border-color:var(--accent); } .cmd-btn.reset::before { background:var(--accent2); } .cmd-btn.reset:hover { border-color:var(--accent2); } .cmd-btn span { position:relative; z-index:1; } .cmd-btn:disabled { opacity:0.3; cursor:not-allowed; } .cmd-btn:disabled::before { display:none; } .cmd-btn:disabled:hover { color:var(--text); border-color:var(--border); } .cmd-btn:disabled:hover .cmd-desc { color:var(--label); } .console { background:var(--panel2); border:1px solid var(--border); padding:14px; height:160px; overflow-y:auto; font-size:10.5px; line-height:1.85; } .console::-webkit-scrollbar { width:3px; } .console::-webkit-scrollbar-thumb { background:var(--dim); } .log-line { display:flex; gap:10px; } .log-time { color:var(--dim); flex-shrink:0; } .log-msg { color:var(--text); } .log-msg.ok { color:var(--ok); } .log-msg.err { color:var(--accent2); } .log-msg.warn { color:var(--warn); } .log-msg.info { color:var(--accent); } .viz-panel { background:var(--panel2); border:1px solid var(--border); padding:16px; } .viz-header { display:flex; justify-content:space-between; align-items:center; margin-bottom:12px; } .viz-title { font-family:var(--sans); font-size:11px; font-weight:600; letter-spacing:0.25em; text-transform:uppercase; color:var(--label); } .orient-card { padding:12px; display:flex; flex-direction:column; align-items:center; } #orientCanvas { display:block; width:100%; aspect-ratio:1; } .viz-ctrl-btn { background:none; border:1px solid var(--border); color:var(--label); font-size:11px; line-height:1; padding:3px 8px; cursor:pointer; letter-spacing:0.05em; } .viz-ctrl-btn:hover { border-color:var(--accent); color:var(--accent); } .viz-live { font-size:9px; letter-spacing:0.2em; display:block; } .viz-live.on { color:var(--accent2); animation:pulse 1.5s infinite; } .viz-live.paused { color:var(--label); } #vizCanvas { display:block; width:100%; background:var(--panel2); border:1px solid var(--border); cursor:crosshair; image-rendering:pixelated; } .viz-axes { display:grid; grid-template-columns:1fr 1fr; gap:8px; margin-top:10px; } .axis-bar-wrap { display:flex; flex-direction:column; gap:3px; } .axis-bar-label { font-size:9px; letter-spacing:0.15em; color:var(--label); text-transform:uppercase; display:flex; justify-content:space-between; } .axis-bar-track { height:4px; background:var(--border); position:relative; } .axis-bar-fill { position:absolute; top:0; height:100%; background:var(--accent); transition:width 0.05s, left 0.05s; } .axis-bar-fill.neg { background:var(--accent2); } .axis-bar-center { position:absolute; top:-2px; left:50%; width:1px; height:8px; background:var(--dim); } .telem-grid { display:grid; grid-template-columns:1fr 1fr; gap:8px; } .telem-cell { background:var(--panel2); border:1px solid var(--border); padding:12px 14px; } .telem-val { font-family:var(--sans); font-size:24px; font-weight:700; color:var(--text); line-height:1; } .telem-val.accent { color:var(--accent); } .telem-val.warn { color:var(--warn); } .telem-val.ok { color:var(--ok); } .telem-lbl { font-size:9px; letter-spacing:0.2em; text-transform:uppercase; color:var(--label); margin-top:5px; } .charge-info { display:grid; grid-template-columns:1fr 1fr 1fr; gap:0; margin-top:14px; border:1px solid var(--border); } .ci-item { padding:10px 12px; text-align:center; border-right:1px solid var(--border); } .ci-item:last-child { border-right:none; } .ci-val { font-family:var(--sans); font-size:16px; font-weight:700; } .ci-lbl { font-size:9px; letter-spacing:0.2em; text-transform:uppercase; color:var(--label); margin-top:3px; } .overlay { display:none; position:fixed; inset:0; background:rgba(0,0,0,0.88); z-index:500; align-items:center; justify-content:center; } .overlay.show { display:flex; } .modal { background:var(--panel); border:1px solid var(--accent2); padding:28px; max-width:360px; width:100%; } .modal h3 { font-family:var(--sans); font-size:18px; font-weight:700; color:var(--accent2); margin-bottom:10px; text-transform:uppercase; } .modal p { font-size:11px; color:var(--label); line-height:1.8; margin-bottom:20px; } .modal-btns { display:flex; gap:10px; } .modal-btns button { flex:1; font-family:var(--sans); font-weight:700; font-size:12px; letter-spacing:0.1em; text-transform:uppercase; padding:10px; cursor:pointer; border:1px solid; transition:all 0.2s; background:transparent; } .btn-cancel { border-color:var(--dim); color:var(--dim); } .btn-cancel:hover { border-color:var(--text); color:var(--text); } .btn-confirm { border-color:var(--accent2); color:var(--accent2); } .btn-confirm:hover { background:var(--accent2); color:var(--bg); } /* ── Debug modal ────────────────────────────────────────────────────────── */ .debug-modal { max-width:720px; padding:20px; border-color:var(--accent); } .debug-modal h3 { color:var(--accent); margin-bottom:0; } .debug-header { display:flex; justify-content:space-between; align-items:center; margin-bottom:14px; } .debug-close { background:none; border:1px solid var(--border); color:var(--label); font-size:14px; cursor:pointer; padding:2px 8px; font-family:var(--mono); } .debug-close:hover { border-color:var(--text); color:var(--text); } .debug-live { max-height:340px; overflow-y:auto; border:1px solid var(--border); margin-bottom:12px; } .debug-table { width:100%; border-collapse:collapse; font-family:var(--mono); font-size:10px; } .debug-table thead { position:sticky; top:0; background:var(--panel); z-index:1; } .debug-table th { padding:4px 6px; text-align:right; color:var(--label); font-weight:400; border-bottom:1px solid var(--border); letter-spacing:0.1em; text-transform:uppercase; } .debug-table td { padding:2px 6px; text-align:right; color:var(--text); border-bottom:1px solid color-mix(in srgb, var(--border) 40%, transparent); white-space:nowrap; } .debug-table td:last-child { text-align:left; color:var(--label); } .debug-table .shock-row td { color:var(--accent2); } .debug-controls { display:flex; align-items:center; gap:10px; } .debug-rec-btn { font-family:var(--mono); font-size:12px; font-weight:700; padding:6px 14px; cursor:pointer; border:1px solid var(--accent2); color:var(--accent2); background:transparent; letter-spacing:0.1em; } .debug-rec-btn.recording { background:var(--accent2); color:var(--bg); animation:rec-pulse 1s infinite; } @keyframes rec-pulse { 0%,100%{opacity:1} 50%{opacity:0.6} } .debug-rec-count { font-family:var(--mono); font-size:10px; color:var(--label); } .debug-ctrl-btn { font-family:var(--mono); font-size:10px; padding:5px 10px; cursor:pointer; border:1px solid var(--border); color:var(--label); background:transparent; } .debug-ctrl-btn:hover { border-color:var(--text); color:var(--text); } .debug-shock-badge { font-family:var(--mono); font-size:9px; letter-spacing:0.15em; padding:2px 8px; border:1px solid var(--border); color:var(--border); opacity:0.3; transition:all 0.15s; } .debug-shock-badge.active { border-color:var(--accent2); color:var(--accent2); opacity:1; } .no-ble { grid-column:1/-1; text-align:center; padding:80px 24px; } .no-ble h2 { font-family:var(--sans); font-size:28px; font-weight:700; color:var(--accent2); margin-bottom:12px; } .no-ble p { font-size:13px; color:var(--label); line-height:1.8; } body.disconnected .card { opacity:0.45; pointer-events:none; transition:opacity 0.3s; } body.disconnected .cmd-grid { opacity:0.45; pointer-events:none; transition:opacity 0.3s; } .tap-key-row { display:flex; align-items:center; gap:10px; padding-top:12px; flex-wrap:wrap; } .mod-btn { display:flex; align-items:center; gap:4px; cursor:pointer; font-family:var(--mono); font-size:10px; color:var(--label); user-select:none; } .mod-btn input { display:none; } .mod-btn span { padding:4px 8px; border:1px solid var(--border); background:transparent; transition:all 0.15s; } .mod-btn input:checked + span { background:var(--accent); color:var(--bg); border-color:var(--accent); font-weight:bold; } .mod-btn input:disabled + span { opacity:0.35; cursor:not-allowed; } .restart-note { color:var(--warn); font-family:var(--mono); font-size:9px; } .pin-select { background:var(--bg); color:var(--text); border:1px solid var(--border); font-family:var(--mono); font-size:11px; padding:3px 6px; cursor:pointer; min-width:80px; } .pin-select:disabled { color:var(--dim); border-color:var(--dim); cursor:not-allowed; } .tap-flash { position:absolute; inset:0; pointer-events:none; opacity:0; transition:opacity 0.25s; } .tap-flash.left { background:radial-gradient(circle at center, var(--tap-left) 0%, transparent 70%); } .tap-flash.right { background:radial-gradient(circle at center, var(--tap-right) 0%, transparent 70%); } .tap-flash.show { opacity:1; } .viz-wrap { position:relative; }