1// appbuilder/styles.js â All AppBuilder CSS, injected once on first mount. 2import { ensureToolbarBaseStyles } from "../../common/toolbar.js"; 3 4let _stylesInjected = false; 5export function ensureStyles() { 6 if (_stylesInjected) return; 7 _stylesInjected = true; 8 // Inject shared toolbar base CSS (toolbar-ab, btn-ab, toolbar-section-ab, etc.) 9 ensureToolbarBaseStyles(); 10 const style = document.createElement("style"); 11 style.textContent = ` 12/* ââ App Builder shell âââââââââââââââââââââââââââââââââââââââââââââââââââ */ 13.shell-ab { 14 display: flex; flex-direction: row; 15 width: 100%; height: 100%; overflow: hidden; 16 background: #0f172a; 17 font-family: system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif; 18} 19/* ââ Vertical Left Toolbar ââââââââââââââââââââââââââââââââââââââââââââââââ */ 20.shell-ab > .toolbar-ab { 21 flex-direction: column; align-items: stretch; 22 width: 132px; min-width: 132px; flex-shrink: 0; 23 height: 100%; border-right: 1px solid #334155; border-bottom: none; 24 padding: 0; overflow-y: auto; overflow-x: hidden; gap: 0; 25} 26.shell-ab > .toolbar-ab .toolbar-title-ab { 27 text-align: center; margin: 0; padding: 7px 4px 6px; 28 border-bottom: 1px solid #334155; font-size: 10px; 29 align-self: auto; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; 30} 31/* Vertical toolbar sections */ 32.shell-ab > .toolbar-ab .toolbar-section-ab { 33 border-left: none; border-top: 1px solid #334155; 34 padding: 0; width: 100%; gap: 0; align-items: stretch; 35} 36.shell-ab > .toolbar-ab .toolbar-section-ab:first-of-type { border-top: none; } 37/* Section label as collapsible toggle header */ 38.shell-ab > .toolbar-ab .toolbar-section-label-ab { 39 display: flex; align-items: center; justify-content: space-between; 40 width: 100%; padding: 4px 6px 3px; cursor: pointer; 41 pointer-events: auto; box-sizing: border-box; 42} 43.shell-ab > .toolbar-ab .toolbar-section-label-ab:hover {
44 color: #94a3b8; background: rgba(255,255,255,0.04); 45} 46.shell-ab > .toolbar-ab .section-toggle-ab { 47 font-size: 8px; color: #475569; transition: transform 0.15s; flex-shrink: 0; 48} 49.shell-ab > .toolbar-ab .toolbar-section-ab.section-collapsed-ab .section-toggle-ab { 50 transform: rotate(-90deg); 51} 52.shell-ab > .toolbar-ab .toolbar-section-ab.section-collapsed-ab .toolbar-section-row-ab { 53 display: none; 54} 55/* Section body: 2-column button grid */ 56.shell-ab > .toolbar-ab .toolbar-section-row-ab { 57 width: 100%; 58 display: grid; 59 grid-template-columns: repeat(2, minmax(0, 1fr)); 60 gap: 4px; 61 padding: 2px 0 4px; 62} 63.shell-ab > .toolbar-ab .palette-ab { 64 grid-column: 1 / -1; 65 width: 100%; 66 min-width: 0; 67 border-right: none; 68 background: transparent; 69 padding: 0; 70 overflow: visible; 71} 72.shell-ab > .toolbar-ab .palette-ab .palette-section { 73 padding: 2px 0 4px; 74} 75.shell-ab > .toolbar-ab .palette-ab .palette-grid { 76 grid-template-columns: repeat(2, minmax(0, 1fr)); 77} 78/* Vertical buttons: icon above, label below */ 79.shell-ab > .toolbar-ab .btn-ab { 80 flex-direction: column; align-items: center; justify-content: center; 81 padding: 5px 2px; gap: 2px; width: 100%; min-width: 0; font-size: 9px; 82} 83.shell-ab > .toolbar-ab .btn-emoji-ab { 84 font-size: 14px; line-height: 1; 85} 86.shell-ab > .toolbar-ab .btn-ab .btn-label-ab { 87 display: block; 88 font-size: 9px; text-align: center; white-space: normal; 89 overflow: hidden; text-overflow: ellipsis; line-height: 1.15; 90} 91/* Theme select fits the sidebar width */ 92.shell-ab > .toolbar-ab .theme-select-ab { 93 grid-column: 1 / -1; 94 width: 100%; min-width: unset; font-size: 10px; padding: 3px 4px; 95} 96/* Hide spacer in vertical layout */ 97.shell-ab > .toolbar-ab .spacer-ab { flex: 0; display: none; } 98/* ââ Theme selector (non-toolbar context) âââââââââââââââââââââââââââââââââ */ 99.theme-select-ab { 100 padding: 4px 8px; border: 1px solid #475569; border-radius: 5px; 101 background: #1e293b; color: #cbd5e1; font: 12px/1.4 system-ui; 102 cursor: pointer; outline: none; min-width: 120px; 103} 104.theme-select-ab:hover { background:#334155; color:#f1f5f9; } 105.theme-select-ab:focus { border-color:#60a5fa; } 106/* ââ Mode toggle (non-toolbar context) âââââââââââââââââââââââââââââââââââ */ 107/* ââ Body âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ */ 108.body-ab { display:flex; flex:1; overflow:hidden; } 109/* ââ Canvas toolbar (inline above canvas) ââââââââââââââââââââââââââââââââââ */ 110.canvas-toolbar-ab { 111 display:flex; align-items:center; gap:3px; flex-shrink:0; 112 padding:4px 8px; background:#e2e8f0; border-bottom:1px solid #cbd5e1; 113 flex-wrap:wrap; 114} 115.canvas-toolbar-ab .btn-ab { 116 background:#f8fafc; border-color:#cbd5e1; color:#64748b; 117 padding:3px 8px; font-size:11px; 118} 119.canvas-toolbar-ab .btn-ab:hover { background:#e2e8f0; color:#334155; } 120.canvas-toolbar-ab .btn-ab:disabled { opacity:.3; } 121.canvas-toolbar-ab .btn-active-ab { background:#dbeafe; border-color:#3b82f6; color:#1d4ed8; } 122.canvas-toolbar-ab .sep-ab { background:#cbd5e1; } 123.ct-label-ab { font:600 10px/1 system-ui; color:#94a3b8; letter-spacing:.4px; margin-right:2px; } 124/* ââ Canvas wrapper âââââââââââââââââââââââââââââââââââââââââââââââââââââââ */ 125.canvas-wrap-ab { flex:1; overflow:auto; background:#e2e8f0; display:flex; flex-direction:column; } 126.canvas-ab { flex:1; overflow:auto; background:#e2e8f0; position:relative; padding:0 20px 20px; touch-action: none; } 127/* ââ Canvas page (the "artboard") ââââââââââââââââââââââââââââââââââââââââ */ 128.canvas-page-ab { 129 position:relative; background:#fff; 130 border-radius:4px; box-shadow:0 2px 20px rgba(0,0,0,.12); 131 margin:0 auto; overflow:visible; 132} 133.canvas-page-ab.grid-on-ab { 134 background-image: linear-gradient(rgba(0,0,0,.06) 1px, transparent 1px), 135 linear-gradient(90deg, rgba(0,0,0,.06) 1px, transparent 1px); 136 background-size: var(--grid-size-ab,10px) var(--grid-size-ab,10px); 137} 138/* ââ Component wrapper (absolute positioned) âââââââââââââââââââââââââââââ */ 139.comp-wrap-ab { 140 position:absolute; box-sizing:border-box; 141 border-radius:3px; outline:none; 142} 143.comp-wrap-ab .live-inner-ab { 144 width:100%; height:100%; overflow:hidden; pointer-events:none; 145 box-sizing:border-box; 146} 147.comp-wrap-ab:hover > .comp-hover-ring-ab { display:block; } 148.comp-hover-ring-ab { 149 display:none; position:absolute; inset:-2px; 150 border:1px dashed #93c5fd; border-radius:4px; pointer-events:none; z-index:1; 151} 152.comp-wrap-ab.selected-ab > .comp-hover-ring-ab { display:none; } 153.comp-wrap-ab.selected-ab { outline:2px solid #2563eb; outline-offset:1px; } 154.comp-wrap-ab.locked-ab { outline-color:#f59e0b !important; } 155.comp-wrap-ab.locked-ab .comp-hover-ring-ab { border-color:#fcd34d; } 156.comp-wrap-ab.group-wrap-ab { 157 outline:2px dashed #6366f1 !important; outline-offset:3px; 158 background:rgba(99,102,241,.04); 159} 160.comp-wrap-ab.comp-moving-ab { opacity:.7; z-index:99999 !important; } 161.comp-wrap-ab.drop-target-ab { outline:2px solid #7c3aed !important; outline-offset:2px; background:rgba(124,58,237,.08) !important; } 162/* A container holding docked children fades its own placeholder template so the 163 docked items read as the real content instead of overlapping mock UI. */ 164.comp-wrap-ab.has-docked-children-ab { outline:1px dashed #94a3b8; outline-offset:2px; } 165.container-template-ab { opacity:.18 !important; pointer-events:none !important; } 166/* ââ Resize handles âââââââââââââââââââââââââââââââââââââââââââââââââââââââ */ 167.handle-ab { 168 position:absolute; width:10px; height:10px; 169 background:#2563eb; border:2px solid #fff; 170 border-radius:2px; z-index:10; box-shadow:0 1px 4px rgba(0,0,0,.3); 171} 172.handle-ab[data-dir="nw"] { top:-5px; left:-5px; cursor:nwse-resize; } 173.handle-ab[data-dir="n"] { top:-5px; left:calc(50% - 5px); cursor:ns-resize; } 174.handle-ab[data-dir="ne"] { top:-5px; right:-5px; cursor:nesw-resize; } 175.handle-ab[data-dir="e"] { top:calc(50% - 5px); right:-5px; cursor:ew-resize; } 176.handle-ab[data-dir="se"] { bottom:-5px; right:-5px; cursor:nwse-resize; } 177.handle-ab[data-dir="s"] { bottom:-5px; left:calc(50% - 5px); cursor:ns-resize; } 178.handle-ab[data-dir="sw"] { bottom:-5px; left:-5px; cursor:nesw-resize; } 179.handle-ab[data-dir="w"] { top:calc(50% - 5px); left:-5px; cursor:ew-resize; } 180/* ââ Label / lock badge on selected component âââââââââââââââââââââââââââââ */ 181.comp-badge-ab { 182 position:absolute; top:-22px; left:0; 183 background:#2563eb; color:#fff; border-radius:3px 3px 0 0; 184 font:600 10px/1 system-ui; padding:2px 6px; white-space:nowrap; 185 pointer-events:none; z-index:10; letter-spacing:.2px; 186} 187.locked-ab .comp-badge-ab { background:#d97706; } 188.comp-lock-icon-ab { position:absolute; top:3px; right:3px; font-size:11px; z-index:5; pointer-events:none; opacity:.7; } 189/* ââ Alignment guide lines ââââââââââââââââââââââââââââââââââââââââââââââââ */ 190.guide-ab { 191 position:absolute; background:#ef4444; z-index:99998; pointer-events:none; 192} 193.guide-h-ab { height:1px; left:0; right:0; box-shadow:0 0 4px rgba(239,68,68,.6); } 194.guide-v-ab { width:1px; top:0; bottom:0; box-shadow:0 0 4px rgba(239,68,68,.6); } 195/* ââ Marquee selection rectangle ââââââââââââââââââââââââââââââââââââââââââ */ 196.marquee-ab { 197 position:absolute; border:1.5px dashed #2563eb; 198 background:rgba(37,99,235,.08); pointer-events:none; z-index:99999; 199 box-sizing:border-box; border-radius:2px; 200} 201/* ââ Touch palette drag ghost âââââââââââââââââââââââââââââââââââââââââââââ */ 202.palette-drag-ghost-ab { 203 position:fixed; pointer-events:none; z-index:99999; 204 transform:translate(-50%,-50%); 205 background:#1e293b; color:#e2e8f0; 206 border:1.5px dashed #3b82f6; border-radius:6px; 207 padding:6px 12px; font:600 12px system-ui; white-space:nowrap; 208 box-shadow:0 4px 12px rgba(0,0,0,.4); opacity:.9; 209} 210/* ââ Canvas empty state âââââââââââââââââââââââââââââââââââââââââââââââââââ */ 211.canvas-empty-ab { 212 position:absolute; inset:0; display:flex; flex-direction:column; 213 align-items:center; justify-content:center; color:#94a3b8; 214 pointer-events:none; text-align:center; gap:10px; 215} 216.canvas-empty-icon-ab { font-size:40px; opacity:.35; } 217.canvas-empty-text-ab { font:13px/1.6 system-ui; max-width:280px; } 218/* ââ Settings modal âââââââââââââââââââââââââââââââââââââââââââââââââââââââ */ 219.settings-overlay-ab { position:fixed; inset:0; z-index:49000; display:grid; place-items:center; background:rgba(2,6,23,.75); backdrop-filter:blur(4px); } 220.settings-panel-ab { width:min(540px,92vw); max-height:85vh; overflow-y:auto; background:#0f172a; border:1px solid rgba(148,163,184,.22); border-radius:12px; box-shadow:0 20px 60px rgba(0,0,0,.55); color:#f8fafc; } 221.settings-header-ab { display:flex; align-items:center; justify-content:space-between; padding:14px 18px; border-bottom:1px solid rgba(148,163,184,.15); position:sticky; top:0; background:#0f172a; z-index:1; } 222.settings-title-ab { font:700 14px/1 system-ui; letter-spacing:.4px; } 223.settings-close-ab { background:none; border:none;
223 color:rgba(148,163,184,.8); font-size:16px; cursor:pointer; padding:2px 6px; border-radius:4px; line-height:1; } 224.settings-close-ab:hover { color:#f1f5f9; background:rgba(255,255,255,.08); } 225.settings-body-ab { padding:16px 18px 20px; } 226.settings-row-ab { display:flex; flex-direction:column; gap:4px; margin-bottom:14px; } 227.settings-row-ab label { font:600 10px/1 system-ui; letter-spacing:.7px; text-transform:uppercase; color:rgba(100,116,139,.9); } 228.settings-row-ab input[type="text"], .settings-row-ab input[type="number"], .settings-row-ab select { padding:6px 10px; border:1px solid #334155; border-radius:6px; background:#1e293b; color:#e2e8f0; font:13px system-ui; outline:none; } 229.settings-row-ab input[type="text"]:focus, .settings-row-ab input[type="number"]:focus, .settings-row-ab select:focus { border-color:#60a5fa; } 230.settings-input-ab { width:100%; box-sizing:border-box; padding:7px 10px; border:1px solid #334155; border-radius:6px; background:#1e293b; color:#e2e8f0; font:13px system-ui; outline:none; } 231.settings-input-ab:focus { border-color:#7c3aed; } 232.settings-row-ab input[type="checkbox"] { width:16px; height:16px; cursor:pointer; } 233.settings-row-ab .settings-check-row-ab { display:flex; align-items:center; gap:8px; } 234.settings-row-ab .settings-check-row-ab span { font:13px system-ui; color:#cbd5e1; } 235.settings-section-title-ab { font:700 11px/1 system-ui; letter-spacing:.5px; text-transform:uppercase; color:#64748b; margin:18px 0 10px; padding-bottom:6px; border-bottom:1px solid #1e293b; } 236.settings-footer-ab { display:flex; justify-content:flex-end; gap:8px; margin-top:20px; padding-top:14px; border-top:1px solid #1e293b; } 237/* ââ Live component styles ââââââââââââââââââââââââââââââââââââââââââââââââ */ 238.lc-btn-ab { display:inline-flex; align-items:center; justify-content:center; padding:8px 18px; background:#0d6efd; color:#fff; border:none; border-radius:6px; font:600 14px/1.4 system-ui; cursor:default; } 239.lc-btn-sec-ab { background:#6c757d; } 240.lc-btn-suc-ab { background:#198754; } 241.lc-btn-dan-ab { background:#dc3545; } 242.lc-btn-out-ab { background:transparent; color:#0d6efd; border:2px solid #0d6efd; } 243.lc-label-ab { display:block; font:600 13px system-ui; color:#374151; margin-bottom:4px; } 244.lc-input-ab { display:block; width:100%; padding:8px 12px; box-sizing:border-box; border:1px solid #ced4da; border-radius:6px; font:14px system-ui; color:#374151; background:#fff; outline:none; } 245.lc-textarea-ab { display:block; width:100%; padding:8px 12px; box-sizing:border-box; border:1px solid #ced4da; border-radius:6px; font:14px system-ui; color:#374151; background:#fff; resize:vertical; min-height:80px; outline:none; } 246.lc-select-ab { display:block; width:100%; padding:8px 12px; box-sizing:border-box; border:1px solid #ced4da; border-radius:6px; font:14px system-ui; color:#374151; background:#fff; } 247.lc-checkbox-row-ab { display:flex; align-items:center; gap:8px; font:14px system-ui; color:#374151; } 248.lc-range-ab { width:100%; accent-color:#0d6efd; margin:6px 0; } 249.lc-toggle-row-ab { display:flex; align-items:center; gap:8px; font:14px system-ui; color:#374151; } 250.lc-toggle-track-ab { width:44px; height:24px; background:#dee2e6; border-radius:12px; position:relative; flex-shrink:0; } 251.lc-toggle-track-ab.on { background:#0d6efd; } 252.lc-toggle-thumb-ab { position:absolute; top:3px; left:3px; width:18px; height:18px; background:#fff; border-radius:50%; transition:left .15s; } 253.lc-toggle-track-ab.on .lc-toggle-thumb-ab { left:23px; } 254.lc-card-ab { background:#fff; border:1px solid #dee2e6; border-radius:8px; overflow:hidden; box-shadow:0 1px 4px rgba(0,0,0,.07); } 255.lc-card-header-ab { padding:10px 16px; background:#f8f9fa; border-bottom:1px solid #dee2e6; font:600 14px system-ui; color:#212529; } 256.lc-card-body-ab { padding:16px; font:14px/1.6 system-ui; color:#495057; } 257.lc-title-ab { font:700 26px/1.3 system-ui; color:#111827; margin:0 0 4px; } 258.lc-subtitle-ab { font:600 17px/1.4 system-ui; color:#6b7280; margin:0 0 2px; } 259.lc-text-ab { font:14px/1.6 system-ui; color:#374151; margin:0; } 260/* Tabs. The strip scrolls rather than wrapping: the Android TabRow keeps every tab 261 on one line, and a tab bar that reflows moves the operator's target between 262 renders. The pointer-events:auto below re-enables hit-testing on the tab buttons 263 alone - .live-inner-ab is inert, so the component stays selectable and draggable 264 by its body while only the tabs themselves take the click. 265 NOTE: this whole stylesheet is a JS template literal - no backticks in here. */ 266.lc-tabs-ab { border-bottom:2px solid var(--ab-comp-border, #dee2e6); display:flex; gap:0; 267 overflow-x:auto; overflow-y:hidden; scrollbar-width:none; flex:0 0 auto; 268 /* Pinned to tabModel.TAB_STRIP_H - a docked child is positioned against the pane 269 top, so the strip cannot be allowed to size itself off its own font metrics. */ 270 height:40px; box-sizing:border-box; align-items:stretch; } 271.lc-tabs-ab::-webkit-scrollbar { display:none; } 272.lc-tab-ab { padding:0 18px; font:14px system-ui; color:var(--ab-text-muted, #6b7280); cursor:pointer; 273 display:flex; align-items:center; 274 border-bottom:3px solid transparent; margin-bottom:-2px; white-space:nowrap; pointer-events:auto; 275 max-width:180px; overflow:hidden; text-overflow:ellipsis; } 276.lc-tab-ab:hover { color:var(--ab-comp-text, #334155); background:rgba(148,163,184,.12); } 277.lc-tab-ab.active { color:var(--ab-comp-accent, #0d6efd); border-bottom-color:var(--ab-comp-accent, #0d6efd); font-weight:600; } 278.lc-tab-pane-ab { position:relative; } 279/* A tabs container with docked children keeps its strip (like a card keeps its 280 title) â only the empty-pane hint goes away, and only for tabs that have one. */ 281.comp-wrap-ab[data-comp-type="tabs"].has-docked-children-ab { outline:none; } 282.comp-wrap-ab[data-comp-type="tabs"] .lc-tab-hint-ab { display:none; } 283.comp-wrap-ab[data-comp-type="tabs"].tab-pane-empty-ab .lc-tab-hint-ab { 284 display:block; margin:8px 0 0; padding:0 4px; font:13px/1.5 system-ui; 285 color:var(--ab-text-muted, #6b7280); opacity:.75; } 286.lc-nav-ab { display:flex; align-items:center; background:#212529; padding:0 16px; height:52px; border-radius:6px; gap:4px; } 287.lc-nav-brand-ab { color:#fff; font:700 16px system-ui; margin-right:20px; flex-shrink:0; } 288.lc-nav-link-ab { color:#adb5bd; font:14px system-ui; padding:0 12px; } 289.lc-nav-link-ab.active { color:#fff; } 290.lc-stackedmenu-ab { background:#fff; border:1px solid #dee2e6; border-radius:8px; overflow:hidden; } 291.lc-smenu-item-ab { display:flex; align-items:center; gap:10px; padding:10px 14px; font:14px system-ui; color:#374151; border-bottom:1px solid #f3f4f6; cursor:default; } 292.lc-smenu-item-ab:last-child { border-bottom:none; } 293.lc-smenu-item-ab i { color:#6b7280; font-size:14px; } 294.lc-img-ph-ab { width:100%; background:#f1f5f9; display:flex; align-items:center; justify-content:center; border:1px dashed #cbd5e1; border-radius:6px; color:#94a3b8; font:13px system-ui; gap:6px; height:100%; } 295.lc-media-ph-ab { width:100%; background:#0f172a; display:flex; flex-direction:column; align-items:center; justify-content:center; border-radius:6px; color:#64748b; gap:6px; height:100%; } 296.lc-media-ph-ab i { font-size:32px; } 297.lc-media-ph-ab span { font:12px system-ui; } 298.lc-chart-ph-ab { width:100%; min-height:160px; background:#f8fafc; display:flex; flex-direction:column; align-items:center; justify-content:center; border:1px solid #e2e8f0; border-radius:8px; gap:6px; color:#94a3b8; height:100%; } 299.lc-chart-ph-ab i { font-size:36px; opacity:.45; } 300.lc-chart-ph-ab .lc-chart-label-ab { font:13px system-ui; color:#64748b; } 301.lc-table-ab { width:100%; border-collapse:collapse; font:13px system-ui; } 302.lc-table-ab th { padding:8px 12px; background:#f1f5f9; border:1px solid #e2e8f0; font:600 13px system-ui; color:#374151; text-align:left; } 303.lc-table-ab td { padding:7px 12px; border:1px solid #e2e8f0; color:#6b7280; } 304.lc-counter-ab { display:flex; flex-direction:column; align-items:flex-start; padding:16px 20px; background:#fff; border-radius:8px; border:1px solid #e2e8f0; box-shadow:0 1px 4px rgba(0,0,0,.06); } 305.lc-counter-val-ab { font:700 36px/1 system-ui; color:#0f172a; } 306.lc-counter-label-ab { font:12px system-ui; color:#64748b; margin-top:4px; }
307/* ââ Badge (Controls) â its own component, not a metric-card internal ââ */ 308.lc-badge-ab { display:inline-block; font-size:10px; font-weight:700; padding:2px 8px; border-radius:999px; background:#eef2f6; color:#475569; letter-spacing:.02em; } 309/* ââ Progress Bar (Controls) â its own component ââ */ 310.lc-progress-row-ab { display:flex; align-items:center; gap:8px; font:600 11px system-ui; color:#475569; width:100%; } 311.lc-progress-ab { height:9px; background:#e8edf3; border-radius:999px; overflow:hidden; flex:1; } 312.lc-progress-fill-ab { display:block; height:100%; border-radius:999px; background:linear-gradient(90deg,#34d399,#10b981); transition:width .3s; } 313.lc-progress-lbl-ab { white-space:nowrap; } 314/* Unbound data part â visibly flagged; NEVER shows plausible fake data (safety readout) */ 315.lc-unbound-ab { outline:1px dashed #f59e0b; outline-offset:1px; color:#b45309 !important; background:#fffbeb !important; font-style:italic; } 316/* Alert rule tripped (live value crossed the band) â the safety RED state */ 317.lc-alert-on-ab { box-shadow:0 0 0 2px #ef4444 inset; border-radius:8px; background:#fef2f2; } 318.lc-alert-on-ab .lc-counter-val-ab, .lc-alert-on-ab .lc-badge-ab, .lc-alert-on-ab .lc-card-header-ab { color:#dc2626 !important; } 319/* Reuse the existing "card" control as a card container: when parts dock into it, keep 320 the card shell on the wrap (the placeholder body fades via container-template-ab). */ 321/* Card as a container: it keeps its OWN shell (.lc-card-ab) + title; just drop the 322 dashed dock outline and hide the empty-body hint once real children are inside. */ 323.comp-wrap-ab[data-comp-type="card"].has-docked-children-ab { outline:none; } 324.comp-wrap-ab[data-comp-type="card"].has-docked-children-ab .lc-card-body-ab { display:none; } 325.lc-status-ab { display:inline-flex; align-items:center; gap:6px; padding:5px 12px; background:#f0fdf4; border-radius:20px; border:1px solid #bbf7d0; font:13px/1 system-ui; color:#15803d; } 326.lc-status-dot-ab { width:8px; height:8px; background:#22c55e; border-radius:50%; flex-shrink:0; } 327.lc-gauge-ab { display:flex; flex-direction:column; align-items:center; padding:14px 20px; background:#fff; border-radius:8px; border:1px solid #e2e8f0; box-shadow:0 1px 4px rgba(0,0,0,.06); } 328.lc-gauge-arc-ab { width:100px; height:55px; border:8px solid #e2e8f0; border-bottom:none; border-radius:60px 60px 0 0; position:relative; } 329.lc-gauge-arc-fill-ab { position:absolute; inset:-8px; bottom:0; border:8px solid #0d6efd; border-bottom:none; border-radius:60px 60px 0 0; clip-path:polygon(0 100%,55% 0%,100% 100%); } 330.lc-gauge-val-ab { font:700 20px/1 system-ui; color:#0f172a; margin-top:6px; } 331.lc-gauge-label-ab { font:11px system-ui; color:#64748b; margin-top:2px; } 332.lc-stream-card-ab { background:#fff; border:1px solid #e2e8f0; border-radius:8px; padding:12px 16px; display:flex; align-items:center; gap:12px; box-shadow:0 1px 4px rgba(0,0,0,.06); } 333.lc-stream-icon-ab { font-size:24px; color:#0d6efd; flex-shrink:0; } 334.lc-stream-info-ab { flex:1; } 335.lc-stream-title-ab { font:600 13px system-ui; color:#374151; } 336.lc-stream-val-ab { font:700 20px/1.2 system-ui; color:#0f172a; } 337.lc-window-ab { background:#fff; border:1px solid #dee2e6; border-radius:8px; overflow:hidden; box-shadow:0 4px 16px rgba(0,0,0,.08); height:100%; } 338.lc-window-bar-ab { display:flex; align-items:center; gap:6px; padding:8px 12px; background:#f8f9fa; border-bottom:1px solid #dee2e6; user-select:none; } 339.lc-window-dot-ab { width:10px; height:10px; border-radius:50%; } 340.lc-window-body-ab { padding:16px; min-height:60px; font:14px/1.6 system-ui; color:#374151; } 341.lc-form-ab { background:#fff; border:1px solid #dee2e6; border-radius:8px; overflow:hidden; height:100%; } 342.lc-form-header-ab { padding:10px 16px; background:#f8f9fa; border-bottom:1px solid #dee2e6; font:600 14px system-ui; color:#374151; } 343.lc-form-body-ab { padding:16px; display:flex; flex-direction:column; gap:12px; overflow:auto; } 344.lc-collapsible-ab { border:1px solid #dee2e6; border-radius:6px; overflow:hidden; } 345.lc-coll-head-ab { display:flex; align-items:center; justify-content:space-between; padding:10px 14px; background:#f8f9fa; font:600 14px system-ui; color:#374151; cursor:default; } 346.lc-coll-body-ab { padding:12px 14px; font:14px system-ui; color:#6b7280; } 347.lc-comment-ab { background:#fefce8; border:1px solid #fde68a; border-radius:8px; padding:12px 16px; font:14px/1.5 system-ui; color:#78350f; } 348.lc-radial-ab { display:flex; align-items:center; gap:10px; flex-wrap:wrap; padding:12px; background:#fff; border-radius:50%; width:120px; height:120px; border:1px solid #dee2e6; justify-content:center; color:#6b7280; font:12px system-ui; text-align:center; } 349.lc-menu-item-ab { display:flex; align-items:center; gap:8px; padding:8px 12px; background:#f8f9fa; border:1px solid #e2e8f0; border-radius:6px; font:13px system-ui; color:#374151; } 350.lc-menu-item-ab i { color:#6b7280; } 351.lc-carousel-ab { width:100%; min-height:160px; background:#e9ecef; display:flex; align-items:center; justify-content:space-between; border-radius:8px; padding:16px; box-sizing:border-box; gap:12px; color:#6b7280; height:100%; } 352.lc-carousel-arrow-ab { font-size:24px; color:#adb5bd; flex-shrink:0; } 353.lc-carousel-content-ab { flex:1; display:flex; flex-direction:column; align-items:center; gap:6px; font:13px system-ui; } 354.lc-carousel-content-ab i { font-size:32px; opacity:.5; } 355.lc-group-outline-ab { border:2px dashed #a5b4fc; border-radius:6px; min-height:60px; background:rgba(99,102,241,.04); padding:4px; } 356/* ââ Live data indicator (edit mode) âââââââââââââââââââââââââââââââââââ */ 357.live-data-active-ab { 358 position:relative; 359} 360.live-data-active-ab::after {
361 content:''; 362 position:absolute; 363 top:2px; right:2px; 364 width:6px; height:6px; 365 background:#22c55e; 366 border-radius:50%; 367 box-shadow:0 0 4px rgba(34,197,94,.6); 368 animation:live-pulse-ab 2s ease-in-out infinite; 369} 370@keyframes live-pulse-ab { 371 0%, 100% { opacity:1; transform:scale(1); } 372 50% { opacity:.6; transform:scale(0.85); } 373} 374/* ââ Mapping diagnostics panel âââââââââââââââââââââââââââââââââââââââââââ */ 375.mapping-diagnostics-ab { 376 border-bottom:1px solid #cbd5e1; background:#f8fafc; padding:6px 8px; 377 max-height:120px; overflow:auto; 378} 379.mapping-diag-ok-ab { font:600 11px/1.4 system-ui; color:#166534; } 380.mapping-diag-list-ab { display:flex; flex-direction:column; gap:4px; } 381.mapping-diag-row-ab { 382 font:600 11px/1.4 system-ui; padding:4px 6px; border-radius:4px; border:1px solid transparent; 383} 384.mapping-diag-row-ab.is-warning { color:#92400e; background:#fffbeb; border-color:#fcd34d; } 385.mapping-diag-row-ab.is-error { color:#991b1b; background:#fef2f2; border-color:#fca5a5; } 386 387/* ââ Widget mapping status badge âââââââââââââââââââââââââââââââââââââââââ */ 388.mapping-health-badge-ab { 389 position:absolute; top:4px; right:4px; z-index:9; 390 border-radius:999px; padding:2px 6px; font:700 9px/1 system-ui; 391 border:1px solid #cbd5e1; background:#fff; color:#334155; 392} 393.mapping-health-badge-ab[data-status="connected"] { background:#ecfdf5; border-color:#86efac; color:#166534; } 394.mapping-health-badge-ab[data-status="connecting"] { background:#eff6ff; border-color:#93c5fd; color:#1d4ed8; } 395.mapping-health-badge-ab[data-status="error"] { background:#fef2f2; border-color:#fca5a5; color:#b91c1c; } 396 397/* ââ Data binding strip (edit mode only) ââââââââââââââââââââââââââââââââ */ 398.bind-strip-ab { 399 position:absolute; bottom:0; left:0; right:0; z-index:8; 400 background:rgba(37,99,235,.82); color:#fff; font:600 9px/1 system-ui; 401 display:flex; align-items:center; gap:4px; padding:2px 5px; 402 border-radius:0 0 3px 3px; letter-spacing:.2px; pointer-events:auto; 403 backdrop-filter:blur(2px); min-height:16px; overflow:hidden; 404} 405.bind-strip-ab i { font-size:9px; opacity:.85; flex-shrink:0; } 406.bind-strip-ab .bind-key-ab { flex:1; min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; } 407.bind-strip-ab .bind-btn-ab { 408 flex-shrink:0; background:rgba(255,255,255,.2); border:none; border-radius:3px; 409 color:#fff; font:600 8px system-ui; cursor:pointer; padding:1px 5px; line-height:1.6; 410 transition:background .1s; 411} 412.bind-strip-ab .bind-btn-ab:hover { background:rgba(255,255,255,.38); } 413/* ââ Data binding modal âââââââââââââââââââââââââââââââââââââââââââââââââ */ 414.bind-modal-overlay-ab { 415 position:fixed; inset:0; z-index:52000; display:grid; place-items:center; 416 background:rgba(2,6,23,.72); backdrop-filter:blur(4px); 417} 418.bind-modal-ab { 419 width:min(420px,90vw); background:#0f172a; border:1px solid rgba(148,163,184,.22); 420 border-radius:10px; box-shadow:0 20px 60px rgba(0,0,0,.55); color:#f8fafc; 421 font:14px system-ui; overflow:hidden; max-height:min(92vh,860px); display:flex; flex-direction:column; 422} 423.bind-modal-header-ab { 424 display:flex; align-items:center; justify-content:space-between; 425 padding:12px 16px; background:#1e293b; border-bottom:1px solid rgba(148,163,184,.15); 426} 427.bind-modal-title-ab { font:700 13px/1 system-ui; letter-spacing:.3px; } 428.bind-modal-close-ab { 429 background:none; border:none; color:rgba(148,163,184,.8); font-size:16px; 430 cursor:pointer; padding:2px 6px; border-radius:4px; line-height:1; 431} 432.bind-modal-close-ab:hover { color:#f1f5f9; background:rgba(255,255,255,.08); } 433.bind-modal-body-ab { 434 padding:16px; display:flex; flex-direction:column; gap:10px; 435 overflow-y:auto; overscroll-behavior:contain; 436} 437.bind-modal-body-ab label { font:600 10px/1 system-ui; letter-spacing:.6px; text-transform:uppercase; color:rgba(100,116,139,.9); } 438.bind-modal-body-ab input { 439 padding:7px 10px; border:1px solid #334155; border-radius:6px; 440 background:#1e293b; color:#e2e8f0; font:13px system-ui; outline:none; width:100%; box-sizing:border-box; 441}
442.bind-modal-body-ab input:focus { border-color:#60a5fa; } 443.bind-modal-body-ab input[type="checkbox"] { 444 width:auto; justify-self:flex-start; accent-color:#3b82f6; 445} 446.bind-map-select-ab { 447 width:100%; padding:7px 10px; border:1px solid #334155; border-radius:6px; 448 background:#1e293b; color:#e2e8f0; font:13px system-ui; outline:none; box-sizing:border-box; 449 transition: border-color .15s ease, box-shadow .15s ease, background .15s ease; 450} 451.bind-map-select-ab:focus { border-color:#60a5fa; } 452.bind-map-drop-target-ab { border-color:#38bdf8 !important; box-shadow:0 0 0 2px rgba(56,189,248,.28); background:#1b2a44; } 453.bind-modal-hint-ab { font:11px/1.5 system-ui; color:#64748b; } 454.bind-modal-section-ab { 455 border:1px solid rgba(148,163,184,.22); 456 border-radius:8px; 457 background:rgba(15,23,42,.6); 458} 459.bind-modal-section-title-ab { 460 list-style:none; 461 cursor:pointer; 462 padding:10px 12px; 463 font:700 11px/1 system-ui; 464 letter-spacing:.5px; 465 text-transform:uppercase; 466 color:#cbd5e1; 467 display:flex; 468 align-items:center; 469 gap:8px; 470} 471.bind-modal-section-title-ab::-webkit-details-marker { display:none; } 472.bind-modal-section-title-ab::before { 473 content:"â¸"; 474 color:#60a5fa; 475 font-size:11px; 476 transform:translateY(-.5px); 477} 478.bind-modal-section-ab[open] .bind-modal-section-title-ab::before { content:"â¾"; } 479.bind-modal-section-content-ab { 480 padding:0 12px 12px; 481 display:grid; 482 grid-template-columns:repeat(2, minmax(0, 1fr)); 483 gap:10px 12px; 484} 485.bind-modal-field-row-ab { 486 display:flex; 487 flex-direction:column; 488 gap:6px; 489 min-width:0; 490} 491.bind-modal-field-row-full-ab { grid-column:1 / -1; } 492.bind-modal-field-row-checkbox-ab input[type="checkbox"] { 493 margin-top:2px; 494 justify-self:flex-start; 495} 496.bind-modal-footer-ab { 497 display:flex; justify-content:flex-end; gap:8px; 498 padding:12px 16px; border-top:1px solid #1e293b; 499} 500@media (max-width:700px) { 501 .bind-modal-section-content-ab { grid-template-columns:1fr; } 502} 503/* ââ FeBe field picker ââââââââââââââââââââââââââââââââââââââââââââââââââ */ 504.bind-field-picker-ab { 505 max-height:180px; overflow-y:auto; border:1px solid #334155; border-radius:6px; 506 background:#1e293b; margin-top:4px; 507} 508.bind-field-picker-ab::-webkit-scrollbar { width:6px; } 509.bind-field-picker-ab::-webkit-scrollbar-track { background:#1e293b; border-radius:3px; } 510.bind-field-picker-ab::-webkit-scrollbar-thumb { background:#475569; border-radius:3px; } 511.bind-stream-header-ab { 512 font:600 10px/1 system-ui; letter-spacing:.5px; text-transform:uppercase; 513 color:#94a3b8; padding:8px 10px 4px; border-bottom:1px solid #334155; 514 background:#0f172a; position:sticky; top:0; z-index:1; 515} 516.bind-field-item-ab { 517 padding:6px 12px; cursor:pointer; font:12px system-ui; color:#cbd5e1; 518 border-bottom:1px solid rgba(51,65,85,.5); display:flex; align-items:center; gap:6px; 519 transition:background .1s; 520} 521.bind-field-item-ab:last-child { border-bottom:none; } 522.bind-field-item-ab:hover { background:rgba(96,165,250,.15); color:#f8fafc; } 523.bind-field-item-ab i { font-size:10px; color:#60a5fa; } 524.bind-no-streams-ab { 525 padding:16px; text-align:center; color:#64748b; font:12px system-ui; 526} 527.bind-no-streams-ab i { font-size:20px; display:block; margin-bottom:6px; opacity:.5; } 528/* ââ Pivot chart placeholder ââââââââââââââââââââââââââââââââââââââââââââ */ 529.lc-pivot-ph-ab { 530 width:100%; height:100%; background:#f8fafc; border:1px solid #e2e8f0; 531 border-radius:8px; display:flex; flex-direction:column; 532 align-items:stretch; overflow:hidden; font:12px system-ui; color:#374151; 533} 534.lc-pivot-header-ab { 535 background:#1e293b; color:#94a3b8; font:600 10px/1 system-ui; 536 padding:6px 10px; display:flex; align-items:center; gap:6px; flex-shrink:0; 537} 538.lc-pivot-header-ab i { font-size:12px; color:#60a5fa; } 539.lc-pivot-lib-label-ab { margin-left:auto; font:10px system-ui; opacity:.6; } 540.lc-pivot-body-ab { flex:1; display:grid; overflow:hidden; } 541.lc-pivot-table-ab { width:100%; border-collapse:collapse; font:11px system-ui; } 542.lc-pivot-table-ab th { 543 padding:5px 8px; background:#e2e8f0; border:1px solid #cbd5e1; 544 font:600 10px system-ui; color:#475569; text-align:center; white-space:nowrap; 545} 546.lc-pivot-table-ab td { 547 padding:4px 8px; border:1px solid #e2e8f0; color:#374151; 548 text-align:right; font:11px system-ui; 549} 550.lc-pivot-table-ab tr:nth-child(even) td { background:#f1f5f9; } 551.lc-pivot-table-ab td.pivot-row-hdr-ab { 552 text-align:left; font-weight:600; color:#475569; background:#f8fafc; 553} 554/* ââ Map placeholder ââââââââââââââââââââââââââââââââââââââââââââââââââââ */ 555.lc-map-ph-ab { 556 width:100%; height:100%; position:relative; border-radius:8px; 557 overflow:hidden; background:#c8d9e6; border:1px solid #b0c4d8; 558 display:flex; flex-direction:column; 559} 560.lc-map-tiles-ab { 561 flex:1; position:relative; overflow:hidden; 562 background:repeating-linear-gradient( 563 0deg, rgba(255,255,255,.12) 0px, rgba(255,255,255,.12) 1px, transparent 1px, transparent 40px 564 ), 565 repeating-linear-gradient( 566 90deg, rgba(255,255,255,.12) 0px, rgba(255,255,255,.12) 1px, transparent 1px, transparent 40px 567 ), 568 linear-gradient(135deg, #a8c5da 0%, #c8d9e6 40%, #b5cfe0 70%, #9fbcd4 100%); 569} 570.lc-map-road-h-ab { 571 position:absolute; top:40%; left:0; right:0; height:6px; 572 background:rgba(255,255,255,.7); border-radius:1px; 573} 574.lc-map-road-v-ab {
575 position:absolute; top:0; bottom:0; left:35%; width:6px; 576 background:rgba(255,255,255,.7); border-radius:1px; 577} 578.lc-map-block-ab { 579 position:absolute; background:rgba(150,170,140,.55); 580 border:1px solid rgba(120,145,110,.4); border-radius:2px; 581} 582.lc-map-pin-ab { 583 position:absolute; width:18px; height:22px; 584 display:flex; flex-direction:column; align-items:center; 585} 586.lc-map-pin-head-ab { 587 width:14px; height:14px; border-radius:50% 50% 50% 0; 588 transform:rotate(-45deg); border:2px solid #fff; 589 box-shadow:0 1px 4px rgba(0,0,0,.3); 590} 591.lc-map-pin-tail-ab { width:2px; height:6px; margin-top:1px; border-radius:0 0 2px 2px; } 592.lc-map-cluster-ab { 593 position:absolute; width:24px; height:24px; border-radius:50%; 594 background:rgba(37,99,235,.8); border:2px solid #fff; color:#fff; 595 font:700 9px system-ui; display:flex; align-items:center; justify-content:center; 596 box-shadow:0 1px 6px rgba(0,0,0,.3); 597} 598.lc-map-ctrl-bar-ab { 599 position:absolute; top:6px; right:6px; display:flex; flex-direction:column; gap:3px; 600} 601.lc-map-ctrl-btn-ab { 602 width:22px; height:22px; background:rgba(255,255,255,.9); 603 border:1px solid rgba(0,0,0,.2); border-radius:3px; display:flex; 604 align-items:center; justify-content:center; font-size:10px; color:#374151; 605 cursor:default; box-shadow:0 1px 3px rgba(0,0,0,.15); 606} 607.lc-map-zoom-bar-ab { 608 position:absolute; bottom:6px; right:6px; display:flex; flex-direction:column; 609 background:rgba(255,255,255,.9); border:1px solid rgba(0,0,0,.2); 610 border-radius:3px; overflow:hidden; box-shadow:0 1px 3px rgba(0,0,0,.15); 611} 612.lc-map-zoom-btn-ab { 613 width:22px; height:22px; display:flex; align-items:center; 614 justify-content:center; font:700 14px system-ui; color:#374151; 615 cursor:default; line-height:1; 616} 617.lc-map-zoom-btn-ab + .lc-map-zoom-btn-ab { border-top:1px solid rgba(0,0,0,.15); } 618.lc-map-draw-bar-ab { 619 position:absolute; top:6px; left:6px; display:flex; flex-direction:column; gap:3px; 620} 621.lc-map-attr-ab { 622 flex-shrink:0; padding:2px 6px; background:rgba(255,255,255,.75); 623 font:9px system-ui; color:#374151; text-align:right; 624} 625.lc-map-badge-ab { 626 position:absolute; bottom:24px; left:6px; background:rgba(0,0,0,.6); 627 color:#fff; font:600 9px system-ui; padding:2px 6px; border-radius:3px; 628 letter-spacing:.3px; 629} 630/* ââ Toast notifications ââââââââââââââââââââââââââââââââââââââââââââââââ */ 631.toast-host-ab { 632 position:fixed; bottom:20px; right:20px; z-index:99999; 633 display:flex; flex-direction:column; gap:8px; pointer-events:none; 634 max-width:380px; 635} 636.toast-ab { 637 display:flex; align-items:flex-start; gap:8px; 638 padding:10px 12px; border-radius:7px; border:1px solid transparent; 639 font:13px/1.45 system-ui; box-shadow:0 4px 18px rgba(0,0,0,.35); 640 pointer-events:all; opacity:0; transform:translateY(8px); 641 transition:opacity .22s ease, transform .22s ease; 642 min-width:220px; 643} 644.toast-ab.toast-visible-ab { opacity:1; transform:translateY(0); } 645.toast-error-ab { background:#1c0b0b; border-color:#dc2626; color:#fca5a5; } 646.toast-warning-ab { background:#1c1408; border-color:#d97706; color:#fcd34d; } 647.toast-success-ab { background:#071c0f; border-color:#16a34a; color:#86efac; } 648.toast-info-ab { background:#0c1730; border-color:#2563eb; color:#93c5fd; } 649.toast-icon-ab { font-size:14px; flex-shrink:0; margin-top:1px; } 650.toast-msg-ab { flex:1; word-break:break-word; } 651.toast-close-ab { 652 background:none; border:none; cursor:pointer; font-size:12px; 653 opacity:.6; padding:0 2px; margin-top:1px; color:inherit; flex-shrink:0; 654 line-height:1; 655} 656.toast-close-ab:hover { opacity:1; } 657/* ââ Diagnostics panel (enhanced) âââââââââââââââââââââââââââââââââââââââ */ 658.mapping-diagnostics-ab { 659 font:11px system-ui; background:#0f172a; border-bottom:1px solid #1e293b; 660 padding:0; flex-shrink:0; overflow:hidden; 661 transition:max-height .2s ease; 662 max-height:200px; 663} 664.mapping-diagnostics-ab.diag-collapsed-ab { max-height:28px; } 665.diag-header-ab { 666 display:flex; align-items:center; gap:6px; padding:4px 10px; 667 background:#1e293b; border-bottom:1px solid #334155; 668 cursor:pointer; user-select:none; 669} 670.diag-header-title-ab { 671 font:700 10px system-ui; color:#94a3b8; letter-spacing:.05em; 672 text-transform:uppercase; flex:1; 673} 674.diag-header-status-ab { 675 font:10px system-ui; color:#64748b; 676} 677.diag-toggle-ab { 678 background:none; border:none;
678 color:#64748b; cursor:pointer; 679 font-size:10px; padding:0 2px; 680} 681.diag-body-ab { 682 overflow-y:auto; max-height:172px; padding:4px 0; 683} 684.diag-body-ab::-webkit-scrollbar { width:4px; } 685.diag-body-ab::-webkit-scrollbar-thumb { background:#334155; border-radius:2px; } 686.diag-section-ab { 687 padding:3px 10px; 688} 689.diag-section-title-ab { 690 font:700 9px system-ui; color:#475569; text-transform:uppercase; 691 letter-spacing:.05em; padding:2px 0; 692} 693.mapping-diag-ok-ab { 694 padding:6px 10px; color:#22c55e; font:11px system-ui; 695} 696.mapping-diag-list-ab { } 697.mapping-diag-row-ab { 698 padding:3px 10px 3px 12px; font:11px/1.4 system-ui; 699 border-left:2px solid transparent; cursor:default; 700 white-space:nowrap; overflow:hidden; text-overflow:ellipsis; 701} 702.mapping-diag-row-ab.is-error { color:#f87171; border-left-color:#dc2626; } 703.mapping-diag-row-ab.is-warning { color:#fcd34d; border-left-color:#d97706; } 704.diag-server-row-ab { 705 display:flex; align-items:center; gap:6px; 706 padding:2px 10px; font:11px/1.4 system-ui; color:#94a3b8; 707} 708.diag-server-dot-ab { 709 width:7px; height:7px; border-radius:50%; flex-shrink:0; 710 background:#64748b; 711} 712.diag-server-dot-ok-ab { background:#22c55e; } 713.diag-server-dot-error-ab { background:#ef4444; } 714.diag-server-dot-pending-ab { background:#f59e0b; } 715/* ââ Undo/Redo toolbar buttons âââââââââââââââââââââââââââââââââââââââââââ */ 716.btn-undo-ab, .btn-redo-ab { 717 padding:4px 8px; font-size:13px; 718} 719.btn-undo-ab:disabled, .btn-redo-ab:disabled { 720 opacity:.25; cursor:default; pointer-events:none; 721} 722/* ââ Chart customization modal ââââââââââââââââââââââââââââââââââââââââââââ */ 723.chart-custom-overlay-ab { 724 position:fixed; inset:0; z-index:52000; display:grid; place-items:center; 725 background:rgba(2,6,23,.72); backdrop-filter:blur(4px); 726} 727.chart-custom-modal-ab { 728 width:min(480px,94vw); background:#0f172a; border:1px solid rgba(148,163,184,.22); 729 border-radius:10px; box-shadow:0 20px 60px rgba(0,0,0,.55); color:#f8fafc; 730 font:14px system-ui; overflow:hidden; max-height:min(92vh,780px); display:flex; flex-direction:column; 731} 732.chart-custom-header-ab { 733 display:flex; align-items:center; justify-content:space-between; 734 padding:12px 16px; background:#1e293b; border-bottom:1px solid rgba(148,163,184,.15); 735} 736.chart-custom-title-ab { font:700 13px/1 system-ui; letter-spacing:.3px; } 737.chart-custom-close-ab { 738 background:none; border:none; color:rgba(148,163,184,.8); font-size:16px; 739 cursor:pointer; padding:2px 6px; border-radius:4px; line-height:1; 740} 741.chart-custom-close-ab:hover { color:#f1f5f9; background:rgba(255,255,255,.08); } 742.chart-custom-body-ab { 743 padding:16px; display:flex; flex-direction:column; gap:12px; 744 overflow-y:auto; overscroll-behavior:contain; 745} 746.chart-custom-field-ab { display:flex; flex-direction:column; gap:5px; } 747.chart-custom-field-ab label { 748 font:600 10px/1 system-ui; letter-spacing:.6px; text-transform:uppercase; 749 color:rgba(100,116,139,.9); 750} 751.chart-custom-field-ab input[type="text"], 752.chart-custom-field-ab input[type="number"], 753.chart-custom-field-ab textarea, 754.chart-custom-field-ab select { 755 padding:7px 10px; border:1px solid #334155; border-radius:6px; 756 background:#1e293b; color:#e2e8f0; font:13px system-ui; outline:none; 757 width:100%; box-sizing:border-box; 758} 759.chart-custom-field-ab input[type="text"]:focus, 760.chart-custom-field-ab input[type="number"]:focus, 761.chart-custom-field-ab textarea:focus, 762.chart-custom-field-ab select:focus { border-color:#60a5fa; } 763.chart-custom-field-ab textarea { 764 min-height:132px; resize:vertical; font:12px/1.5 ui-monospace, SFMono-Regular, Menlo, monospace; 765} 766.chart-custom-row2-ab { display:grid; grid-template-columns:1fr 1fr; gap:12px; } 767.chart-custom-series-group-ab { display:flex; flex-direction:column; gap:10px; } 768.chart-custom-series-card-ab { 769 display:flex; flex-direction:column; gap:8px; padding:10px; 770 border:1px solid rgba(148,163,184,.15); border-radius:8px; background:rgba(15,23,42,.45); 771} 772.chart-custom-series-heading-ab { 773 font:700 11px/1 system-ui; letter-spacing:.4px; text-transform:uppercase; color:#cbd5e1; 774} 775.chart-custom-series-row-ab { display:grid; grid-template-columns:repeat(auto-fit,minmax(180px,1fr)); gap:12px; }
776.chart-custom-checkbox-row-ab { display:flex; align-items:center; gap:8px; } 777.chart-custom-checkbox-row-ab input[type="checkbox"] { 778 accent-color:#3b82f6; width:14px; height:14px; flex-shrink:0; 779} 780.chart-custom-checkbox-row-ab label { 781 font:12px system-ui; color:#cbd5e1; text-transform:none; letter-spacing:0; 782} 783.chart-custom-hint-ab { font:11px/1.5 system-ui; color:#64748b; } 784.chart-custom-footer-ab { 785 display:flex; justify-content:flex-end; gap:8px; 786 padding:12px 16px; border-top:1px solid #1e293b; 787} 788/* chart style button inside the per-component bind strip */ 789.bind-strip-ab .chart-style-btn-ab { 790 flex-shrink:0; background:rgba(16,185,129,.25); border:none; border-radius:3px; 791 color:#6ee7b7; font:600 8px system-ui; cursor:pointer; padding:1px 5px; line-height:1.6; 792 transition:background .1s; 793} 794.bind-strip-ab .chart-style-btn-ab:hover { background:rgba(16,185,129,.45); } 795@media (max-width:700px) { 796 .chart-custom-row2-ab { grid-template-columns:1fr; } 797 .chart-custom-series-row-ab { grid-template-columns:1fr; } 798} 799 800/* ââ RoadDefender tablet shelf âââââââââââââââââââââââââââââââââââââââââââââ 801 Every value is traced to zim-mobile/RoadDefender (branch \`live\`): 802 ui/theme/RoadDefenderTheme.kt for the tokens, app/src/tablet/.../zim for the 803 composables. Each colour reads a --rd-* variable with the RoadDefenderTheme.kt 804 value as its FALLBACK, so the shelf renders under the four generic themes too â 805 picking the RoadDefender theme is what makes it match the device rather than 806 merely resemble it. 807 Density note: the tablet is a dark, high-contrast, tight-radius surface. The 808 generic AppBuilder widgets are light with 8px radii and roomy padding, which is 809 why an AppBuilder mock reads as "close but not it". These use RdShapes (8/12/18) 810 and RdSpacing (4/8/12/16/24) exactly. */ 811 812.rd-section-ab { 813 width:100%; height:100%; box-sizing:border-box; position:relative; 814 background:var(--ab-comp-bg,#000); color:var(--ab-comp-text,#fff); 815 border:1px solid var(--ab-comp-border,#2a2a2a); 816 border-radius:var(--rd-radius,12px); padding:var(--rd-md,12px) var(--rd-lg,16px); 817 font:14px/1.35 system-ui; 818} 819.rd-section-title-ab { 820 font:600 12px system-ui; letter-spacing:.06em; text-transform:uppercase; 821 color:var(--ab-text-muted,#9e9e9e); margin-bottom:var(--rd-sm,8px); 822} 823.rd-section-body-ab { min-height:24px; } 824.rd-section-rule-ab { 825 position:absolute; left:var(--rd-lg,16px); right:var(--rd-lg,16px); 826 bottom:var(--rd-md,12px); height:1px; background:rgba(255,255,255,.12); 827} 828 829/* Stat / CompactStat / LiveStat â label, value, unit, AGE. */ 830.rd-stat-ab { 831 width:100%; height:100%; box-sizing:border-box; display:flex; flex-direction:column; 832 justify-content:center; gap:2px; padding:var(--rd-sm,8px) var(--rd-md,12px); 833 background:var(--ab-comp-bg,#000); border:1px solid var(--ab-comp-border,#2a2a2a); 834 border-radius:var(--rd-radius-sm,8px); font-family:system-ui; 835} 836.rd-stat-label-ab { 837 font:600 10px system-ui; letter-spacing:.08em; text-transform:uppercase; 838 color:var(--ab-text-muted,#9e9e9e); 839} 840.rd-stat-row-ab { display:flex; align-items:baseline; gap:4px; } 841.rd-stat-val-ab { font:600 26px/1 system-ui; color:var(--ab-comp-text,#fff); } 842.rd-stat-unit-ab { font:500 12px system-ui; color:var(--ab-text-muted,#9e9e9e); } 843.rd-stat-age-ab { font:400 10px system-ui; color:var(--rd-neutral,#9e9e9e); opacity:.8; } 844.rd-stat-ab[data-sev="danger"] .rd-stat-val-ab { color:var(--rd-danger,#e53935); } 845.rd-stat-ab[data-sev="caution"] .rd-stat-val-ab { color:var(--rd-caution,#ffa000); } 846.rd-stat-ab[data-sev="hazard"] .rd-stat-val-ab { color:var(--rd-hazard,#ff9800); } 847.rd-stat-ab[data-sev="safe"] .rd-stat-val-ab { color:var(--rd-safe,#4caf50); } 848.rd-stat-ab[data-sev="info"] .rd-stat-val-ab { color:var(--rd-info,#2196f3); } 849 850/* SpeedHeadline â the one number you read from across the cab. */ 851.rd-headline-ab { 852 width:100%; height:100%; box-sizing:border-box; display:flex; flex-direction:column; 853 align-items:center; justify-content:center; gap:var(--rd-xs,4px); 854 background:var(--ab-comp-bg,#000); border-radius:var(--rd-radius,12px); 855 font-family:system-ui; 856} 857.rd-headline-val-ab { 858 font:700 56px/1 system-ui; color:var(--rd-scheme2,#ffa000); 859 display:flex; align-items:baseline; gap:6px; 860} 861.rd-headline-unit-ab { font:600 18px system-ui; color:var(--ab-text-muted,#9e9e9e); } 862.rd-headline-label-ab { 863 font:600 11px system-ui; letter-spacing:.12em; text-transform:uppercase; 864 color:var(--ab-text-muted,#9e9e9e); 865} 866 867/* FilterChip row â Material3 chips: pill, 1px outline, filled when selected. */ 868.rd-chiprow-ab { 869 width:100%; height:100%; box-sizing:border-box; display:flex; align-items:center; 870 flex-wrap:wrap; gap:var(--rd-sm,8px); font-family:system-ui; 871} 872.rd-chip-ab { 873 display:inline-flex; align-items:center; height:32px; padding:0 var(--rd-md,12px); 874 border:1px solid var(--ab-comp-border,#2a2a2a); border-radius:var(--rd-radius-sm,8px); 875 font:500 13px system-ui; color:var(--ab-comp-text,#fff); white-space:nowrap; 876} 877.rd-chip-on-ab { 878 background:var(--rd-scheme2,#ffa000); border-color:var(--rd-scheme2,#ffa000); 879 color:#000; font-weight:600; 880} 881 882/* InvalidationBanner / OfflineBanner / Warn. */ 883.rd-banner-ab { 884 width:100%; height:100%; box-sizing:border-box; display:flex; align-items:center; 885 gap:var(--rd-sm,8px); padding:0 var(--rd-md,12px); border-radius:var(--rd-radius,12px); 886 font:600 13px system-ui; 887} 888.rd-banner-icon-ab { font-size:14px; flex-shrink:0; opacity:.9; } 889.rd-banner-text-ab { overflow:hidden; text-overflow:ellipsis; white-space:nowrap; } 890.rd-banner-ab[data-sev="caution"] { background:rgba(255,160,0,.16); color:var(--rd-caution,#ffa000); } 891.rd-banner-ab[data-sev="danger"] { background:rgba(229,57,53,.16); color:var(--rd-danger,#e53935); } 892.rd-banner-ab[data-sev="hazard"] { background:rgba(255,152,0,.16);
892 color:var(--rd-hazard,#ff9800); } 893.rd-banner-ab[data-sev="safe"] { background:rgba(76,175,80,.16); color:var(--rd-safe,#4caf50); } 894.rd-banner-ab[data-sev="info"] { background:rgba(33,150,243,.16); color:var(--rd-info,#2196f3); } 895.rd-banner-ab[data-sev="neutral"] { background:rgba(158,158,158,.16); color:var(--rd-neutral,#9e9e9e); } 896 897/* SeverityCard â the state itself is the widget. */ 898.rd-sevcard-ab { 899 width:100%; height:100%; box-sizing:border-box; display:flex; align-items:center; 900 justify-content:center; border-radius:var(--rd-radius,12px); 901} 902.rd-sevcard-label-ab { font:700 22px system-ui; letter-spacing:.06em; } 903.rd-sevcard-ab[data-sev="caution"] { background:var(--rd-caution,#ffa000); color:#000; } 904.rd-sevcard-ab[data-sev="danger"] { background:var(--rd-danger,#e53935); color:#fff; } 905.rd-sevcard-ab[data-sev="hazard"] { background:var(--rd-hazard,#ff9800); color:#000; } 906.rd-sevcard-ab[data-sev="safe"] { background:var(--rd-safe,#4caf50); color:#000; } 907.rd-sevcard-ab[data-sev="info"] { background:var(--rd-info,#2196f3); color:#000; } 908.rd-sevcard-ab[data-sev="neutral"] { background:var(--rd-neutral,#9e9e9e); color:#000; } 909 910/* ViLadderCard â rungs top-down, most severe first. */ 911.rd-ladder-ab { 912 width:100%; height:100%; box-sizing:border-box; display:flex; flex-direction:column; 913 gap:var(--rd-xs,4px); padding:var(--rd-md,12px); 914 background:var(--ab-comp-bg,#000); border:1px solid var(--ab-comp-border,#2a2a2a); 915 border-radius:var(--rd-radius,12px); font-family:system-ui; overflow:hidden; 916} 917.rd-ladder-title-ab { 918 font:600 11px system-ui; letter-spacing:.1em; text-transform:uppercase; 919 color:var(--ab-text-muted,#9e9e9e); margin-bottom:var(--rd-xs,4px); 920} 921.rd-rung-ab { 922 display:flex; align-items:center; gap:var(--rd-sm,8px); flex:1; min-height:28px; 923 padding:0 var(--rd-sm,8px); border-radius:var(--rd-radius-sm,8px); 924 font:600 13px system-ui; color:var(--ab-text-muted,#9e9e9e); 925 border:1px solid transparent; 926} 927.rd-rung-dot-ab { width:10px; height:10px; border-radius:50%; background:currentColor; flex-shrink:0; opacity:.45; } 928.rd-rung-ab[data-sev="danger"] { color:var(--rd-danger,#e53935); } 929.rd-rung-ab[data-sev="caution"] { color:var(--rd-caution,#ffa000); } 930.rd-rung-ab[data-sev="hazard"] { color:var(--rd-hazard,#ff9800); } 931.rd-rung-ab[data-sev="safe"] { color:var(--rd-safe,#4caf50); } 932.rd-rung-ab[data-sev="neutral"] { color:var(--rd-neutral,#9e9e9e); } 933.rd-rung-on-ab { border-color:currentColor; background:rgba(255,255,255,.06); } 934.rd-rung-on-ab .rd-rung-dot-ab { opacity:1; } 935 936/* TrailBar â a segmented history meter, not a single-value progress bar. */ 937.rd-trail-ab { 938 width:100%; height:100%; box-sizing:border-box; display:flex; flex-direction:column; 939 gap:var(--rd-xs,4px); justify-content:center; font-family:system-ui; 940} 941.rd-trail-label-ab { 942 font:600 10px system-ui; letter-spacing:.08em; text-transform:uppercase; 943 color:var(--ab-text-muted,#9e9e9e); 944} 945.rd-trail-track-ab { display:flex; gap:2px; height:16px; } 946.rd-trail-seg-ab { 947 flex:1; border-radius:2px; background:rgba(255,255,255,.10); 948 border:1px solid var(--ab-comp-border,#2a2a2a); 949} 950 951/* SettingRow / LimitRow / Field â a key/value line, not a table cell. */ 952.rd-setrow-ab { 953 width:100%; height:100%; box-sizing:border-box; display:flex; align-items:center; 954 justify-content:space-between; gap:var(--rd-md,12px); padding:0 var(--rd-md,12px); 955 border-bottom:1px solid var(--ab-comp-border,#2a2a2a); font:14px system-ui; 956 color:var(--ab-comp-text,#fff); 957} 958.rd-setrow-label-ab { color:var(--ab-text-muted,#9e9e9e); } 959.rd-setrow-val-ab { font-weight:600; display:inline-flex; align-items:baseline; gap:4px; } 960.rd-setrow-unit-ab { font:500 11px system-ui; color:var(--ab-text-muted,#9e9e9e); } 961 962/* AppTile â the TabletLauncherActivity launcher tile. */ 963.rd-apptile-ab { 964 width:100%; height:100%; box-sizing:border-box; display:flex; flex-direction:column; 965 align-items:center; justify-content:center; gap:var(--rd-sm,8px); 966 background:var(--ab-comp-bg,#000); border:1px solid var(--ab-comp-border,#2a2a2a); 967 border-radius:var(--rd-radius-lg,18px); font-family:system-ui; 968 min-height:var(--rd-touch,48px); 969} 970.rd-apptile-icon-ab { font-size:30px; color:var(--rd-scheme1,#2196f3); } 971.rd-apptile-label-ab { 972 font:600 13px system-ui; letter-spacing:.04em; color:var(--ab-comp-text,#fff); 973} 974 975/* ConfirmDialog. */ 976.rd-dialog-ab { 977 width:100%; height:100%; box-sizing:border-box; display:flex; flex-direction:column; 978 gap:var(--rd-sm,8px); padding:var(--rd-lg,16px); 979 background:var(--ab-surface,#141414); border:1px solid var(--ab-comp-border,#2a2a2a); 980 border-radius:var(--rd-radius-lg,18px); box-shadow:0 12px 32px rgba(0,0,0,.55); 981 font-family:system-ui; color:var(--ab-comp-text,#fff); 982} 983.rd-dialog-title-ab { font:600 16px system-ui; } 984.rd-dialog-msg-ab { font:14px/1.4 system-ui; color:var(--ab-text-muted,#9e9e9e); flex:1; } 985.rd-dialog-actions-ab { display:flex; justify-content:flex-end; gap:var(--rd-sm,8px); } 986.rd-dialog-cancel-ab, .rd-dialog-confirm-ab { 987 display:inline-flex; align-items:center; height:36px; padding:0 var(--rd-lg,16px); 988 border-radius:var(--rd-radius-sm,8px); font:600 13px system-ui; letter-spacing:.04em; 989} 990.rd-dialog-cancel-ab { color:var(--ab-text-muted,#9e9e9e); border:1px solid var(--ab-comp-border,#2a2a2a); } 991.rd-dialog-confirm-ab { background:var(--rd-caution,#ffa000); color:#000; } 992 993/* LoadingState. */ 994.rd-loading-ab { 995 width:100%; height:100%; box-sizing:border-box; display:flex; flex-direction:column; 996 align-items:center; justify-content:center; gap:var(--rd-sm,8px); font-family:system-ui; 997 color:var(--ab-text-muted,#9e9e9e); 998} 999.rd-loading-spin-ab { 1000 width:26px; height:26px; border-radius:50%; 1001 border:3px solid var(--ab-comp-border,#2a2a2a); 1002 border-top-color:var(--rd-caution,#ffa000); 1003 animation:rd-spin-ab .9s linear infinite; 1004} 1005.rd-loading-msg-ab { font:500 13px system-ui; } 1006@keyframes rd-spin-ab { to { transform:rotate(360deg); } } 1007@media (prefers-reduced-motion:reduce) { .rd-loading-spin-ab { animation:none; } }`; 1008 document.head.appendChild(style); 1009}
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.