*{margin:0;padding:0;box-sizing:border-box}
:root{
  --bg:#08080a;--surface:#0e0e11;--surface2:#141418;--border:rgba(255,255,255,0.08);
  --border-hi:rgba(255,255,255,0.14);--text:#ededf0;--text2:#a1a1aa;--text3:#71717a;
  --accent:#6366f1;--accent2:#a855f7;--green:#22c55e;--red:#ef4444;--amber:#f59e0b;
  --green-bg:rgba(34,197,94,0.1);--red-bg:rgba(239,68,68,0.1);--blue-bg:rgba(99,102,241,0.1);
  --font:'Inter','Segoe UI',system-ui,sans-serif;
}
body{background:var(--bg);color:var(--text);font-family:var(--font);font-size:13px;letter-spacing:-0.01em;overflow:hidden}
#app{display:flex;flex-direction:column;height:100vh}
.header{display:flex;align-items:center;justify-content:space-between;padding:0 20px;height:52px;background:var(--surface);border-bottom:1px solid var(--border);backdrop-filter:blur(20px);z-index:50}
.header-left{display:flex;align-items:center;gap:12px}
.logo{width:28px;height:28px;border-radius:6px;background:linear-gradient(135deg,var(--accent),var(--accent2));display:flex;align-items:center;justify-content:center;font-size:14px;font-weight:700;color:#fff;box-shadow:0 0 20px rgba(99,102,241,0.3)}
.header h1{font-size:14px;font-weight:600;letter-spacing:-0.02em}
.header h1 span{color:var(--text3);font-weight:400;margin-left:6px}
.header-right{display:flex;align-items:center;gap:16px}
.conn-status{display:flex;align-items:center;gap:6px;font-size:12px;color:var(--text2)}
.conn-dot{width:8px;height:8px;border-radius:50%;background:var(--red);animation:breathe 2s ease-in-out infinite}
.conn-dot.ok{background:var(--green)}
.conn-dot.warn{background:var(--amber)}
@keyframes breathe{0%,100%{opacity:1}50%{opacity:0.6}}
.layout-switch{display:flex;gap:2px;background:var(--surface2);border:1px solid var(--border);border-radius:6px;padding:2px}
.layout-switch button{background:transparent;border:none;color:var(--text3);padding:4px 10px;border-radius:4px;cursor:pointer;font-size:11px;transition:all 0.15s}
.layout-switch button.active{background:var(--accent);color:#fff}
.layout-switch button:hover:not(.active){color:var(--text2)}
.main{flex:1;display:grid;gap:12px;padding:12px;overflow:hidden;transition:grid-template-columns 0.2s}
.main.dashboard{grid-template-columns:1fr 340px}
.main.focus{grid-template-columns:2fr 1fr 340px}
.main.wall{grid-template-columns:1fr}
.main.wall .sidebar{display:none}
.cam-grid{display:grid;gap:10px;height:100%;overflow:hidden}
.cam-grid.g4{grid-template-columns:repeat(2,1fr);grid-template-rows:repeat(2,1fr)}
.cam-grid.g2{grid-template-columns:repeat(2,1fr);grid-template-rows:1fr}
.cam-grid.g6{grid-template-columns:repeat(3,1fr);grid-template-rows:repeat(2,1fr)}
.cam-grid.g8{grid-template-columns:repeat(4,1fr);grid-template-rows:repeat(2,1fr)}
.cam-grid.g1{grid-template-columns:1fr;grid-template-rows:1fr}
.cam-card{background:var(--surface);border:1px solid var(--border);border-radius:10px;overflow:hidden;display:flex;flex-direction:column;position:relative;transition:border-color 0.2s,box-shadow 0.2s}
.cam-card:hover{border-color:var(--border-hi)}
.cam-card.active{border-color:rgba(34,197,94,0.3);box-shadow:0 0 16px rgba(34,197,94,0.08)}
.cam-head{display:flex;align-items:center;justify-content:space-between;padding:8px 12px;border-bottom:1px solid var(--border)}
.ch-label{display:flex;align-items:center;gap:8px;font-size:12px;font-weight:600}
.ch-badge{background:var(--accent);color:#fff;padding:2px 7px;border-radius:4px;font-size:10px;font-weight:600}
.ch-name{color:var(--text2);font-size:11px}
.detect-badge{display:flex;align-items:center;gap:4px;font-size:11px;color:var(--text2)}
.cnt{color:var(--text);font-weight:700;font-size:11px}
.snap-wrap{flex:1;position:relative;background:#000;overflow:hidden;min-height:0}
.snap-wrap img{width:100%;height:100%;object-fit:contain}
.bbox-canvas{position:absolute;top:0;left:0;width:100%;height:100%;pointer-events:none}
.no-snap{display:flex;align-items:center;justify-content:center;height:100%;color:var(--text3);font-size:12px}
.shimmer{position:absolute;inset:0;background:linear-gradient(105deg,transparent 40%,rgba(255,255,255,0.03) 50%,transparent 60%);animation:shimmer 3s linear infinite;pointer-events:none}
@keyframes shimmer{0%{transform:translateX(-100%)}100%{transform:translateX(100%)}}
.cam-foot{display:flex;gap:1px;border-top:1px solid var(--border);background:var(--border)}
.cam-foot .metric{flex:1;background:var(--surface);padding:6px 8px;text-align:center}
.cam-foot .metric .lbl{font-size:9px;color:var(--text3);text-transform:uppercase;letter-spacing:0.05em}
.cam-foot .metric .val{font-size:14px;font-weight:600;margin-top:2px}
.cam-foot .metric .val.good{color:var(--green)}
.cam-foot .metric .val.bad{color:var(--red)}
.cam-foot .metric .val.warn{color:var(--amber)}
.focus-thumbs{display:flex;flex-direction:column;gap:10px}
.focus-thumbs .cam-card{flex:1}
.sidebar{display:flex;flex-direction:column;gap:10px;overflow:hidden;height:100%}
.panel{background:var(--surface);border:1px solid var(--border);border-radius:10px;overflow:hidden;display:flex;flex-direction:column}
.panel-head{padding:10px 14px;border-bottom:1px solid var(--border);display:flex;align-items:center;justify-content:space-between}
.panel-head .title{font-size:12px;font-weight:600}
.panel-head .badge{font-size:10px;color:var(--text3);background:var(--surface2);padding:2px 6px;border-radius:4px}
.panel-body{padding:12px 14px;overflow-y:auto;flex:1}
.status-grid{display:grid;grid-template-columns:1fr 1fr;gap:8px}
.stat-item{background:var(--surface2);border:1px solid var(--border);border-radius:8px;padding:10px}
.stat-item .stat-label{font-size:10px;color:var(--text3);text-transform:uppercase;letter-spacing:0.05em;margin-bottom:4px}
.stat-item .stat-value{font-size:18px;font-weight:700;letter-spacing:-0.02em}
.stat-item .stat-value .unit{font-size:11px;font-weight:400;color:var(--text3);margin-left:2px}
.stat-item .stat-bar{height:3px;background:var(--border);border-radius:2px;margin-top:6px;overflow:hidden}
.stat-item .stat-bar .fill{height:100%;border-radius:2px;transition:width 0.5s ease}
.stat-item .stat-bar .fill.green{background:linear-gradient(90deg,#16a34a,var(--green))}
.stat-item .stat-bar .fill.accent{background:linear-gradient(90deg,#4f46e5,var(--accent))}
.stat-item .stat-bar .fill.amber{background:linear-gradient(90deg,#d97706,var(--amber))}
.stat-item .stat-value.good{color:var(--green)}
.stat-item .stat-value.bad{color:var(--red)}
.pipeline-status{display:flex;align-items:center;gap:6px}
.pipeline-status .dot{width:6px;height:6px;border-radius:50%}
.pipeline-status .dot.on{background:var(--green);box-shadow:0 0 8px var(--green)}
.pipeline-status .dot.off{background:var(--red)}

.tabs{display:flex;gap:1px;background:var(--border);border-radius:6px;overflow:hidden;padding:1px;flex:1}
.tabs button{flex:1;background:var(--surface);border:none;color:var(--text3);padding:6px;cursor:pointer;font-size:11px;transition:all 0.15s}
.tabs button.active{background:var(--accent);color:#fff}
.tabs button:hover:not(.active){color:var(--text2)}
.alert-feed{overflow-y:auto;flex:1}
.alert-feed::-webkit-scrollbar{width:4px}
.alert-feed::-webkit-scrollbar-thumb{background:var(--border-hi);border-radius:2px}
.alert-row{display:flex;align-items:center;gap:8px;padding:8px 0;border-bottom:1px solid var(--border);font-size:11px}
.alert-row .ch-tag{background:var(--accent);color:#fff;padding:1px 6px;border-radius:3px;font-size:9px;font-weight:600;min-width:28px;text-align:center}
.alert-row .persons{color:var(--red);font-weight:700;font-size:12px}
.alert-row .persons.zero{color:var(--green)}
.alert-row .meta{color:var(--text3);font-size:10px;margin-left:auto}
.alert-row .time{color:var(--text3);font-size:10px;white-space:nowrap}
.empty{text-align:center;color:var(--text3);padding:20px;font-size:11px}
.hist-toolbar{display:flex;gap:6px;align-items:center;margin-bottom:8px;flex-wrap:wrap}
.hist-toolbar select{background:var(--surface2);border:1px solid var(--border);color:var(--text);padding:4px 8px;border-radius:4px;font-size:11px}
.hist-toolbar .info{color:var(--text3);font-size:10px;margin-left:auto}
.hist-table{width:100%;border-collapse:collapse;font-size:11px}
.hist-table th{color:var(--text3);padding:5px 4px;text-align:left;font-weight:500;font-size:10px;text-transform:uppercase;letter-spacing:0.05em;position:sticky;top:0;background:var(--surface)}
.hist-table td{padding:4px;border-bottom:1px solid var(--border)}
.hist-table .ch-tag{background:var(--accent);color:#fff;padding:1px 5px;border-radius:3px;font-size:9px}
.hist-table .pc{color:var(--red);font-weight:600}
.hist-wrap{max-height:300px;overflow-y:auto;border:1px solid var(--border);border-radius:6px;padding:0 8px}
.hist-wrap::-webkit-scrollbar{width:4px}
.hist-wrap::-webkit-scrollbar-thumb{background:var(--border-hi);border-radius:2px}
.snap-thumb{width:32px;height:24px;object-fit:cover;border-radius:3px;cursor:pointer;border:1px solid var(--border);vertical-align:middle}
.snap-thumb:hover{border-color:var(--accent)}
.snap-icon{cursor:pointer;color:var(--accent);font-size:14px}
.snap-icon:hover{color:var(--green)}
.snap-modal{position:fixed;inset:0;z-index:9999;background:rgba(0,0,0,0.85);display:flex;align-items:center;justify-content:center;flex-direction:column}
.snap-modal img{max-width:90vw;max-height:80vh;border-radius:8px;box-shadow:0 4px 32px rgba(0,0,0,0.5)}
.snap-modal .close-btn{position:absolute;top:16px;right:24px;font-size:28px;color:#fff;cursor:pointer;background:none;border:none;line-height:1}
.snap-modal .info{color:var(--text2);margin-top:12px;font-size:13px}
.snap-view{padding:8px;overflow-y:auto;flex:1}
.snap-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(140px,1fr));gap:8px}
.snap-card{background:var(--surface2);border:1px solid var(--border);border-radius:6px;overflow:hidden;cursor:pointer;transition:border-color 0.15s}
.snap-card:hover{border-color:var(--accent)}
.snap-card-img{width:100%;height:80px;object-fit:cover;display:block}
.snap-card-info{display:flex;align-items:center;gap:4px;padding:4px 6px;font-size:10px;flex-wrap:wrap}
.snap-card-info .time{color:var(--text3);font-size:9px;width:100%;margin-top:2px}
.stats-view{padding:8px;overflow-y:auto;flex:1}
.stats-cards{display:flex;gap:8px;margin-bottom:12px}
.stat-card{flex:1;background:var(--surface2);border:1px solid var(--border);border-radius:6px;padding:10px;text-align:center}
.stat-val{font-size:24px;font-weight:700;color:var(--accent)}
.stat-label{font-size:10px;color:var(--text3);margin-top:4px;text-transform:uppercase;letter-spacing:0.05em}
.stats-chart{background:var(--surface2);border:1px solid var(--border);border-radius:6px;padding:8px;margin-bottom:8px}
.chart-title{font-size:11px;color:var(--text2);margin-bottom:4px;font-weight:600}
.chart-svg{width:100%;height:auto;display:block}
.stats-row{display:flex;gap:8px}
.playback-view{padding:8px;overflow-y:auto;flex:1;display:flex;flex-direction:column}
.pb-toolbar{display:flex;gap:6px;align-items:center;margin-bottom:8px}
.pb-display{position:relative;flex:1;min-height:200px;background:#000;border-radius:6px;overflow:hidden;display:flex;align-items:center;justify-content:center}
.pb-image{max-width:100%;max-height:100%;object-fit:contain}
.pb-empty{color:var(--text3);font-size:14px}
.pb-overlay{position:absolute;bottom:0;left:0;right:0;display:flex;gap:8px;align-items:center;padding:6px 10px;background:linear-gradient(transparent,rgba(0,0,0,0.8));color:#fff;font-size:11px}
.pb-controls{display:flex;gap:6px;align-items:center;padding:8px 0}
.pb-slider{flex:1;height:4px}
.pb-thumbs{display:flex;gap:4px;overflow-x:auto;padding:4px 0}
.pb-thumb{width:64px;height:48px;object-fit:cover;border-radius:3px;cursor:pointer;border:2px solid transparent;opacity:0.6}
.pb-thumb.active{border-color:var(--accent);opacity:1}
.pb-thumb:hover{opacity:0.9}
.pager{display:flex;gap:4px;align-items:center;justify-content:center;margin-top:8px}
.pager button{background:var(--surface2);border:1px solid var(--border);color:var(--text2);padding:3px 8px;border-radius:4px;cursor:pointer;font-size:11px}
.pager button:disabled{opacity:0.3;cursor:default}
.pager button:hover:not(:disabled){border-color:var(--border-hi)}
.pager .page-info{color:var(--text3);font-size:10px;margin:0 4px}
.cfg-section{margin-bottom:20px}
.cfg-section .sec-title{font-size:15px;color:var(--text);font-weight:600;margin-bottom:10px;padding-bottom:8px;border-bottom:1px solid var(--border-hi)}
.cfg-form label{display:block;color:var(--text2);font-size:13px;margin:8px 0 4px;font-weight:500}
.cfg-form input,.cfg-form select{width:100%;background:var(--surface2);border:1px solid var(--border);color:var(--text);padding:8px 10px;border-radius:6px;font-size:13px;transition:border-color 0.15s}
.cfg-form input:focus,.cfg-form select:focus{outline:none;border-color:var(--accent)}
.cfg-form .hint{font-size:11px;color:var(--text3);margin-top:4px;line-height:1.5}
.cfg-form button{width:100%;background:var(--accent);color:#fff;border:none;padding:9px;border-radius:6px;cursor:pointer;font-size:13px;font-weight:600;margin-top:10px;transition:background 0.15s}
.cfg-form button:hover{background:#4f46e5}
.cfg-status{margin-top:10px;padding:10px;background:var(--surface2);border:1px solid var(--border);border-radius:6px;font-size:12px;line-height:1.6}
.cfg-status .row{display:flex;justify-content:space-between}
.cfg-status .val.on{color:var(--green)}
.cfg-status .val.off{color:var(--text3)}
.wall-overlay{position:absolute;bottom:12px;left:12px;display:flex;gap:8px;z-index:10}
.wall-overlay .stat{background:rgba(8,8,10,0.7);backdrop-filter:blur(12px);border:1px solid var(--border);border-radius:6px;padding:4px 10px;font-size:11px;color:var(--text2)}
.wall-overlay .stat .v{color:var(--text);font-weight:600;margin-left:4px}

/* ========== 配置页布局 ========== */
.view-switch{display:flex;gap:2px;background:var(--surface2);border:1px solid var(--border);border-radius:6px;padding:2px}
.view-switch button{background:transparent;border:none;color:var(--text3);padding:4px 14px;border-radius:4px;cursor:pointer;font-size:12px;font-weight:600;transition:all 0.15s}
.view-switch button.active{background:var(--accent);color:#fff}
.view-switch button:hover:not(.active){color:var(--text2)}
.config-page{flex:1;display:grid;grid-template-columns:200px 1fr;gap:0;overflow:hidden}
.config-nav{background:var(--surface);border-right:1px solid var(--border);display:flex;flex-direction:column;padding:12px 8px;gap:2px;overflow-y:auto}
.config-nav button{background:transparent;border:none;color:var(--text2);padding:10px 14px;border-radius:8px;cursor:pointer;font-size:14px;text-align:left;transition:all 0.15s;display:flex;align-items:center;gap:8px}
.config-nav button.active{background:var(--accent);color:#fff}
.config-nav button:hover:not(.active){background:var(--surface2);color:var(--text)}
.config-content{padding:20px 28px;overflow-y:auto;max-width:1200px}
.config-content::-webkit-scrollbar{width:6px}
.config-content::-webkit-scrollbar-thumb{background:var(--border-hi);border-radius:3px}
.cfg-form{max-width:900px}
.cfg-actions{display:flex;gap:8px;margin-top:16px;margin-bottom:16px;padding-top:12px;border-top:1px solid var(--border)}
.cfg-actions button{width:auto;padding:8px 20px}
.btn-green{background:var(--green)!important}
.btn-green:hover{background:#16a34a!important}
.btn-secondary{background:var(--surface2)!important;color:var(--text)!important;border:1px solid var(--border)!important}
.btn-secondary:hover{background:var(--border)!important;border-color:var(--border-hi)!important}
.btn-danger{background:var(--red)!important;color:#fff!important}
.btn-danger:hover{background:#dc2626!important}
.btn-primary{background:var(--accent)!important;color:#fff!important}

/* 通道卡片网格 */
.ch-card-grid{display:grid;grid-template-columns:1fr 1fr;gap:12px}
.ch-card{background:var(--surface2);border:1px solid var(--border);border-radius:8px;padding:14px}
.ch-card-head{font-size:14px;font-weight:600;color:var(--text);margin-bottom:10px;padding-bottom:8px;border-bottom:1px solid var(--border)}

/* 区域列表 */
.zone-list-item{display:flex;justify-content:space-between;padding:6px 10px;background:var(--surface2);border:1px solid var(--border);border-radius:6px;margin-bottom:4px;cursor:pointer;font-size:12px;transition:all 0.15s}
.zone-list-item:hover{border-color:var(--border-hi)}
.zone-list-item.selected{background:var(--accent);color:#fff;border-color:var(--accent)}
.zone-meta{opacity:0.7;font-size:10px}

/* 跨通道规则 */
.crosszone-rule{background:var(--surface2);border:1px solid var(--border);border-radius:8px;padding:14px;margin-top:12px}

/* 蓝牙 */
.bt-connected{background:var(--surface2);padding:12px;border-radius:8px;margin-bottom:12px;font-size:13px;border:1px solid var(--green)}
.bt-device{display:flex;justify-content:space-between;align-items:center;padding:8px 12px;background:var(--surface2);border-bottom:1px solid var(--border);font-size:12px}
.bt-device:last-child{border-bottom:none}

/* 管线信息 */
.pipeline-info{background:var(--surface2);border:1px solid var(--border);border-radius:8px;padding:12px;font-size:13px}
.info-row{display:flex;justify-content:space-between;padding:5px 0}
.info-row:not(:last-child){border-bottom:1px solid var(--border)}
/* 推送通道卡片 */
.push-channel-card{background:var(--surface2);border:1px solid var(--border);border-radius:8px;padding:12px 14px;margin-bottom:8px;display:grid;grid-template-columns:1fr 1fr auto;gap:8px;align-items:center}
.dir-overlay{position:absolute;top:8px;right:8px;z-index:20;display:flex;align-items:center;gap:6px;padding:6px 12px;border-radius:6px;background:rgba(0,0,0,0.75);backdrop-filter:blur(4px);font-size:14px;font-weight:700;pointer-events:none;animation:dirFadeIn .3s ease;border-left:3px solid;box-shadow:0 2px 8px rgba(0,0,0,0.3)}
.dir-overlay.in{color:#22c55e;border-left-color:#22c55e}
.dir-overlay.out{color:#f97316;border-left-color:#f97316}
.dir-overlay .dir-arrow{font-size:22px;line-height:1}
.dir-overlay .dir-zone{font-size:11px;font-weight:400;color:rgba(255,255,255,0.7);margin-left:4px}
@keyframes dirFadeIn{from{opacity:0;transform:translateX(20px)}to{opacity:1;transform:translateX(0)}}
.push-ch-info{display:flex;align-items:center;gap:8px}
.push-ch-type{padding:2px 8px;border-radius:4px;font-size:11px;font-weight:600}
.push-ch-type.http{background:rgba(99,102,241,0.15);color:var(--accent)}
.push-ch-type.mqtt{background:rgba(245,158,11,0.15);color:var(--amber)}
.push-ch-on{color:var(--green);font-size:12px}
.push-ch-off{color:var(--text3);font-size:12px}
.push-ch-stats{font-size:12px}
.push-ch-actions{display:flex;gap:6px}
.push-modal-overlay{position:fixed;inset:0;z-index:9998;background:rgba(0,0,0,0.6);display:flex;align-items:center;justify-content:center}
.push-modal{background:var(--surface);border:1px solid var(--border-hi);border-radius:12px;padding:24px;width:480px;max-width:90vw;max-height:85vh;overflow-y:auto}
