/* u_14_2_ver_wifi_3k — horizontal pct, top-aligned with segment 8 */
/* u_14_2_ver_wifi_3h — bigger pct, rotated 180° */
/* u_14_2_ver_wifi_3f — bigger rotated pct font */
:root {
  --bg:#0b0f14; --bg-1:#131923; --bg-2:#1a2230; --bg-3:#232d3d;
  --border:#2a3546; --border-hi:#3d4a60;
  --fg:#e6edf3; --fg-dim:#8b96a5; --fg-mute:#5b6878;
  --accent:#58a6ff; --accent-2:#1f6feb;
  --green:#2ecc71; --green-dim:#1e8449;
  --amber:#f39c12; --red:#e74c3c; --purple:#a371f7;
  --mono:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;
  --sans:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Helvetica,Arial,sans-serif;
  --shadow:0 10px 30px rgba(0,0,0,.6);
  --bank-X:#22d3a7; --bank-Y:#fbbf24; --bank-M:#60a5fa; --bank-D:#c084fc;
  --bank-T:#fb7185; --bank-C:#fb923c; --bank-S:#22d3ee; --bank-K:#94a3b8;
  --bank-P:#818cf8; --bank-I:#a3e635; --bank-F:#e879f9;
  --NODE_W:112px;
}
[data-theme="light"] {
  --bg:#f6f8fa; --bg-1:#ffffff; --bg-2:#eef1f5; --bg-3:#e1e6ec;
  --border:#d0d7de; --border-hi:#aeb6c0;
  --fg:#1f2328; --fg-dim:#57606a; --fg-mute:#8c95a0;
  --accent:#0969da; --accent-2:#0550ae;
  --green:#1a7f37; --green-dim:#2da44e; --amber:#9a6700; --red:#cf222e;
  --shadow:0 10px 30px rgba(140,149,159,.2);
  --bank-X:#059669; --bank-Y:#b45309; --bank-M:#1d4ed8; --bank-D:#7c3aed;
  --bank-T:#be123c; --bank-C:#c2410c; --bank-S:#0e7490; --bank-K:#475569;
  --bank-P:#3730a3; --bank-I:#4d7c0f; --bank-F:#a21caf; --bank-A:#0d9488;
}
* { box-sizing:border-box; -webkit-tap-highlight-color:transparent; }
html,body { height:100%; margin:0; }
body { font-family:var(--sans); background:var(--bg); color:var(--fg);
       font-size:14px; line-height:1.5; overflow:hidden; -webkit-font-smoothing:antialiased; }
button,input,select,textarea { font:inherit; color:inherit; }
a { color:var(--accent); text-decoration:none; }
::-webkit-scrollbar { width:10px; height:10px; }
::-webkit-scrollbar-track { background:transparent; }
::-webkit-scrollbar-thumb { background:var(--bg-3); border-radius:6px; border:2px solid var(--bg); }
.btn { display:inline-flex; align-items:center; gap:6px; padding:7px 12px;
       border:1px solid var(--border); border-radius:6px; background:var(--bg-2);
       color:var(--fg); cursor:pointer; font-size:13px; font-weight:500;
       white-space:nowrap; transition:background .12s,border-color .12s; }
.btn:hover:not(:disabled) { background:var(--bg-3); border-color:var(--border-hi); }
.btn:disabled { opacity:.45; cursor:not-allowed; }
.btn.primary { background:var(--green-dim); border-color:var(--green-dim); color:#fff; }
.btn.primary:hover:not(:disabled) { background:var(--green); }
.btn.danger { background:#6e1c1c; border-color:#8b2c2c; color:#ffd7d5; }
.btn.ghost { background:transparent; border-color:transparent; }
.btn.ghost:hover:not(:disabled) { background:var(--bg-3); }
.btn.sm { padding:4px 9px; font-size:12px; }
.btn.active { background:var(--accent-2); color:#fff; border-color:var(--accent-2); }
.shell { display:flex; flex-direction:column; height:100vh; }
.topbar { display:flex; align-items:center; gap:8px; padding:8px 14px;
          border-bottom:1px solid var(--border); background:var(--bg-1); flex:0 0 auto;
          overflow-x:auto; }
.brand { font-weight:700; font-size:14px; letter-spacing:.3px;
         display:flex; align-items:center; gap:8px; margin-right:8px; flex:0 0 auto; }
.brand .dot { width:8px; height:8px; border-radius:50%; background:var(--green);
              box-shadow:0 0 8px var(--green); }
.spacer { flex:1; }
.topbar .user { font-size:12px; color:var(--fg-dim); padding:4px 10px;
                border:1px solid var(--border); border-radius:999px; flex:0 0 auto; }
.workspace { display:flex; flex:1; min-height:0; position:relative; }
.sidebar { width:250px; flex:0 0 auto; border-right:1px solid var(--border);
           background:var(--bg-1); display:flex; flex-direction:column; min-height:0;
           transition:margin-left .18s ease; }
.sidebar.hidden { display:none; }
.main { flex:1; display:flex; flex-direction:column; min-width:0; min-height:0;
        position:relative; }
.rightbar { width:340px; flex:0 0 auto; border-left:1px solid var(--border);
            background:var(--bg-1); display:flex; flex-direction:column; min-height:0;
            transition:margin-right .18s ease; }
.rightbar.hidden { display:none; }
.panel-toggle {
  position:absolute; top:50%; transform:translate(-50%, -50%);
  width:14px; height:46px; padding:0; z-index:55;
  background:var(--bg-2); border:1px solid var(--border);
  color:var(--fg-dim); cursor:pointer;
  display:flex; align-items:center; justify-content:center;
  font-size:11px; font-weight:700; line-height:1; border-radius:4px;
  transition:background .12s, color .12s, border-color .12s;
}
.panel-toggle:hover { background:var(--accent-2); border-color:var(--accent-2); color:#fff; }
.panel-toggle-left  { left:0; transform:translate(-50%, -50%); }
.panel-toggle-right { right:0; transform:translate(50%, -50%); }
.search-wrap { padding:10px; border-bottom:1px solid var(--border); background:var(--bg-1); z-index:5; }
.search-wrap input { width:100%; padding:8px 10px; background:var(--bg);
                     border:1px solid var(--border); border-radius:6px; font-size:13px; outline:none; }
.palette { flex:1; overflow-y:auto; padding:4px 0 20px; }
.pal-group { margin-bottom:4px; }
.pal-head { display:flex; align-items:center; gap:6px; padding:6px 12px 6px 14px;
            font-size:11px; font-weight:700; text-transform:uppercase;
            letter-spacing:.6px; cursor:pointer; user-select:none;
            border-left:3px solid transparent; }
.pal-head .arrow { font-size:9px; transition:transform .15s; }
.pal-group.collapsed .arrow { transform:rotate(-90deg); }
.pal-group.collapsed .pal-items { display:none; }
.pal-item { padding:6px 12px 6px 22px; font-size:12.5px; cursor:grab;
            border-left:3px solid transparent; color:var(--fg-dim); user-select:none;
            display:flex; align-items:center; gap:8px; }
.pal-item:hover { background:var(--bg-2); color:var(--fg); }
.pal-item svg { flex:0 0 auto; }
.pal-item.bank-X { border-left-color:var(--bank-X); }
.pal-item.bank-Y { border-left-color:var(--bank-Y); }
.pal-item.bank-M { border-left-color:var(--bank-M); }
.pal-item.bank-D { border-left-color:var(--bank-D); }
.pal-item.bank-T { border-left-color:var(--bank-T); }
.pal-item.bank-C { border-left-color:var(--bank-C); }
.pal-item.bank-S { border-left-color:var(--bank-S); }
.pal-item.bank-K { border-left-color:var(--bank-K); }
.pal-item.bank-P { border-left-color:var(--bank-P); }
.pal-item.bank-I { border-left-color:var(--bank-I); }
.pal-item.bank-F { border-left-color:var(--bank-F); }
.pal-item.gate   { border-left-color:var(--border-hi); }
.editor-tabs { display:flex; align-items:center; gap:2px; padding:6px 10px 0;
               background:var(--bg-1); border-bottom:1px solid var(--border);
               flex:0 0 auto; overflow-x:auto; }
.tab { padding:6px 14px; font-size:12px; border:1px solid transparent;
       border-bottom:none; border-radius:6px 6px 0 0; color:var(--fg-dim);
       cursor:pointer; white-space:nowrap; display:flex; align-items:center; gap:5px; }
.tab.active { background:var(--bg); border-color:var(--border); color:var(--fg); margin-bottom:-1px; }
.tab:hover:not(.active) { color:var(--fg); }
.tab.disabled { opacity:.5; text-decoration:line-through; }
.tab .tab-lock { font-size:10px; opacity:.8; }
.view-toggle { display:flex; gap:6px; padding:6px 10px;
               border-bottom:1px solid var(--border); background:var(--bg-1);
               align-items:center; flex-wrap:wrap; }
.tool-sep { width:1px; height:22px; background:var(--border); margin:0 4px; }
.tool-btn { display:inline-flex; align-items:center; gap:6px; padding:5px 11px;
            border:1px solid var(--border); border-radius:6px; background:var(--bg-2);
            cursor:pointer; font-size:12px; color:var(--fg-dim);
            transition:background .12s,color .12s,border-color .12s; }
.tool-btn:hover { background:var(--bg-3); color:var(--fg); }
.tool-btn.active { background:var(--accent-2); color:#fff; border-color:var(--accent-2); }
.tool-color { width:30px; height:26px; border:1px solid var(--border); border-radius:6px;
              cursor:pointer; background:var(--bg-2); padding:2px; }
.tool-select { padding:5px 8px; border:1px solid var(--border); border-radius:6px;
               background:var(--bg-2); color:var(--fg); font-size:12px; cursor:pointer; }
.canvas-wrap { flex:1; position:relative; overflow:hidden; min-height:0; background:var(--bg);
               display:flex; flex-direction:column; }
.graph-canvas { position:relative; flex:1; min-height:200px; overflow:auto;
                -webkit-overflow-scrolling:touch;
                background-color:var(--bg);
                background-image:linear-gradient(rgba(255,255,255,.03) 1px, transparent 1px),
                                 linear-gradient(90deg, rgba(255,255,255,.03) 1px, transparent 1px);
                background-size:20px 20px; outline:none; }
[data-theme="light"] .graph-canvas {
  background-image:linear-gradient(rgba(0,0,0,.05) 1px, transparent 1px),
                   linear-gradient(90deg, rgba(0,0,0,.05) 1px, transparent 1px); }
.canvas-scroll { position:relative; }
.canvas-surface { position:absolute; top:0; left:0; transform-origin:0 0; }
.graph-svg { position:absolute; top:0; left:0; width:100%; height:100%;
             pointer-events:none; overflow:visible; z-index:1; }
.graph-node-layer { position:absolute; top:0; left:0; width:100%; height:100%;
                    z-index:10; pointer-events:none; }
.graph-node-layer > * { pointer-events:auto; }
.zone-layer { position:absolute; top:0; left:0; width:100%; height:100%;
              z-index:5; pointer-events:none; }
.tab-lock-overlay { position:absolute; inset:0; z-index:80;
                    backdrop-filter:blur(8px) saturate(.6);
                    -webkit-backdrop-filter:blur(8px) saturate(.6);
                    background:rgba(11,15,20,.35);
                    display:flex; align-items:flex-start; justify-content:flex-start;
                    padding:24px; pointer-events:auto; }
.tab-lock-card { pointer-events:auto; width:100%; max-width:320px;
                 background:var(--bg-1); border:1px solid var(--border-hi);
                 border-radius:10px; padding:16px 18px; box-shadow:var(--shadow);
                 display:flex; flex-direction:column; gap:10px; }
.tab-lock-card h3 { margin:0; font-size:13px; }
.tab-lock-card p  { margin:0; font-size:12px; color:var(--fg-dim); }
.tab-lock-card input { width:100%; padding:9px 11px; background:var(--bg);
                       border:1px solid var(--border); border-radius:6px;
                       font-family:var(--mono); outline:none; }
.tab-lock-card input:focus { border-color:var(--accent); }
.tab-lock-card .err { margin-top:0; }
.marquee-count { position:absolute; padding:4px 10px; background:var(--accent-2);
                 color:#fff; font-size:11px; font-weight:700; border-radius:999px;
                 pointer-events:none; z-index:100; font-family:var(--mono);
                 box-shadow:0 4px 12px rgba(0,0,0,.5); }
.zone { position:absolute; border-radius:12px;
        background:color-mix(in oklab, var(--zone-color) 14%, transparent);
        border:2px dashed var(--zone-color);
        pointer-events:none; transition:background .15s; }
.zone-header { position:absolute; top:-14px; left:10px;
               display:flex; align-items:center; gap:6px;
               padding:2px 10px 2px 10px; background:var(--bg-1);
               border:1px solid var(--zone-color); border-radius:6px;
               font-size:11px; font-weight:600; color:var(--zone-color);
               cursor:grab; white-space:nowrap; pointer-events:auto;
               box-shadow:0 2px 6px rgba(0,0,0,.35); user-select:none; }
.zone-header:active { cursor:grabbing; }
.zone-actions { display:flex; gap:2px; margin-left:4px; }
.zone-btn { width:16px; height:16px; padding:0; border:0; border-radius:3px;
            background:transparent; color:var(--zone-color); cursor:pointer;
            font-size:11px; line-height:1; }
.zone-btn.danger:hover { background:var(--red); color:#fff; }
.zone-resize {
  position:absolute; width:12px; height:12px;
  background:var(--bg-1);
  border:2px solid var(--zone-color, var(--accent));
  border-radius:3px; z-index:10; pointer-events:auto;
  opacity:0; transition:opacity .15s, background .15s, border-color .15s;
}
.zone:hover .zone-resize { opacity:1; }
.zone-resize:hover { background:var(--accent); border-color:var(--accent); }
.zone-resize-nw { top:-6px;    left:-6px;   cursor:nwse-resize; }
.zone-resize-ne { top:-6px;    right:-6px;  cursor:nesw-resize; }
.zone-resize-sw { bottom:-6px; left:-6px;   cursor:nesw-resize; }
.zone-resize-se { bottom:-6px; right:-6px;  cursor:nwse-resize; }
.marquee-box { position:absolute; pointer-events:none; z-index:40;
               border:1.5px dashed var(--accent); background:rgba(88,166,255,.06);
               border-radius:4px; }
.marquee-box.filter-blocks { border-color:var(--green); background:rgba(46,204,113,.06); }
.marquee-box.filter-wires  { border-color:var(--amber); background:rgba(243,156,18,.06); }
.graph-wire { fill:none; stroke:#5c7cfa; stroke-width:2.5; stroke-linecap:round;
              transition:stroke .15s, stroke-width .15s;
              filter:drop-shadow(0 1px 2px rgba(0,0,0,.4)); }
.graph-wire-hit { fill:none; stroke:transparent; stroke-width:14; stroke-linecap:round;
                  cursor:pointer; pointer-events:stroke; }
.graph-wire.selected { stroke:#f0a020 !important; stroke-width:3.5;
                       filter:drop-shadow(0 0 6px #f0a020); }
.graph-wire.temp   { stroke:var(--accent); stroke-dasharray:6 4; }
.graph-wire.live {
  stroke:#2ecc71; stroke-width:3; stroke-dasharray:8 5;
  animation: currentFlow .7s linear infinite;
  filter:drop-shadow(0 0 6px rgba(46,204,113,.95));
}
@keyframes currentFlow { to { stroke-dashoffset:-26; } }
.graph-wire.magnet { stroke:#2ecc71; stroke-width:3; stroke-dasharray:6 5; opacity:.9;
                     filter:drop-shadow(0 0 8px #2ecc71); animation:magnetPulse 1s infinite; }
@keyframes magnetPulse { 0%,100% { opacity:.6; } 50% { opacity:1; } }
.wire-end { fill:#5c7cfa; }
.wire-end.selected { fill:#f0a020; }
.wire-end.live { fill:#2ecc71; }
.guide-line { stroke:#f0a020; stroke-width:1; stroke-dasharray:5 5; opacity:.9; }
.rung-rail {
  position:absolute; left:22px; top:15px; bottom:15px; width:6px;
  background:linear-gradient(180deg, #4c8bf5 0%, #1f6feb 100%);
  border-radius:3px;
  box-shadow:0 0 14px rgba(88,166,255,.45), inset 0 0 6px rgba(255,255,255,.25);
  z-index:2; pointer-events:none; transition:background .25s, box-shadow .25s;
}
.rung-rail::after { content:''; position:absolute; inset:-3px;
  border:1px solid rgba(88,166,255,.25); border-radius:6px; transition:border-color .25s; }
.rung-rail.state-run { background:linear-gradient(180deg, #2ecc71 0%, #1e8449 100%);
  box-shadow:0 0 22px rgba(46,204,113,.85); }
.rung-rail.state-pause { background:linear-gradient(180deg, #f39c12 0%, #b8770a 100%);
  box-shadow:0 0 18px rgba(243,156,18,.65); }
.rung-rail.state-monitor { background:linear-gradient(180deg, #a371f7 0%, #6b3dbf 100%);
  box-shadow:0 0 18px rgba(163,113,247,.65); }
.rung-connector { fill:none; stroke:#2ecc71; stroke-width:3; stroke-linecap:round;
                  filter:drop-shadow(0 0 4px rgba(46,204,113,.7)); }
.rung-connector.idle { stroke:#2a3546; filter:none; }
.graph-node.on-rail { border-color:#2ecc71 !important;
                     box-shadow:0 0 0 2px rgba(46,204,113,.35), 0 2px 8px rgba(0,0,0,.4); }
.graph-node {
  position:absolute; width:var(--NODE_W); min-height:46px;
  padding:2px 7px;
  background:var(--bg-2); border:2px solid var(--border-hi);
  border-radius:8px; cursor:grab; user-select:none; font-size:12px;
  box-shadow:0 2px 6px rgba(0,0,0,.35);
  display:flex; flex-direction:column; justify-content:center; align-items:center;
  transition:border-color .12s, background .12s;
}
.graph-node:hover { border-color:var(--accent); }
.graph-node.selected { outline:2px dashed var(--accent); outline-offset:2px; }
.graph-node.type-coil  { border-radius:14px; }
.graph-node.type-AND,.graph-node.type-OR,.graph-node.type-NOT,
.graph-node.type-XOR,.graph-node.type-NAND,.graph-node.type-NOR,
.graph-node.type-XNOR { border-radius:4px; }
.graph-node.bank-X { border-color:var(--bank-X); background:color-mix(in oklab, var(--bank-X) 10%, var(--bg-2)); }
.graph-node.bank-Y { border-color:var(--bank-Y); background:color-mix(in oklab, var(--bank-Y) 10%, var(--bg-2)); }
.graph-node.bank-M { border-color:var(--bank-M); background:color-mix(in oklab, var(--bank-M) 10%, var(--bg-2)); }
.graph-node.bank-D { border-color:var(--bank-D); background:color-mix(in oklab, var(--bank-D) 10%, var(--bg-2)); }
.graph-node.bank-T { border-color:var(--bank-T); background:color-mix(in oklab, var(--bank-T) 10%, var(--bg-2)); }
.graph-node.bank-C { border-color:var(--bank-C); background:color-mix(in oklab, var(--bank-C) 10%, var(--bg-2)); }
.graph-node.bank-S { border-color:var(--bank-S); background:color-mix(in oklab, var(--bank-S) 10%, var(--bg-2)); }
.graph-node.bank-K { border-color:var(--bank-K); background:color-mix(in oklab, var(--bank-K) 10%, var(--bg-2)); }
.graph-node.bank-P { border-color:var(--bank-P); background:color-mix(in oklab, var(--bank-P) 10%, var(--bg-2)); }
.graph-node.bank-I { border-color:var(--bank-I); background:color-mix(in oklab, var(--bank-I) 10%, var(--bg-2)); }
.graph-node.bank-F { border-color:var(--bank-F); background:color-mix(in oklab, var(--bank-F) 10%, var(--bg-2)); }
.graph-node.is-on  { box-shadow:0 0 0 2px currentColor, 0 0 20px -2px currentColor; }
.gnode-name { font-family:var(--mono); font-size:12px; font-weight:700;
              letter-spacing:.2px; text-align:center; width:100%;
              white-space:nowrap; overflow:hidden; text-overflow:ellipsis;
              color:var(--accent); line-height:1.15; }
.graph-node.bank-X .gnode-name { color:var(--bank-X); }
.graph-node.bank-Y .gnode-name { color:var(--bank-Y); }
.graph-node.bank-M .gnode-name { color:var(--bank-M); }
.graph-node.bank-D .gnode-name { color:var(--bank-D); }
.graph-node.bank-T .gnode-name { color:var(--bank-T); }
.graph-node.bank-C .gnode-name { color:var(--bank-C); }
.graph-node.bank-S .gnode-name { color:var(--bank-S); }
.graph-node.bank-K .gnode-name { color:var(--bank-K); }
.graph-node.bank-P .gnode-name { color:var(--bank-P); }
.graph-node.bank-I .gnode-name { color:var(--bank-I); }
.graph-node.bank-F .gnode-name { color:var(--bank-F); }
.gnode-icon { display:flex; justify-content:center; align-items:center;
              margin:1px 0; min-height:0; width:100%; color:var(--fg); }
.gnode-icon svg { display:block; height:22px; width:44px; }
.gnode-comment { font-size:8px; color:var(--fg-mute); font-style:italic;
                 text-align:center; width:100%; min-height:9px; line-height:1.1;
                 white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.gnode-out-value { position:absolute; right:6px; top:50%; transform:translateY(-50%);
                   font-family:var(--mono); font-size:9px; font-weight:800;
                   padding:1px 4px; border-radius:3px;
                   background:var(--bg-1); color:var(--fg-mute);
                   pointer-events:none; z-index:5;
                   border:1px solid var(--border);
                   min-width:24px; text-align:center; letter-spacing:.3px; }
.gnode-out-value.on   { color:#0a2a12; background:var(--green); border-color:var(--green);
                        box-shadow:0 0 8px rgba(46,204,113,.6); }
.gnode-out-value.off  { color:var(--fg-mute); }
.gnode-out-value.word { color:#0a2a12; background:var(--green); border-color:var(--green);
                        box-shadow:0 0 8px rgba(46,204,113,.6); }
.force-badge { position:absolute; top:-8px; right:-8px; width:18px; height:18px;
               border-radius:50%; background:var(--red); color:#fff;
               font-size:10px; font-weight:900; display:flex; align-items:center; justify-content:center;
               border:2px solid var(--bg-1); cursor:pointer; z-index:20;
               box-shadow:0 0 10px rgba(231,76,60,.9); }
.force-badge:hover { transform:scale(1.2); }
.port { position:absolute; width:14px; height:14px; border-radius:50%;
        background:var(--bg-3); border:2px solid var(--border-hi);
        cursor:crosshair; transition:transform .1s, background .1s, border-color .1s, box-shadow .15s; }
.port:hover { background:var(--accent); border-color:var(--accent); transform:translateY(-50%) scale(1.35); }
.port.connected { background:var(--green); border-color:var(--green); }
.port.in  { left:-8px; top:50%; transform:translateY(-50%); }
.port.out { right:-8px; top:50%; transform:translateY(-50%); }
.port.magnet-target { background:#2ecc71 !important; border-color:#2ecc71 !important;
                      transform:translateY(-50%) scale(1.55) !important;
                      box-shadow:0 0 14px #2ecc71, 0 0 26px rgba(46,204,113,.65); }
.port.snap-target   { background:var(--accent) !important; border-color:var(--accent) !important;
                      transform:translateY(-50%) scale(1.45) !important;
                      box-shadow:0 0 14px var(--accent); }
.port.plus { background:transparent; border:1.5px dashed var(--border-hi);
             width:12px; height:12px; font-size:10px; line-height:1;
             display:flex; align-items:center; justify-content:center;
             color:var(--fg-mute); font-weight:700; }
.port.plus:hover { background:var(--green-dim); border-color:var(--green); color:#fff;
                   transform:translateY(-50%) scale(1.4); }
.palette-ghost { position:fixed; z-index:9999; pointer-events:none;
                 padding:6px 12px; background:var(--bg-1); border:2px dashed var(--accent);
                 border-radius:8px; font-size:12px; color:var(--fg-dim);
                 box-shadow:0 8px 24px rgba(0,0,0,.5); opacity:.9; transform:translate(-50%,-50%); }
.graph-node.palette-preview { pointer-events:none; opacity:.75; border-style:dashed !important; }
.sim-toolbar { display:flex; gap:6px; padding:8px 12px; align-items:center;
               border-top:1px solid var(--border); background:var(--bg-1);
               flex:0 0 auto; flex-wrap:wrap; }
.sim-toolbar .speed-group { display:flex; align-items:center; gap:8px;
                            padding:4px 12px; border:1px solid var(--border);
                            border-radius:8px; background:var(--bg-2); }
.sim-toolbar input[type=range] { width:180px; accent-color:var(--accent); }
.sim-toolbar .speed-val { font-family:var(--mono); font-size:12px;
                          color:var(--accent); min-width:56px; text-align:right; }
.sim-state-badge { padding:5px 14px; border-radius:999px; font-weight:800; font-size:12px;
                   font-family:var(--mono); letter-spacing:1.5px; text-transform:uppercase;
                   border:1px solid var(--border-hi); }
.sim-state-badge { font-size:13px; padding:7px 18px; letter-spacing:2px;
                   box-shadow:0 0 0 1px rgba(255,255,255,.06) inset; }
.sim-state-badge.state-RUN   { background:var(--green); color:#001a0d; border-color:var(--green);
                               box-shadow:0 0 18px rgba(46,204,113,.55); }
.sim-state-badge.state-STOP  { background:var(--bg-3); color:var(--fg-dim); }
.sim-state-badge.state-PAUSE { background:var(--amber); color:#1a0f00; border-color:var(--amber);
                               box-shadow:0 0 18px rgba(243,156,18,.55); }

.sim-btn-run   { background:rgba(46,204,113,.14);  border-color:var(--green); color:var(--green); font-weight:700; }
.sim-btn-run:hover:not(:disabled)   { background:rgba(46,204,113,.28); }
.sim-btn-run.active   { background:var(--green); color:#001a0d; box-shadow:0 0 12px rgba(46,204,113,.6); }
.sim-btn-pause { background:rgba(243,156,18,.14);  border-color:var(--amber); color:var(--amber); font-weight:700; }
.sim-btn-pause:hover:not(:disabled) { background:rgba(243,156,18,.28); }
.sim-btn-pause.active { background:var(--amber); color:#1a0f00; box-shadow:0 0 12px rgba(243,156,18,.6); }
.sim-btn-stop  { background:rgba(231,76,60,.14);   border-color:var(--red);   color:var(--red);   font-weight:700; }
.sim-btn-stop:hover:not(:disabled)  { background:rgba(231,76,60,.28); }
.sim-btn-stop.active  { background:var(--red);   color:#fff;    box-shadow:0 0 12px rgba(231,76,60,.6); }

/* ---- Monitor tab --------------------------------------------------------
   Monitor buttons reuse the same semantics as Simulate but with a colored
   left bar, a slightly squarer shape, and a purple accent for Refresh so
   the tab is visually distinct at a glance. */
.mon-btn-refresh,
.mon-btn-run,
.mon-btn-pause,
.mon-btn-stop {
  border-radius: 5px;
  padding: 5px 12px 5px 10px;
  border-left-width: 3px;
  border-left-style: solid;
  font-weight: 700;
  letter-spacing: .3px;
  transition: background .12s, border-color .12s, color .12s, box-shadow .12s;
}
.mon-btn-refresh {
  background: rgba(163,113,247,.14);
  border-color: var(--border);
  border-left-color: var(--purple);
  color: var(--purple);
}
.mon-btn-refresh:hover:not(:disabled) { background: rgba(163,113,247,.26); }
.mon-btn-refresh:active:not(:disabled) {
  background: var(--purple); color: #0d0817;
  box-shadow: 0 0 12px rgba(163,113,247,.65);
}
.mon-btn-run {
  background: rgba(46,204,113,.14);
  border-color: var(--border);
  border-left-color: var(--green);
  color: var(--green);
}
.mon-btn-run:hover:not(:disabled) { background: rgba(46,204,113,.26); }
.mon-btn-run.active {
  background: var(--green); color: #001a0d; border-left-color: var(--green);
  box-shadow: 0 0 12px rgba(46,204,113,.65);
}
.mon-btn-pause {
  background: rgba(243,156,18,.14);
  border-color: var(--border);
  border-left-color: var(--amber);
  color: var(--amber);
}
.mon-btn-pause:hover:not(:disabled) { background: rgba(243,156,18,.26); }
.mon-btn-pause.active {
  background: var(--amber); color: #1a0f00; border-left-color: var(--amber);
  box-shadow: 0 0 12px rgba(243,156,18,.65);
}
.mon-btn-stop {
  background: rgba(231,76,60,.14);
  border-color: var(--border);
  border-left-color: var(--red);
  color: var(--red);
}
.mon-btn-stop:hover:not(:disabled) { background: rgba(231,76,60,.26); }
.mon-btn-stop.active {
  background: var(--red); color: #fff; border-left-color: var(--red);
  box-shadow: 0 0 12px rgba(231,76,60,.65);
}
.mon-btn-refresh:disabled,
.mon-btn-run:disabled,
.mon-btn-pause:disabled,
.mon-btn-stop:disabled {
  opacity: .38; cursor: not-allowed; box-shadow: none;
}

/* LIVE / OFFLINE pill next to the run-state badge */
.mon-live-badge {
  padding: 5px 12px; border-radius: 999px; font-family: var(--mono);
  font-size: 11px; font-weight: 800; letter-spacing: 1.2px;
  border: 1px solid var(--border);
  transition: background .2s, color .2s, border-color .2s;
}
.mon-live-badge.live {
  background: rgba(46,204,113,.15); color: var(--green);
  border-color: rgba(46,204,113,.45);
  animation: monLivePulse 1.6s ease-in-out infinite;
}
.mon-live-badge.offline {
  background: var(--bg-3); color: var(--fg-dim);
  border-color: var(--border-hi);
}
@keyframes monLivePulse {
  0%, 100% { box-shadow: 0 0 0 0 rgba(46,204,113,.45); }
  50%      { box-shadow: 0 0 0 6px rgba(46,204,113,0); }
}
.mon-dev-label {
  font-size: 12px; color: var(--fg-dim); font-family: var(--mono);
  padding-left: 4px; overflow: hidden; text-overflow: ellipsis;
  white-space: nowrap; max-width: 40vw;
}
.sim-stats { font-size:12px; color:var(--fg-dim); font-family:var(--mono); }
.sim-io-bar { display:flex; gap:14px; padding:10px 12px; overflow-x:auto;
              border-top:1px solid var(--border); background:var(--bg-1);
              flex:0 0 auto; min-height:52px; align-items:center; flex-wrap:wrap; }
.sim-io-group { display:flex; gap:4px; align-items:center; padding:4px 8px;
                border-radius:8px; background:var(--bg-2);
                border:1px solid var(--border); flex:0 0 auto; flex-wrap:wrap; }
.sim-io-group .sim-io-label { font-family:var(--mono); font-size:11px; font-weight:800;
                             padding-right:8px; border-right:1px solid var(--border);
                             margin-right:4px; letter-spacing:.5px; }
.sim-io-group.bank-X .sim-io-label { color:var(--bank-X); }
.sim-io-group.bank-Y .sim-io-label { color:var(--bank-Y); }
.sim-io-group.bank-M .sim-io-label { color:var(--bank-M); }
.sim-io-group.bank-T .sim-io-label { color:var(--bank-T); }
.sim-io-group.bank-C .sim-io-label { color:var(--bank-C); }
.sim-io-group.bank-S .sim-io-label { color:var(--bank-S); }
.sim-io-btn { padding:5px 9px; font-family:var(--mono); font-size:11px;
              background:var(--bg); border:1px solid var(--border);
              border-radius:5px; cursor:pointer; color:var(--fg-dim);
              transition:background .1s, color .1s, border-color .1s, box-shadow .1s; position:relative; }
.sim-io-btn:hover { border-color:var(--border-hi); color:var(--fg); }
.sim-io-btn.active { background:var(--green); color:#001a0d; border-color:var(--green);
                    font-weight:800; box-shadow:0 0 10px rgba(46,204,113,.65); }
.sim-io-btn.forced { border-color:var(--red) !important; color:var(--red); }
.sim-io-btn.forced.active { background:var(--red); color:#fff; border-color:var(--red); }
.sim-io-btn.forced::after { content:'●'; position:absolute; top:-6px; right:-4px;
                            color:var(--red); font-size:10px; }
.panel { border-bottom:1px solid var(--border); }
.panel-head { display:flex; align-items:center; gap:8px; padding:8px 12px;
              font-size:11px; font-weight:700; text-transform:uppercase;
              letter-spacing:.6px; color:var(--fg-mute); background:var(--bg-1);
              cursor:pointer; user-select:none; }
.panel-body { padding:10px 12px; max-height:340px; overflow-y:auto; }
.device-card { position:relative; background:var(--bg-2); border:1px solid var(--border);
               border-radius:8px; padding:10px 12px; margin-bottom:8px; cursor:pointer; }
.device-card:hover { border-color:var(--border-hi); }
.device-card.active { border-color:var(--accent); }
.device-card .row1 { display:flex; align-items:center; gap:8px; margin-bottom:4px; padding-right:26px; }
.device-card .name { font-weight:600; font-size:13px; }
.device-card .uid  { font-family:var(--mono); font-size:11px; color:var(--fg-mute); }
.device-card .meta { font-size:11px; color:var(--fg-dim); display:flex; gap:10px; flex-wrap:wrap; }
.device-card .gear-btn { position:absolute; top:6px; right:6px; width:24px; height:24px;
                         padding:0; border-radius:6px; background:var(--bg-1); border:1px solid var(--border);
                         color:var(--fg-dim); cursor:pointer; font-size:13px; line-height:1;
                         display:flex; align-items:center; justify-content:center; }
.device-card .gear-btn:hover { background:var(--accent-2); color:#fff; border-color:var(--accent-2); }
.state-pill { font-size:10px; font-weight:700; padding:2px 7px; border-radius:999px;
              text-transform:uppercase; letter-spacing:.4px; }
.state-pill.online  { background:rgba(46,204,113,.15); color:var(--green); }
.state-pill.offline { background:rgba(139,150,165,.15); color:var(--fg-dim); }
.state-pill.RUN     { background:rgba(46,204,113,.15); color:var(--green); }
.state-pill.STOP    { background:rgba(139,150,165,.15); color:var(--fg-dim); }
.state-pill.PAUSE   { background:rgba(243,156,18,.15); color:var(--amber); }
.state-pill.FAULT   { background:rgba(231,76,60,.15);  color:var(--red); }
.watch-table { width:100%; border-collapse:collapse; font-size:12.5px; }
.watch-table th { text-align:left; font-size:10px; text-transform:uppercase;
                  letter-spacing:.5px; color:var(--fg-mute); font-weight:600;
                  padding:4px 6px; border-bottom:1px solid var(--border); }
.watch-table td { padding:5px 6px; font-family:var(--mono); border-bottom:1px solid var(--bg-2); }
.watch-table .val-true  { color:var(--green); font-weight:700; }
.watch-table .val-false { color:var(--fg-mute); }
.watch-table .val-word  { color:var(--green); font-weight:700; }
.watch-empty { color:var(--fg-mute); font-size:12px; padding:8px 2px; }
.log-list { font-family:var(--mono); font-size:11.5px; line-height:1.7; }
.log-line { display:flex; gap:8px; padding:1px 0; }
.log-line .t { color:var(--fg-mute); flex:0 0 auto; }
.log-line.info .m     { color:var(--fg-dim); }
.log-line.warn .m     { color:var(--amber); }
.log-line.error .m,
.log-line.critical .m { color:var(--red); }
.log-line.ok .m       { color:var(--green); }
.auth-wrap { display:flex; align-items:center; justify-content:center; height:100vh;
             background:radial-gradient(circle at 50% 0%, #16202f 0%, var(--bg) 55%);
             padding:16px; }
.auth-card { width:100%; max-width:400px; background:var(--bg-1);
             border:1px solid var(--border); border-radius:14px;
             padding:34px 30px; box-shadow:var(--shadow); }
.auth-card h1 { font-size:22px; margin:0 0 4px; letter-spacing:-.3px; }
.auth-card .sub { color:var(--fg-dim); font-size:13px; margin:0 0 24px; }
.field { margin-bottom:14px; }
.field label { display:block; font-size:12px; color:var(--fg-dim);
               margin-bottom:5px; font-weight:500; }
.field input, .field textarea, .field select { width:100%; padding:10px 12px; background:var(--bg);
               border:1px solid var(--border); border-radius:6px;
               font-size:14px; outline:none; transition:border-color .12s;
               font-family:var(--mono); }
.field textarea { resize:vertical; min-height:60px; font-size:13px; }
.field input:focus, .field textarea:focus, .field select:focus { border-color:var(--accent); box-shadow:0 0 0 3px rgba(88,166,255,.12); }
.auth-card .btn { width:100%; justify-content:center; padding:11px; margin-top:8px; }
.auth-alt { text-align:center; margin-top:18px; font-size:13px; color:var(--fg-dim); }
.err { color:var(--red); font-size:13px; margin-top:12px; padding:8px 12px;
       background:rgba(231,76,60,.1); border-radius:6px; border:1px solid rgba(231,76,60,.25); }
.info { color:var(--accent); font-size:13px; margin-top:12px; padding:8px 12px;
        background:rgba(88,166,255,.1); border-radius:6px; border:1px solid rgba(88,166,255,.25); }
.ok-msg { color:var(--green); font-size:13px; margin-top:12px; padding:8px 12px;
          background:rgba(46,204,113,.1); border-radius:6px; border:1px solid rgba(46,204,113,.25); }
.modal-back { position:fixed; inset:0; background:rgba(0,0,0,.7);
              display:flex; align-items:center; justify-content:center;
              z-index:100; animation:fade .15s; padding:16px; }
@keyframes fade { from { opacity:0 } }
.modal { background:var(--bg-1); border:1px solid var(--border);
         border-radius:12px; width:100%; max-width:520px; max-height:82vh;
         overflow:hidden; display:flex; flex-direction:column; box-shadow:var(--shadow); }
.modal.wide { max-width:720px; }
.modal-head { padding:16px 20px; border-bottom:1px solid var(--border);
              font-weight:600; display:flex; align-items:center; justify-content:space-between; }
.modal-body { padding:20px; overflow-y:auto; flex:1; }
.modal-foot { padding:14px 20px; border-top:1px solid var(--border);
              display:flex; gap:8px; justify-content:flex-end; }
.modal-tabs { display:flex; border-bottom:1px solid var(--border); background:var(--bg-2); overflow-x:auto; }
.modal-tab { flex:0 0 auto; padding:10px 18px; font-size:12px; font-weight:600;
             text-transform:uppercase; letter-spacing:.5px;
             background:transparent; border:0; cursor:pointer; color:var(--fg-mute);
             border-bottom:2px solid transparent; }
.modal-tab.active { color:var(--accent); border-bottom-color:var(--accent); }
.toast-wrap { position:fixed; bottom:20px; right:20px; z-index:200;
              display:flex; flex-direction:column; gap:8px; }
.toast { padding:10px 16px; border-radius:8px; background:var(--bg-2);
         border:1px solid var(--border); font-size:13px; box-shadow:var(--shadow);
         animation:slide .2s; max-width:380px; }
@keyframes slide { from { transform:translateY(8px); opacity:0 } }
.toast.ok    { border-color:var(--green-dim); }
.toast.error { border-color:var(--red); }
.toast.warn  { border-color:var(--amber); }
.banner { padding:8px 14px; background:rgba(243,156,18,.12);
          border-bottom:1px solid rgba(243,156,18,.35); color:var(--amber);
          font-size:12.5px; display:flex; align-items:center; gap:10px; }
.empty { color:var(--fg-mute); font-size:12.5px; text-align:center; padding:24px 12px; }
.ctx-menu { position:fixed; z-index:9999; min-width:200px; padding:4px;
            background:var(--bg-1); border:1px solid var(--border-hi);
            border-radius:8px; box-shadow:0 12px 32px rgba(0,0,0,.55); }
.ctx-item { padding:7px 12px; border-radius:6px; font-size:13px; cursor:pointer; color:var(--fg); }
.ctx-item:hover { background:var(--accent-2); color:#fff; }
.ctx-item.danger { color:var(--red); }
.ctx-item.danger:hover { background:var(--red); color:#fff; }
.ctx-sep { height:1px; background:var(--border); margin:4px 6px; }
.node-tooltip { position:fixed; z-index:9999; pointer-events:none;
                max-width:280px; padding:8px 12px; background:var(--bg-2);
                border:1px solid var(--border-hi); border-radius:8px;
                font-size:12px; color:var(--fg); box-shadow:0 6px 20px rgba(0,0,0,.5); }
.node-tooltip .tt-title { font-size:10px; color:var(--fg-mute);
                          text-transform:uppercase; letter-spacing:.5px; margin-bottom:3px; }
.file-list { display:flex; flex-direction:column; gap:6px; }
.file-row { display:flex; align-items:center; gap:10px; padding:10px 12px;
            background:var(--bg-2); border:1px solid var(--border); border-radius:8px; flex-wrap:wrap; }
.file-row .fname { font-family:var(--mono); font-size:13px; flex:1;
                   overflow:hidden; text-overflow:ellipsis; white-space:nowrap; min-width:100px; }
.file-row .fmeta { font-size:11px; color:var(--fg-mute); flex:0 0 auto; }
.qr-wrap { display:flex; flex-direction:column; align-items:center; gap:12px;
           padding:14px; background:#fff; border-radius:10px; margin-bottom:16px; }
.qr-wrap img { display:block; width:220px; height:220px; }
.secret-box { font-family:var(--mono); font-size:12px; padding:8px 12px;
              background:var(--bg-2); border:1px solid var(--border); border-radius:6px;
              word-break:break-all; }
.mobile-only { display:none; }
.sidebar-backdrop {
  position:fixed; inset:0; background:rgba(0,0,0,.5); z-index:140;
  opacity:0; pointer-events:none; transition:opacity .2s;
}
.sidebar-backdrop.show { opacity:1; pointer-events:auto; }
@media (max-width: 900px) {
  .shell.mobile { height: 100vh; height: 100dvh;
    padding-bottom: calc(64px + env(safe-area-inset-bottom, 0px));
    box-sizing: border-box; }
  .sidebar { position: fixed; top: 0; left: 0;
    bottom: calc(64px + env(safe-area-inset-bottom, 0px));
    z-index: 150; width: 86vw; max-width: 340px;
    transform: translateX(-100%); transition: transform .22s ease;
    box-shadow: 6px 0 24px rgba(0,0,0,.55); border-right: 1px solid var(--border-hi); }
  .sidebar.open { transform: translateX(0); }
  .rightbar { position: fixed; top: 0; right: 0;
    bottom: calc(64px + env(safe-area-inset-bottom, 0px));
    z-index: 150; width: 92vw; max-width: 380px;
    transform: translateX(100%); transition: transform .22s ease;
    box-shadow: -6px 0 24px rgba(0,0,0,.55); border-left: 1px solid var(--border-hi); }
  .rightbar.open { transform: translateX(0); }
  .sidebar-backdrop { z-index: 140; }
  .panel-toggle { display: none !important; }
  .mobile-only { display: inline-flex; }
  .topbar { padding: 6px 10px calc(6px + env(safe-area-inset-top, 0px)); gap: 6px; min-height: 48px; }
  .topbar .user { display: none; }
  .topbar .btn.ghost { padding: 8px 10px; font-size: 15px; min-height: 38px; }
  .brand { font-size: 13px; }
  .editor-tabs { padding: 8px 10px 0; gap: 4px; }
  .tab { padding: 10px 14px; font-size: 13px; }
  .view-toggle { padding: 8px 10px; gap: 8px; overflow-x: auto; scrollbar-width: none; flex-wrap: nowrap; }
  .view-toggle::-webkit-scrollbar { display: none; }
  .tool-btn { min-height: 38px; padding: 8px 12px; font-size: 13px; flex: 0 0 auto; }
  .btn { min-height: 38px; padding: 9px 14px; font-size: 13px; }
  .btn.sm { min-height: 34px; padding: 7px 12px; font-size: 12px; }
  .tool-select { min-height: 38px; font-size: 13px; }
  .tool-sep { display: none; }
  :root { --NODE_W: 118px; }
  .graph-node { width: 118px; min-height: 50px; padding: 4px 8px; }
  .gnode-name { font-size: 12px; }
  .gnode-icon svg { height: 20px; width: 40px; }
  .port { width: 20px; height: 20px; }
  .port.in  { left: -11px; }
  .port.out { right: -11px; }
  .port.plus { width: 18px; height: 18px; font-size: 13px; }
  .graph-wire-hit { stroke-width: 26; }
  .graph-canvas { touch-action: pan-x pan-y; }
  .sim-toolbar { padding: 8px 10px; gap: 6px; flex-wrap: wrap; row-gap: 8px; }
  .sim-toolbar .btn { flex: 1 1 auto; min-width: 66px; min-height: 40px; }
  .sim-toolbar .speed-group { flex: 1 1 100%; }
  .sim-toolbar input[type=range] { width: 100%; }
  .sim-io-bar { padding: 8px 10px; gap: 8px; }
  .sim-io-group { padding: 6px 8px; gap: 6px; }
  .sim-io-btn { padding: 8px 10px; min-width: 44px; min-height: 36px; font-size: 12px; }
  .panel-body { max-height: 240px; }
  .modal-back { align-items: flex-end !important; padding: 0 !important; z-index: 220 !important; }
  .modal, .modal.wide { max-width: 100% !important; max-height: 92dvh;
    border-radius: 16px 16px 0 0; border-bottom: none; margin: 0; width: 100% !important; }
  .modal-head { padding: 14px 16px; font-size: 15px; }
  .modal-body { padding: 14px 16px; }
  .modal-foot { padding: 12px 16px calc(12px + env(safe-area-inset-bottom, 0px)); flex-wrap: wrap; }
  .modal-foot .btn { flex: 1 1 auto; min-width: 110px; }
  .modal-tabs { overflow-x: auto; scrollbar-width: none; }
  .modal-tabs::-webkit-scrollbar { display: none; }
  .modal-tab { padding: 12px 14px; font-size: 12px; }
  input, select, textarea { font-size: 16px !important; }
  .field input, .field textarea, .field select { padding: 11px 13px; }
  .field label { font-size: 12.5px; }
  .watch-table th, .watch-table td { padding: 10px 8px; font-size: 12.5px; }
  .file-row { flex-direction: column; align-items: stretch; gap: 6px; padding: 10px; }
  .file-row .fname { white-space: normal; word-break: break-all; }
  .file-row .btn { width: 100%; justify-content: center; }
  .search-wrap { padding: 8px 10px; }
  .search-wrap input { padding: 11px 12px; font-size: 16px; }
  .pal-item { padding: 12px 12px 12px 22px; font-size: 14px; }
  .pal-head { padding: 10px 12px 10px 14px; font-size: 12px; }
  .btn, .tool-btn, .mobile-nav-item, .tab, .pal-item, .sim-io-btn,
  input, select, textarea, button { touch-action: manipulation; }
}
.device-info-table { width:100%; border-collapse:collapse; font-size:13px; }
.device-info-table td { padding:6px 8px; border-bottom:1px solid var(--bg-2); font-family:var(--mono); }
.device-info-table td.k { color:var(--fg-mute); font-family:var(--sans); width:45%; }
.device-info-table tr:last-child td { border-bottom:none; }
.info-chip { display:inline-block; padding:3px 8px; border-radius:6px; background:var(--bg-2);
             border:1px solid var(--border); font-family:var(--mono); font-size:11.5px;
             margin:2px 4px 2px 0; }


/* =========================================================================
   Mobile bottom navigation (phones only)
   ========================================================================= */
.mobile-nav {
  position: fixed; left: 0; right: 0; bottom: 0;
  height: calc(64px + env(safe-area-inset-bottom, 0px));
  padding-bottom: env(safe-area-inset-bottom, 0px);
  background: var(--bg-1); border-top: 1px solid var(--border-hi);
  display: flex; align-items: stretch; z-index: 180;
  box-shadow: 0 -4px 16px rgba(0,0,0,.35);
  user-select: none; -webkit-user-select: none;
}
.mobile-nav-item {
  position: relative; flex: 1;
  display: flex; flex-direction: column;
  align-items: center; justify-content: center; gap: 3px;
  padding: 6px 4px; background: transparent; border: 0;
  color: var(--fg-dim); cursor: pointer;
  transition: background .12s, color .12s;
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;
}
.mobile-nav-item:active { background: var(--bg-2); }
.mobile-nav-item.active { color: var(--accent); }
.mobile-nav-item.disabled, .mobile-nav-item:disabled { opacity: .35; cursor: not-allowed; }
.mobile-nav-item.active::before {
  content: ''; position: absolute; top: 0; left: 22%; right: 22%;
  height: 2px; background: var(--accent);
  border-radius: 0 0 3px 3px; box-shadow: 0 0 8px var(--accent);
}
.mnav-icon { font-size: 22px; line-height: 1; font-weight: 500; }
.mnav-label { font-size: 10px; font-weight: 600; letter-spacing: .3px;
              text-transform: uppercase; line-height: 1; }

/* =========================================================================
   Node "..." menu button — mobile only
   ========================================================================= */
.node-menu-btn {
  position: absolute; top: -10px; right: -10px;
  width: 26px; height: 26px; padding: 0; border-radius: 50%;
  background: var(--bg-1); border: 1.5px solid var(--border-hi);
  color: var(--fg-dim); font-size: 15px; font-weight: 700; line-height: 1;
  cursor: pointer; display: flex; align-items: center; justify-content: center;
  z-index: 15; box-shadow: 0 2px 6px rgba(0,0,0,.35);
  touch-action: manipulation;
}
.node-menu-btn:active { background: var(--accent-2); color: #fff; border-color: var(--accent-2); }

/* =========================================================================
   Landscape phones
   ========================================================================= */
@media (max-width: 900px) and (orientation: landscape) {
  .shell.mobile { padding-bottom: calc(44px + env(safe-area-inset-bottom, 0px)); }
  .mobile-nav { height: calc(44px + env(safe-area-inset-bottom, 0px)); }
  .mnav-icon { font-size: 16px; }
  .mnav-label { display: none; }
  .topbar { padding: 4px 8px; min-height: 40px; }
  .brand span:not(.dot) { display: none; }
  .editor-tabs { padding: 4px 8px 0; }
  .tab { padding: 6px 10px; }
  .view-toggle { padding: 4px 8px; gap: 4px; }
  .tool-btn { min-height: 32px; padding: 5px 8px; font-size: 12px; }
  .btn { min-height: 32px; padding: 6px 10px; font-size: 12px; }
  .btn.sm { min-height: 28px; padding: 4px 8px; font-size: 11px; }
  .panel-body { max-height: 160px; }
  .sim-io-bar { padding: 4px 8px; }
  .sim-io-btn { padding: 6px 8px; min-width: 34px; min-height: 30px; }
  .sim-toolbar .btn { min-height: 32px; }
  .port { width: 16px; height: 16px; }
}

/* =========================================================================
   Very small phones
   ========================================================================= */
@media (max-width: 420px) {
  :root { --NODE_W: 108px; }
  .graph-node { width: 108px; }
  .topbar .btn.ghost { padding: 6px 8px; font-size: 14px; }
  .tab { padding: 8px 10px; font-size: 12px; }
  .tool-btn { padding: 7px 9px; font-size: 12px; }
  .mnav-label { font-size: 9px; }
  .mnav-icon { font-size: 20px; }
  .brand { font-size: 12px; }
  .modal { max-height: 95dvh; }
}

@media (max-width: 900px) and (hover: none) {
  .modal-head button[title="Close"] { display: none; }
}


/* ==== mobile touch ============================================ */
@media (max-width: 900px) {
  .graph-node   { touch-action: none; }
  .port         { touch-action: none; }
  .node-menu-btn{ touch-action: manipulation; width:32px; height:32px;
                  font-size:18px; }
  .pal-item     { touch-action: manipulation; }
}


/* ==== Mobile "More" sheet ===================================== */
.mobile-more-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 10px;
}
.mobile-more-item {
  display: flex; flex-direction: column; align-items: center;
  gap: 6px; padding: 14px 8px;
  background: var(--bg-2); border: 1px solid var(--border);
  border-radius: 10px; color: var(--fg); cursor: pointer;
  font-size: 12px; font-weight: 600; min-height: 76px;
  font-family: inherit;
  touch-action: manipulation;
}
.mobile-more-item:active { background: var(--bg-3); }
.mobile-more-item.danger { color: var(--red); border-color: rgba(231,76,60,.4); }
.mmi-icon { font-size: 22px; line-height: 1; }
.mmi-label { text-align: center; }
@media (max-width: 420px) { .mobile-more-grid { grid-template-columns: repeat(3, 1fr); gap: 8px; } }


/* ==== watch add button (mobile) =============================== */
@media (max-width: 900px) {
  .watch-add-btn {
    min-width: 40px; min-height: 40px;
    padding: 0 12px; font-size: 22px; line-height: 1;
    touch-action: manipulation;
  }
  .sidebar.open, .rightbar.open { pointer-events: auto; }
  .sidebar, .rightbar { pointer-events: auto; }
  .sidebar-backdrop { z-index: 140; }
}


/* ==== device-card long-press ================================== */
@media (max-width: 900px) {
  .device-card {
    -webkit-touch-callout: none;
    -webkit-user-select: none;
    user-select: none;
    touch-action: manipulation;
  }
  .device-card .uid, .device-card .name {
    -webkit-user-select: none;
    user-select: none;
  }
}


/* ==== topbar dropdown menus ==================================== */
.topbar-menu-btn { font-size: 13px; padding: 6px 10px; }
.topbar-menu .ctx-item { padding: 9px 12px; }
.topbar-menu .ctx-item.disabled { opacity: .45; cursor: not-allowed; }
.topbar-menu .ctx-item.disabled:hover { background: transparent; color: var(--fg); }

/* ==== mobile toast — top-left behind the Compile button ======== */
@media (max-width: 900px) {
  .toast-wrap {
    bottom: auto;
    top: calc(54px + env(safe-area-inset-top, 0px));
    left: 10px;
    right: auto;
    align-items: flex-start;
    max-width: calc(100vw - 20px);
  }
  .toast { max-width: calc(100vw - 20px); }
  .topbar-menu-btn { padding: 6px 8px; font-size: 12px; min-height: 36px; }
}

/* ==== print: hide chrome ======================================= */
@media print {
  .topbar, .sidebar, .rightbar, .sim-toolbar, .sim-io-bar,
  .view-toggle, .mobile-nav, .panel-toggle, .toast-wrap { display: none !important; }
  .canvas-wrap { position: static; height: auto; }
  .graph-canvas { overflow: visible; height: auto; }
}


/* ==== analog channel input ==================================== */
.sim-io-group.bank-A .sim-io-label { color: var(--bank-A); }
.sim-io-analog {
  width: 74px; padding: 5px 6px; font-family: var(--mono); font-size: 12px;
  background: var(--bg); color: var(--bank-A); font-weight: 700;
  border: 1px solid var(--border); border-radius: 5px; text-align: center;
  outline: none;
}
.sim-io-analog:focus { border-color: var(--bank-A); }
.graph-node.bank-A { border-color: var(--bank-A); background: color-mix(in oklab, var(--bank-A) 10%, var(--bg-2)); }
.graph-node.bank-A .gnode-name { color: var(--bank-A); }


/* ==== ANA section bar (analog group) ========================== */
.pal-group[data-group*="analog"] .pal-head {
  color: var(--bank-A) !important;
  border-left-color: var(--bank-A) !important;
}
.pal-item.bank-A { border-left-color: var(--bank-A); }

/* ANA applied instruction: teal tint to make it stand apart */
.graph-node.type-applied.bank-A {
  border-color: var(--bank-A);
  background: color-mix(in oklab, var(--bank-A) 12%, var(--bg-2));
}
/* ==== palette group colour mapping =======================================
   Every section's header bar matches the colour of the items inside it.
   Text colour is kept neutral (grey) so the bar is what carries the
   meaning; only the ANALOGS section gets a highlighted label because its
   near-white bar disappears on some displays. */

/* Inputs (X) — emerald */
.pal-group[data-group*="input"] .pal-head,
.pal-item.bank-X { border-left-color: var(--bank-X) !important; }

/* Outputs (Y) — amber */
.pal-group[data-group*="output"] .pal-head,
.pal-item.bank-Y { border-left-color: var(--bank-Y) !important; }

/* Internal (M) — sky blue */
.pal-group[data-group*="internal"] .pal-head,
.pal-item.bank-M { border-left-color: var(--bank-M) !important; }

/* Analogs (ANA) — near-white (matches the A bank, but as a light neutral) */
.pal-group[data-group*="analog"] .pal-head,
.pal-item.bank-A { border-left-color: var(--fg) !important; }
.pal-group[data-group*="analog"] .pal-head { color: var(--fg) !important; }

/* Timers (T) — rose */
.pal-group[data-group*="timer"] .pal-head,
.pal-item.bank-T { border-left-color: var(--bank-T) !important; }

/* Counters (C) — orange */
.pal-group[data-group*="counter"] .pal-head,
.pal-item.bank-C { border-left-color: var(--bank-C) !important; }

/* Math / Data / Compare all operate on D registers — violet */
.pal-group[data-group*="math"] .pal-head,
.pal-group[data-group*="data"] .pal-head,
.pal-group[data-group*="compare"] .pal-head,
.pal-item.bank-D { border-left-color: var(--bank-D) !important; }

/* Logic — neutral grey, matching the .pal-item.gate bar */
.pal-group[data-group*="logic"] .pal-head,
.pal-item.gate { border-left-color: var(--border-hi) !important; }

/* Header text stays neutral for every group so the bar is the signal */
.pal-group .pal-head { color: var(--fg-mute); }


/* ==== saved-indicator + Deploy & Run ========================== */
.saved-indicator {
  font-family: var(--mono); font-size: 11px; color: var(--fg-mute);
  white-space: nowrap; margin-right: 6px; letter-spacing: .3px;
  padding: 4px 8px; border-radius: 4px;
  background: color-mix(in oklab, var(--fg) 4%, transparent);
}
.saved-indicator:empty { display: none; }

.btn-deploy-run {
  border-color: var(--green) !important;
  color: var(--green) !important;
}
.btn-deploy-run:hover:not(:disabled) {
  background: color-mix(in oklab, var(--green) 18%, transparent) !important;
}

@media (max-width: 900px) {
  .saved-indicator { display: none !important; }
  .btn-deploy-run  { display: none !important; }
}


/* ==== topbar: centered project name =========================== */
.project-name-display {
  cursor: pointer;
  user-select: none;
  flex: 0 0 auto;
  font-family: var(--mono);
  font-size: 12px;
  font-weight: 600;
  color: var(--fg);
  padding: 4px 12px;
  border-radius: 6px;
  background: color-mix(in oklab, var(--fg) 5%, transparent);
  border: 1px solid var(--border);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 42vw;
  letter-spacing: .3px;
}
.project-name-display:empty { display: none; }

/* ==== topbar: action button styles ============================ */
.topbar-btn {
  font-weight: 600;
  border-width: 1px;
  border-style: solid;
  transition: background .12s, border-color .12s, color .12s, box-shadow .12s;
}

/* Compile — blue */
.topbar-btn-compile {
  background: rgba(88,166,255,.12);
  border-color: rgba(88,166,255,.45);
  color: var(--accent);
}
.topbar-btn-compile:hover:not(:disabled) {
  background: rgba(88,166,255,.22);
  border-color: var(--accent);
  box-shadow: 0 0 8px rgba(88,166,255,.30);
}

/* Deploy — amber */
.topbar-btn-deploy {
  background: rgba(243,156,18,.12);
  border-color: rgba(243,156,18,.45);
  color: var(--amber);
}
.topbar-btn-deploy:hover:not(:disabled) {
  background: rgba(243,156,18,.22);
  border-color: var(--amber);
  box-shadow: 0 0 8px rgba(243,156,18,.30);
}

/* Deploy & Run — green, emphasised */
.topbar-btn-deploy-run {
  background: rgba(46,204,113,.14);
  border-color: var(--green);
  color: var(--green);
  font-weight: 700;
}
.topbar-btn-deploy-run:hover:not(:disabled) {
  background: rgba(46,204,113,.26);
  border-color: var(--green);
  box-shadow: 0 0 10px rgba(46,204,113,.40);
}

/* Override the old .btn-deploy-run rule if it's still around */
.btn-deploy-run { background: transparent; border-color: var(--border); color: inherit; }

@media (max-width: 900px) {
  .project-name-display { display: none; }
  .topbar-btn { padding: 6px 8px; }
}


/* ==== inline project name editor ============================== */
.project-name-display {
  touch-action: manipulation;
  -webkit-tap-highlight-color: transparent;
  -webkit-touch-callout: none;
  -webkit-user-select: none;
  user-select: none;
}
.project-name-display.editing {
  background: var(--bg-1) !important;
  border-color: var(--accent) !important;
  box-shadow: 0 0 0 3px rgba(88,166,255,.20);
  padding: 0 !important;
}
.project-name-input {
  width: 100%;
  padding: 3px 10px;
  margin: 0;
  border: 0;
  background: transparent;
  color: inherit;
  font: inherit;
  font-family: var(--mono);
  font-weight: 600;
  text-align: center;
  outline: none;
  box-sizing: border-box;
}

/* Compile button: prevent long-press callout / selection on mobile */
.topbar-btn-compile {
  -webkit-touch-callout: none;
  -webkit-user-select: none;
  user-select: none;
}

/* Show the project name on mobile so users can tap / long-press to rename */
@media (max-width: 900px) {
  .project-name-display {
    display: inline-block !important;
    font-size: 11px;
    padding: 3px 8px;
    max-width: 34vw;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }
}

/* =========================================================================
   u_10_12-modal-overflow
   ---------------------------------------------------------------------------
   A flex child with overflow:auto does not shrink below its content size
   unless min-height:0 is also declared.  Without it, .modal-body grew past
   the modal frame when the Info or Variables tab produced many rows, and
   the content spilled over the rest of the page.
   ========================================================================= */
.modal {
  /* give the modal a hard upper bound that flex can respect */
  max-height: min(82vh, 900px);
  min-height: 0;
}
.modal-body {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  overflow-x: hidden;
  -webkit-overflow-scrolling: touch;
}
.modal-tabs {
  flex: 0 0 auto;
}
.modal-head,
.modal-foot {
  flex: 0 0 auto;
}
/* Settings tab body wraps content in a plain div; keep it from growing the
   outer scroll container. */
.modal-body > div { min-height: 0; }

/* Info table can be very tall; keep it inside the scrollable body. */
.device-info-table td {
  word-break: break-word;
  vertical-align: top;
}
.device-info-table tr:last-child td { border-bottom: none; }

/* Same fix on mobile — modal is anchored to the bottom of the viewport
   there, so 92dvh is the hard ceiling. */
@media (max-width: 900px) {
  .modal,
  .modal.wide {
    max-height: 92dvh;
    min-height: 0;
  }
  .modal-body { min-height: 0; }
}

/* =========================================================================
   u_10_14-health — Device Health panel
   ========================================================================= */
.health-sec {
  margin: 10px 0 4px;
  padding: 2px 0 4px;
  font-size: 10px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .6px;
  color: var(--fg-mute);
  border-bottom: 1px solid var(--border);
}
.health-sec:first-child { margin-top: 0; }
.health-row {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 8px;
  padding: 3px 0;
  font-size: 12px;
  line-height: 1.5;
}
.health-label {
  color: var(--fg-dim);
  flex: 0 0 auto;
}
.health-value {
  font-family: var(--mono);
  font-size: 12px;
  font-weight: 600;
  color: var(--fg);
  text-align: right;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  min-width: 0;
}
.health-row.health-warn .health-value { color: var(--amber); }
.health-row.health-bad  .health-value { color: var(--red); }

/* =========================================================================
   u_10_15-panels — collapsible sidebar sections + outer scroll
   ---------------------------------------------------------------------------
   The .rightbar is the only scroll container when several panels are
   expanded.  Each .panel-body flows freely (no internal cap) so the whole
   sidebar scrolls as one column.  Watch and Event log keep their own
   internal cap because their contents grow continuously.
   ========================================================================= */
.rightbar {
  overflow-y: auto;
  overflow-x: hidden;
  -webkit-overflow-scrolling: touch;
}

/* Body flows by default — no max-height, no internal scroll */
.panel-body {
  max-height: none;
  overflow-y: visible;
}

/* Optional cap for panels whose content is unbounded (Watch, Event log) */
.panel-body.capped {
  max-height: 40vh;
  overflow-y: auto;
}

/* Collapsed: hide the body, dim the head slightly */
.panel.collapsed .panel-body { display: none; }
.panel.collapsed .panel-head  { color: var(--fg-mute); }

/* Chevron rotates to point right when collapsed */
.panel-chevron {
  display: inline-block;
  width: 10px;
  font-size: 10px;
  line-height: 1;
  color: var(--fg-mute);
  transition: transform .12s ease;
  transform-origin: 50% 50%;
  text-align: center;
}
.panel.collapsed .panel-chevron { transform: rotate(-90deg); }

/* Head should always have enough click surface */
.panel-head {
  user-select: none;
  -webkit-user-select: none;
}
.panel-head:hover { background: var(--bg-2); }

/* Mobile: the drawer is fixed and already has a bottom bound — just keep
   the outer scroll and drop the panel-body cap a little tighter. */
@media (max-width: 900px) {
  .panel-body.capped { max-height: 32vh; }
}

/* =========================================================================
   u_11_1-manager — full-screen Device Manager
   ========================================================================= */
.manager-shell { display: flex; flex-direction: column; min-height: 100vh; background: var(--bg); }
.manager-topbar { display: flex; align-items: center; gap: 8px; padding: 10px 18px; border-bottom: 1px solid var(--border); background: var(--bg-1); flex: 0 0 auto; }
.manager-brand { display: flex; align-items: center; gap: 8px; font-weight: 700; font-size: 14px; letter-spacing: .3px; }
.manager-brand .dot { width: 8px; height: 8px; border-radius: 50%; background: var(--green); box-shadow: 0 0 8px var(--green); }
.manager-body { flex: 1 1 auto; overflow-y: auto; padding: 28px 24px 60px; max-width: 1400px; width: 100%; margin: 0 auto; box-sizing: border-box; }
.manager-header { display: flex; align-items: flex-end; justify-content: space-between; gap: 16px; margin-bottom: 22px; flex-wrap: wrap; }
.manager-header h1 { font-size: 24px; margin: 0 0 2px; font-weight: 700; letter-spacing: -.3px; }
.manager-sub { margin: 0; color: var(--fg-dim); font-size: 13px; }
.manager-add-btn { padding: 10px 18px; font-weight: 600; }
.manager-stats { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 12px; margin-bottom: 22px; }
.stat-card { background: var(--bg-1); border: 1px solid var(--border); border-radius: 10px; padding: 14px 16px; display: flex; flex-direction: column; gap: 4px; position: relative; overflow: hidden; }
.stat-card::before { content: ''; position: absolute; left: 0; top: 0; bottom: 0; width: 3px; background: var(--border-hi); }
.stat-card.stat-green::before  { background: var(--green); }
.stat-card.stat-blue::before   { background: var(--accent); }
.stat-card.stat-red::before    { background: var(--red); }
.stat-value { font-size: 26px; font-weight: 700; font-family: var(--mono); line-height: 1; color: var(--fg); }
.stat-green .stat-value { color: var(--green); }
.stat-blue  .stat-value { color: var(--accent); }
.stat-red   .stat-value { color: var(--red); }
.stat-label { font-size: 11px; color: var(--fg-mute); text-transform: uppercase; letter-spacing: .6px; font-weight: 600; }
.manager-filters { display: flex; gap: 12px; align-items: center; margin-bottom: 18px; flex-wrap: wrap; }
.manager-search { flex: 1 1 280px; min-width: 200px; padding: 10px 14px; background: var(--bg-1); border: 1px solid var(--border); border-radius: 8px; color: var(--fg); font-size: 14px; outline: none; }
.manager-search:focus { border-color: var(--accent); box-shadow: 0 0 0 3px rgba(88,166,255,.12); }
.filter-chips { display: flex; gap: 6px; flex-wrap: wrap; }
.chip { padding: 7px 14px; border-radius: 999px; background: var(--bg-1); border: 1px solid var(--border); color: var(--fg-dim); font-size: 12.5px; cursor: pointer; transition: background .12s, color .12s, border-color .12s; }
.chip:hover { background: var(--bg-2); color: var(--fg); }
.chip.active { background: var(--accent-2); color: #fff; border-color: var(--accent-2); }
.manager-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(360px, 1fr)); gap: 16px; }
.mgr-card { background: var(--bg-1); border: 1px solid var(--border); border-radius: 12px; padding: 16px 18px; display: flex; flex-direction: column; gap: 12px; transition: border-color .12s, box-shadow .12s; position: relative; }
.mgr-card.online:hover { border-color: var(--border-hi); box-shadow: 0 4px 20px rgba(0,0,0,.35); }
.mgr-card.unpaired { opacity: .85; }
.mgr-card-head { display: flex; align-items: center; gap: 10px; }
.mgr-status-dot { width: 10px; height: 10px; border-radius: 50%; flex: 0 0 auto; background: var(--fg-mute); box-shadow: 0 0 0 3px color-mix(in oklab, var(--fg-mute) 20%, transparent); }
.mgr-status-dot.run     { background: var(--green); box-shadow: 0 0 0 3px rgba(46,204,113,.25), 0 0 12px rgba(46,204,113,.55); }
.mgr-status-dot.stop    { background: var(--amber); box-shadow: 0 0 0 3px rgba(243,156,18,.25); }
.mgr-status-dot.pause   { background: var(--amber); box-shadow: 0 0 0 3px rgba(243,156,18,.25); }
.mgr-status-dot.fault   { background: var(--red);   box-shadow: 0 0 0 3px rgba(231,76,60,.30); }
.mgr-status-dot.offline { background: var(--fg-mute); }
.mgr-status-dot.unpaired { background: var(--accent); box-shadow: 0 0 0 3px rgba(88,166,255,.25); }
.mgr-card-title { flex: 1 1 auto; min-width: 0; }
.mgr-card-name { font-size: 15px; font-weight: 600; cursor: text; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.mgr-card-uid { font-family: var(--mono); font-size: 11px; color: var(--fg-mute); margin-top: 2px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.mgr-card-menu { width: 30px; height: 30px; padding: 0; border-radius: 6px; background: transparent; border: 1px solid transparent; color: var(--fg-dim); cursor: pointer; font-size: 20px; line-height: 1; }
.mgr-card-menu:hover { background: var(--bg-2); border-color: var(--border); color: var(--fg); }
.mgr-card-info { display: flex; flex-direction: column; gap: 6px; font-size: 12.5px; color: var(--fg-dim); }
.mgr-row { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; overflow: hidden; }
.mgr-sep { color: var(--fg-mute); }
.mgr-label { color: var(--fg-mute); }
.mgr-program span:last-child { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 240px; }
.mgr-online-dot { font-size: 11px; }
.mgr-online-dot.on  { color: var(--green); }
.mgr-online-dot.off { color: var(--fg-mute); }
.mgr-detail-line { color: var(--fg-mute); font-size: 12px; }
.mgr-detail-line .info-chip { margin: 0; }
.mgr-card-actions { display: flex; gap: 6px; margin-top: 2px; }
.mgr-btn { flex: 1 1 0; justify-content: center; font-size: 12.5px; padding: 8px 10px; background: var(--bg-2); border: 1px solid var(--border); color: var(--fg); border-radius: 6px; font-weight: 500; }
.mgr-btn:hover:not(:disabled) { background: var(--accent-2); border-color: var(--accent-2); color: #fff; }
.mgr-unpaired-banner { display: flex; align-items: center; justify-content: space-between; gap: 8px; padding: 8px 10px; border-radius: 6px; background: rgba(88,166,255,.10); border: 1px solid rgba(88,166,255,.30); color: var(--accent); font-size: 12.5px; }
.manager-empty { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 10px; padding: 60px 20px; border: 2px dashed var(--border-hi); border-radius: 12px; color: var(--fg-dim); text-align: center; }
.manager-empty .empty-icon { font-size: 42px; color: var(--fg-mute); line-height: 1; }
.manager-empty h2 { font-size: 18px; margin: 4px 0 0; color: var(--fg); }
.manager-empty p { margin: 0 0 10px; font-size: 13px; }
.topbar-back-btn { margin-right: 4px; font-weight: 600; }
/* u_12_4 — device name pinned to the left of the project name in the
   topbar. Deliberately NOT interactive: no hover-affordance styling that
   would suggest it can be clicked/edited, unlike .project-name-display. */
.topbar-device-name {
  display: inline-flex; align-items: center; gap: 7px;
  font-size: 12.5px; font-weight: 600; color: var(--fg-dim);
  padding: 4px 2px; white-space: nowrap; overflow: hidden;
  max-width: 220px; flex: 0 1 auto;
  user-select: none; -webkit-user-select: none; -webkit-touch-callout: none;
  cursor: default;
}
.topbar-device-name-dot {
  width: 7px; height: 7px; border-radius: 50%; flex: 0 0 auto;
  background: var(--fg-mute);
  box-shadow: 0 0 0 2px color-mix(in oklab, var(--fg-mute) 25%, transparent);
}
.topbar-device-name-dot.online  { background: var(--green); box-shadow: 0 0 0 2px rgba(46,204,113,.25); }
.topbar-device-name-dot.run     { background: var(--green); box-shadow: 0 0 0 2px rgba(46,204,113,.30), 0 0 7px rgba(46,204,113,.7); }
.topbar-device-name-dot.stop    { background: var(--amber); box-shadow: 0 0 0 2px rgba(243,156,18,.30); }
.topbar-device-name-dot.pause   { background: var(--amber); box-shadow: 0 0 0 2px rgba(243,156,18,.30); }
.topbar-device-name-dot.fault   { background: var(--red);   box-shadow: 0 0 0 2px rgba(231,76,60,.30); }
.topbar-device-name-dot.offline { background: var(--fg-mute); }
.topbar-device-name-dot.unpaired{ background: var(--accent); box-shadow: 0 0 0 2px rgba(88,166,255,.30); }
.topbar-device-name-text {
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--fg);
}
.topbar-device-name-sep { color: var(--border-hi); font-weight: 400; margin-left: 2px; }
@media (max-width: 900px) {
  .topbar-device-name { max-width: 120px; font-size: 12px; }
  .topbar-device-name-sep { display: none; }
}
@media (max-width: 420px) {
  .topbar-device-name { max-width: 84px; }
  .topbar-device-name-text { display: none; }
}
@media (max-width: 900px) {
  .manager-body { padding: 14px 10px calc(24px + env(safe-area-inset-bottom, 0px)); }
  .manager-topbar { padding: 10px 12px calc(8px + env(safe-area-inset-top, 0px)); }
  .manager-topbar .btn.ghost { min-height: 40px; min-width: 40px; padding: 8px 10px; font-size: 15px; touch-action: manipulation; }
  .manager-brand { font-size: 13px; }
  .manager-header { flex-direction: column; align-items: stretch; gap: 10px; margin-bottom: 16px; }
  .manager-header h1 { font-size: 19px; }
  .manager-sub { font-size: 12.5px; }
  .manager-stats { grid-template-columns: repeat(2, 1fr); gap: 8px; margin-bottom: 16px; }
  .stat-card { padding: 10px 12px; }
  .stat-value { font-size: 20px; }
  .manager-grid { grid-template-columns: 1fr; gap: 12px; }
  .manager-filters { flex-direction: column; align-items: stretch; gap: 10px; }
  .manager-search { flex-basis: auto; width: 100%; min-height: 42px; font-size: 16px; touch-action: manipulation; }
  .manager-add-btn { width: 100%; justify-content: center; min-height: 44px; font-size: 14px; }
  .filter-chips { display: flex; overflow-x: auto; gap: 8px; padding-bottom: 2px;
    -webkit-overflow-scrolling: touch; scrollbar-width: none; touch-action: pan-x; }
  .filter-chips::-webkit-scrollbar { display: none; }
  .chip { flex: 0 0 auto; padding: 9px 14px; font-size: 12.5px; min-height: 36px;
    touch-action: manipulation; }

  /* Cards: bigger everything, generous hit areas, no reliance on hover */
  .mgr-card { padding: 14px; gap: 10px; border-radius: 14px; touch-action: manipulation;
    -webkit-user-select: none; user-select: none; -webkit-touch-callout: none; }
  .mgr-card-name { font-size: 16px; }
  .mgr-card-menu { width: 40px; height: 40px; font-size: 22px; touch-action: manipulation; }
  .mgr-card-info { font-size: 13px; gap: 8px; }
  .mgr-program span:last-child { max-width: 60vw; }
  .mgr-card-state { gap: 8px; }
  .mgr-state-btn { min-height: 44px; font-size: 12.5px; touch-action: manipulation; }
  .mgr-card-actions { gap: 8px; }
  .mgr-btn { min-height: 42px; font-size: 13px; touch-action: manipulation; }
  .mgr-unpaired-banner { flex-direction: column; align-items: stretch; text-align: center; gap: 8px; }
  .mgr-unpaired-banner .btn { min-height: 40px; }
  .manager-empty { padding: 40px 16px; }
  .manager-empty .btn { min-height: 44px; width: 100%; justify-content: center; }
}
@media (max-width: 420px) {
  .manager-stats { grid-template-columns: repeat(2, 1fr); }
  .mgr-card-actions { flex-wrap: wrap; }
  .mgr-btn { flex: 1 1 45%; }
}

/* =========================================================================
   u_11_1d-state — quick state buttons on manager cards
   ========================================================================= */
.mgr-card-state {
  display: flex;
  gap: 6px;
  margin-top: 4px;
}
.mgr-state-btn {
  flex: 1 1 0;
  justify-content: center;
  font-size: 11.5px;
  padding: 7px 8px;
  font-weight: 700;
  letter-spacing: .3px;
  border-radius: 6px;
  background: var(--bg-2);
  border: 1px solid var(--border);
  color: var(--fg-dim);
  font-family: var(--mono);
}
.mgr-state-btn.run:hover:not(:disabled)  { background: rgba(46,204,113,.20); border-color: var(--green); color: var(--green); }
.mgr-state-btn.run.active                { background: var(--green); color: #001a0d; border-color: var(--green);
                                           box-shadow: 0 0 10px rgba(46,204,113,.45); }
.mgr-state-btn.stop:hover:not(:disabled) { background: rgba(231,76,60,.20); border-color: var(--red); color: var(--red); }
.mgr-state-btn.stop.active               { background: var(--red); color: #fff; border-color: var(--red);
                                           box-shadow: 0 0 10px rgba(231,76,60,.45); }
.mgr-state-btn.reset:hover:not(:disabled){ background: rgba(243,156,18,.20); border-color: var(--amber); color: var(--amber); }
.mgr-state-btn:disabled                  { opacity: .40; cursor: not-allowed; }

.ctx-item.disabled { opacity: .45; cursor: not-allowed; }
.ctx-item.disabled:hover { background: transparent; color: var(--fg-dim); }
@media (max-width: 900px) {
  .ctx-menu { min-width: 220px; padding: 6px; max-width: calc(100vw - 24px); }
  .ctx-item { padding: 12px 14px; font-size: 14px; min-height: 44px; display: flex; align-items: center;
    touch-action: manipulation; }
}

/* =========================================================================
   u_11_1g-pill — professional topbar pill + device switcher
   ========================================================================= */
.topbar-device-pill {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 5px 10px 5px 10px;
  background: var(--bg-2);
  border: 1px solid var(--border);
  border-radius: 8px;
  color: var(--fg);
  font-size: 12.5px;
  font-weight: 600;
  cursor: pointer;
  user-select: none;
  transition: background .12s, border-color .12s, box-shadow .12s;
  white-space: nowrap;
  flex: 0 0 auto;
  font-family: var(--sans);
  letter-spacing: .2px;
}
.topbar-device-pill:hover {
  background: var(--bg-3);
  border-color: var(--border-hi);
}
.topbar-device-pill:active { transform: translateY(1px); }
.topbar-device-pill .device-pill-dot {
  width: 8px; height: 8px; border-radius: 50%;
  background: var(--fg-mute);
  box-shadow: 0 0 0 2px color-mix(in oklab, var(--fg-mute) 25%, transparent);
  transition: background .2s, box-shadow .2s;
}
.topbar-device-pill .device-pill-dot.online  { background: var(--green);  box-shadow: 0 0 0 2px rgba(46,204,113,.25); }
.topbar-device-pill .device-pill-dot.run     { background: var(--green);  box-shadow: 0 0 0 2px rgba(46,204,113,.30), 0 0 8px rgba(46,204,113,.70); }
.topbar-device-pill .device-pill-dot.stop    { background: var(--amber);  box-shadow: 0 0 0 2px rgba(243,156,18,.30); }
.topbar-device-pill .device-pill-dot.pause   { background: var(--amber);  box-shadow: 0 0 0 2px rgba(243,156,18,.30); }
.topbar-device-pill .device-pill-dot.fault   { background: var(--red);    box-shadow: 0 0 0 2px rgba(231,76,60,.30); }
.topbar-device-pill .device-pill-dot.offline { background: var(--fg-mute); }
.topbar-device-pill .device-pill-dot.unpaired{ background: var(--accent); box-shadow: 0 0 0 2px rgba(88,166,255,.30); }
.topbar-device-pill .device-pill-label {
  letter-spacing: .2px;
}
/* u_12_5 — the chevron is the dedicated "switch device" control, so it
   gets its own visible, comfortably-sized tap target (was a bare 9px
   glyph that was easy to miss, especially on touch). */
.topbar-device-pill .device-pill-chevron {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 15px;
  font-weight: 700;
  line-height: 1;
  color: var(--fg-dim);
  margin-left: 3px;
  min-width: 26px;
  min-height: 26px;
  padding: 0;
  border-radius: 6px;
  background: color-mix(in oklab, var(--fg) 6%, transparent);
  border: 1px solid transparent;
  transition: transform .15s ease, color .12s, background .12s, border-color .12s;
}
.topbar-device-pill .device-pill-chevron:hover {
  color: #fff;
  background: var(--accent-2);
  border-color: var(--accent-2);
}
@media (max-width: 900px) {
  .topbar-device-pill .device-pill-chevron {
    min-width: 32px; min-height: 32px; font-size: 17px;
    touch-action: manipulation;
  }
}

/* Device switcher dropdown */
.device-switcher {
  position: fixed;
  z-index: 9998;
  min-width: 300px;
  max-width: 380px;
  max-height: 60vh;
  overflow-y: auto;
  background: var(--bg-1);
  border: 1px solid var(--border-hi);
  border-radius: 10px;
  box-shadow: 0 12px 40px rgba(0,0,0,.55);
  padding: 6px;
  animation: switcherIn .12s ease;
}
@keyframes switcherIn {
  from { opacity: 0; transform: translateY(-4px); }
}
.device-switcher-header {
  padding: 8px 12px 6px;
  font-size: 10.5px;
  text-transform: uppercase;
  letter-spacing: .8px;
  color: var(--fg-mute);
  font-weight: 700;
  border-bottom: 1px solid var(--border);
  margin-bottom: 4px;
}
.device-switcher-item {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 10px;
  border-radius: 6px;
  cursor: pointer;
  transition: background .1s;
}
.device-switcher-item:hover { background: var(--bg-2); }
.device-switcher-item.current {
  background: color-mix(in oklab, var(--accent) 12%, transparent);
}
.device-switcher-item.current .sw-name { color: var(--accent); }
.device-switcher-item.current::after {
  content: '\2713';
  color: var(--accent);
  font-weight: 700;
  margin-left: auto;
  font-size: 14px;
}
.device-switcher-item .sw-dot {
  width: 9px; height: 9px; border-radius: 50%; flex: 0 0 auto;
  background: var(--fg-mute);
  box-shadow: 0 0 0 2px color-mix(in oklab, var(--fg-mute) 22%, transparent);
}
.device-switcher-item .sw-dot.online  { background: var(--green);  box-shadow: 0 0 0 2px rgba(46,204,113,.25); }
.device-switcher-item .sw-dot.run     { background: var(--green);  box-shadow: 0 0 0 2px rgba(46,204,113,.30), 0 0 6px rgba(46,204,113,.65); }
.device-switcher-item .sw-dot.stop    { background: var(--amber);  box-shadow: 0 0 0 2px rgba(243,156,18,.28); }
.device-switcher-item .sw-dot.pause   { background: var(--amber);  box-shadow: 0 0 0 2px rgba(243,156,18,.28); }
.device-switcher-item .sw-dot.fault   { background: var(--red);    box-shadow: 0 0 0 2px rgba(231,76,60,.30); }
.device-switcher-item .sw-dot.offline { background: var(--fg-mute); }
.device-switcher-item .sw-main {
  flex: 1 1 auto;
  min-width: 0;
}
.device-switcher-item .sw-name {
  font-size: 13px;
  font-weight: 600;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  color: var(--fg);
}
.device-switcher-item .sw-uid {
  font-family: var(--mono);
  font-size: 10.5px;
  color: var(--fg-mute);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  margin-top: 1px;
}
.device-switcher-item .sw-state {
  font-size: 10px;
  font-weight: 700;
  letter-spacing: .6px;
  padding: 2px 6px;
  border-radius: 4px;
  background: var(--bg-3);
  color: var(--fg-dim);
  text-transform: uppercase;
  flex: 0 0 auto;
}
.device-switcher-item.current .sw-state {
  background: color-mix(in oklab, var(--accent) 20%, transparent);
  color: var(--accent);
}
.device-switcher-sep {
  height: 1px;
  background: var(--border);
  margin: 4px 6px;
}
.device-switcher-action {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 10px;
  border-radius: 6px;
  cursor: pointer;
  font-size: 12.5px;
  color: var(--fg-dim);
  transition: background .1s, color .1s;
}
.device-switcher-action:hover {
  background: var(--bg-2);
  color: var(--fg);
}
.device-switcher-empty {
  padding: 24px 16px;
  text-align: center;
  color: var(--fg-mute);
  font-size: 12px;
  line-height: 1.5;
}

/* Mobile: pill shrinks, chevron still tappable */
@media (max-width: 900px) {
  .topbar-device-pill { padding: 5px 8px; font-size: 12px; }
  .topbar-device-pill .device-pill-label { display: none; }
  .topbar-device-pill .device-pill-chevron { margin-left: 0; }
  .device-switcher { min-width: 260px; max-width: calc(100vw - 24px); max-height: 50vh; }
  .device-switcher-item { padding: 12px 10px; min-height: 48px; touch-action: manipulation; }
  .device-switcher-action { padding: 12px 10px; min-height: 46px; touch-action: manipulation; }
  .sw-name { font-size: 14px; }
}

/* =========================================================================
   u_11_1i-bound — single-device card shown in the workspace sidebar
   ========================================================================= */
.bound-device-card {
  background: var(--bg-2);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 10px 12px;
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.bound-device-card.offline { opacity: .82; }
.bd-head { display: flex; align-items: center; gap: 10px; }
.bd-title { min-width: 0; flex: 1 1 auto; }
.bd-name { font-size: 13px; font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.bd-uid { font-family: var(--mono); font-size: 10.5px; color: var(--fg-mute); margin-top: 1px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.bd-info { display: flex; flex-direction: column; gap: 5px; font-size: 12px; color: var(--fg-dim); }
.bd-row { display: flex; align-items: center; gap: 6px; overflow: hidden; }
.bd-program { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 60%; }
.bd-actions { display: flex; gap: 6px; }
.bd-actions .btn { flex: 1 1 0; justify-content: center; padding: 6px 8px; font-size: 11.5px; }
.bd-actions .btn.danger { background: rgba(231,76,60,.12); border-color: rgba(231,76,60,.35); color: var(--red); }
.bd-actions .btn.danger:hover:not(:disabled) { background: var(--red); color: #fff; border-color: var(--red); }

/* =========================================================================
   u_11_4-quiet — debug-off indicator
   ========================================================================= */
.mgr-card.quiet,
.bound-device-card.quiet {
  border-left: 3px solid var(--amber);
}
.mgr-card.quiet::after {
  content: 'QUIET';
  position: absolute;
  top: 10px; right: 48px;
  font-size: 9px;
  font-weight: 700;
  letter-spacing: .6px;
  color: var(--amber);
  background: rgba(243,156,18,.15);
  border: 1px solid rgba(243,156,18,.40);
  padding: 2px 6px;
  border-radius: 3px;
  pointer-events: none;
  z-index: 2;
}
.bound-device-card.quiet .bd-head::after {
  content: 'QUIET';
  margin-left: auto;
  font-size: 9px;
  font-weight: 700;
  letter-spacing: .5px;
  color: var(--amber);
  background: rgba(243,156,18,.15);
  border: 1px solid rgba(243,156,18,.40);
  padding: 2px 5px;
  border-radius: 3px;
}
.monitor-quiet-banner {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 14px;
  background: rgba(243,156,18,.10);
  border-top: 1px solid rgba(243,156,18,.35);
  border-bottom: 1px solid rgba(243,156,18,.35);
  color: var(--amber);
  font-size: 12.5px;
  flex: 0 0 auto;
}
.monitor-quiet-banner .mqb-icon { font-size: 16px; }
.monitor-quiet-banner .mqb-text { flex: 1 1 auto; }
.monitor-quiet-banner .btn { flex: 0 0 auto; }

/* u_11_6 — Monitor divergence pill */
.monitor-diverged-pill {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 14px;
  background: rgba(243,156,18,.10);
  border-bottom: 1px solid rgba(243,156,18,.35);
  color: var(--amber);
  font-size: 12.5px;
  flex: 0 0 auto;
}
.monitor-diverged-pill .mdp-icon { font-size: 16px; }
.monitor-diverged-pill .mdp-text { flex: 1 1 auto; }

/* =========================================================================
   u_11_7-themes — 10 additional themes on top of Dark + White.
   Each block overrides the same set of tokens so components pick up the
   new palette automatically.  Adding a theme = one block + one entry in
   State.availableThemes.
   ========================================================================= */

/* ---- Dracula (#282a36 bg, #f8f8f2 fg, #bd93f9 accent) ---- */
[data-theme="dracula"] {
  --bg:#191a21; --bg-1:#21222c; --bg-2:#282a36; --bg-3:#343746;
  --border:#44475a; --border-hi:#6272a4;
  --fg:#f8f8f2; --fg-dim:#c8cad6; --fg-mute:#6272a4;
  --accent:#bd93f9; --accent-2:#9d6fdb;
  --green:#50fa7b; --green-dim:#2ea84b; --amber:#ffb86c; --red:#ff5555; --purple:#bd93f9;
  --bank-X:#50fa7b; --bank-Y:#ffb86c; --bank-M:#8be9fd; --bank-D:#bd93f9;
  --bank-T:#ff79c6; --bank-C:#ffb86c; --bank-S:#8be9fd; --bank-K:#6272a4;
  --bank-P:#ff79c6; --bank-I:#50fa7b; --bank-F:#bd93f9; --bank-A:#8be9fd;
  --shadow:0 10px 30px rgba(0,0,0,.65);
}

/* ---- Nord (#2e3440 bg, #d8dee9 fg, #88c0d0 accent) ---- */
[data-theme="nord"] {
  --bg:#242933; --bg-1:#2e3440; --bg-2:#3b4252; --bg-3:#434c5e;
  --border:#4c566a; --border-hi:#5e6a7d;
  --fg:#eceff4; --fg-dim:#d8dee9; --fg-mute:#7a889c;
  --accent:#88c0d0; --accent-2:#5e81ac;
  --green:#a3be8c; --green-dim:#6c8f56; --amber:#ebcb8b; --red:#bf616a; --purple:#b48ead;
  --bank-X:#a3be8c; --bank-Y:#ebcb8b; --bank-M:#81a1c1; --bank-D:#b48ead;
  --bank-T:#bf616a; --bank-C:#d08770; --bank-S:#88c0d0; --bank-K:#7a889c;
  --bank-P:#b48ead; --bank-I:#a3be8c; --bank-F:#b48ead; --bank-A:#88c0d0;
  --shadow:0 10px 30px rgba(0,0,0,.55);
}

/* ---- Monokai (#272822 bg, #f8f8f2 fg, #a6e22e accent) ---- */
[data-theme="monokai"] {
  --bg:#1e1f1c; --bg-1:#272822; --bg-2:#3e3d32; --bg-3:#49483e;
  --border:#49483e; --border-hi:#75715e;
  --fg:#f8f8f2; --fg-dim:#cfcfc2; --fg-mute:#75715e;
  --accent:#a6e22e; --accent-2:#7eb320;
  --green:#a6e22e; --green-dim:#5f8f12; --amber:#e6db74; --red:#f92672; --purple:#ae81ff;
  --bank-X:#a6e22e; --bank-Y:#e6db74; --bank-M:#66d9ef; --bank-D:#ae81ff;
  --bank-T:#f92672; --bank-C:#fd971f; --bank-S:#66d9ef; --bank-K:#75715e;
  --bank-P:#ae81ff; --bank-I:#a6e22e; --bank-F:#ae81ff; --bank-A:#66d9ef;
  --shadow:0 10px 30px rgba(0,0,0,.55);
}

/* ---- Solarized Dark (#002b36 bg, #839496 fg, #268bd2 accent) ---- */
[data-theme="solarized"] {
  --bg:#00252e; --bg-1:#002b36; --bg-2:#073642; --bg-3:#094552;
  --border:#0d4f5f; --border-hi:#586e75;
  --fg:#eee8d5; --fg-dim:#93a1a1; --fg-mute:#586e75;
  --accent:#268bd2; --accent-2:#1a6ea8;
  --green:#859900; --green-dim:#5f6d00; --amber:#b58900; --red:#dc322f; --purple:#6c71c4;
  --bank-X:#859900; --bank-Y:#b58900; --bank-M:#268bd2; --bank-D:#6c71c4;
  --bank-T:#dc322f; --bank-C:#cb4b16; --bank-S:#2aa198; --bank-K:#586e75;
  --bank-P:#6c71c4; --bank-I:#859900; --bank-F:#6c71c4; --bank-A:#2aa198;
  --shadow:0 10px 30px rgba(0,0,0,.55);
}

/* ---- Catppuccin Mocha (#1e1e2e bg, #cdd6f4 fg, #89b4fa accent) ---- */
[data-theme="catppuccin"] {
  --bg:#11111b; --bg-1:#1e1e2e; --bg-2:#313244; --bg-3:#45475a;
  --border:#45475a; --border-hi:#585b70;
  --fg:#cdd6f4; --fg-dim:#bac2de; --fg-mute:#7f849c;
  --accent:#89b4fa; --accent-2:#74c7ec;
  --green:#a6e3a1; --green-dim:#4caf50; --amber:#f9e2af; --red:#f38ba8; --purple:#cba6f7;
  --bank-X:#a6e3a1; --bank-Y:#f9e2af; --bank-M:#89b4fa; --bank-D:#cba6f7;
  --bank-T:#f38ba8; --bank-C:#fab387; --bank-S:#94e2d5; --bank-K:#7f849c;
  --bank-P:#cba6f7; --bank-I:#a6e3a1; --bank-F:#cba6f7; --bank-A:#94e2d5;
  --shadow:0 10px 30px rgba(0,0,0,.55);
}

/* ---- Gruvbox Dark (#282828 bg, #ebdbb2 fg, #d79921 accent) ---- */
[data-theme="gruvbox"] {
  --bg:#1d2021; --bg-1:#282828; --bg-2:#32302f; --bg-3:#3c3836;
  --border:#504945; --border-hi:#665c54;
  --fg:#ebdbb2; --fg-dim:#d5c4a1; --fg-mute:#928374;
  --accent:#d79921; --accent-2:#b57614;
  --green:#98971a; --green-dim:#6d6c13; --amber:#d79921; --red:#cc241d; --purple:#b16286;
  --bank-X:#98971a; --bank-Y:#d79921; --bank-M:#458588; --bank-D:#b16286;
  --bank-T:#cc241d; --bank-C:#d65d0e; --bank-S:#689d6a; --bank-K:#928374;
  --bank-P:#b16286; --bank-I:#98971a; --bank-F:#b16286; --bank-A:#689d6a;
  --shadow:0 10px 30px rgba(0,0,0,.55);
}

/* ---- Rosé Pine (#191724 bg, #e0def4 fg, #eb6f92 accent) ---- */
[data-theme="rosepine"] {
  --bg:#16141f; --bg-1:#191724; --bg-2:#1f1d2e; --bg-3:#26233a;
  --border:#26233a; --border-hi:#403d52;
  --fg:#e0def4; --fg-dim:#908caa; --fg-mute:#6e6a86;
  --accent:#eb6f92; --accent-2:#c4a7e7;
  --green:#9ccfd8; --green-dim:#56949f; --amber:#f6c177; --red:#eb6f92; --purple:#c4a7e7;
  --bank-X:#9ccfd8; --bank-Y:#f6c177; --bank-M:#31748f; --bank-D:#c4a7e7;
  --bank-T:#eb6f92; --bank-C:#f6c177; --bank-S:#9ccfd8; --bank-K:#6e6a86;
  --bank-P:#c4a7e7; --bank-I:#9ccfd8; --bank-F:#c4a7e7; --bank-A:#9ccfd8;
  --shadow:0 10px 30px rgba(0,0,0,.55);
}

/* ---- GitHub Dark (#0d1117 bg, #c9d1d9 fg, #58a6ff accent) ---- */
[data-theme="github"] {
  --bg:#010409; --bg-1:#0d1117; --bg-2:#161b22; --bg-3:#21262d;
  --border:#30363d; --border-hi:#484f58;
  --fg:#c9d1d9; --fg-dim:#8b949e; --fg-mute:#6e7681;
  --accent:#58a6ff; --accent-2:#1f6feb;
  --green:#3fb950; --green-dim:#2da44e; --amber:#d29922; --red:#f85149; --purple:#a371f7;
  --bank-X:#3fb950; --bank-Y:#d29922; --bank-M:#58a6ff; --bank-D:#a371f7;
  --bank-T:#f85149; --bank-C:#db6d28; --bank-S:#33b3ae; --bank-K:#6e7681;
  --bank-P:#a371f7; --bank-I:#3fb950; --bank-F:#a371f7; --bank-A:#33b3ae;
  --shadow:0 10px 30px rgba(0,0,0,.65);
}

/* ---- Tokyo Night (#1a1b26 bg, #c0caf5 fg, #7aa2f7 accent) ---- */
[data-theme="tokyonight"] {
  --bg:#16161e; --bg-1:#1a1b26; --bg-2:#24283b; --bg-3:#2f334d;
  --border:#2f334d; --border-hi:#565f89;
  --fg:#c0caf5; --fg-dim:#a9b1d6; --fg-mute:#565f89;
  --accent:#7aa2f7; --accent-2:#2ac3de;
  --green:#9ece6a; --green-dim:#5c8b3e; --amber:#e0af68; --red:#f7768e; --purple:#bb9af7;
  --bank-X:#9ece6a; --bank-Y:#e0af68; --bank-M:#7aa2f7; --bank-D:#bb9af7;
  --bank-T:#f7768e; --bank-C:#ff9e64; --bank-S:#73daca; --bank-K:#565f89;
  --bank-P:#bb9af7; --bank-I:#9ece6a; --bank-F:#bb9af7; --bank-A:#73daca;
  --shadow:0 10px 30px rgba(0,0,0,.55);
}

/* ---- Ayu Mirage (#1f2430 bg, #cbccc6 fg, #ffcc66 accent) ---- */
[data-theme="ayu"] {
  --bg:#171b24; --bg-1:#1f2430; --bg-2:#242936; --bg-3:#2d3343;
  --border:#2d3343; --border-hi:#3d4354;
  --fg:#cbccc6; --fg-dim:#a0a6b3; --fg-mute:#6c7380;
  --accent:#ffcc66; --accent-2:#ffb454;
  --green:#bae67e; --green-dim:#7fa848; --amber:#ffcc66; --red:#f07178; --purple:#d4bfff;
  --bank-X:#bae67e; --bank-Y:#ffcc66; --bank-M:#73d0ff; --bank-D:#d4bfff;
  --bank-T:#f07178; --bank-C:#ffb454; --bank-S:#95e6cb; --bank-K:#6c7380;
  --bank-P:#d4bfff; --bank-I:#bae67e; --bank-F:#d4bfff; --bank-A:#95e6cb;
  --shadow:0 10px 30px rgba(0,0,0,.55);
}

/* =========================================================================
   u_12_1-themes-pro — 5 additional "Pro" themes.
   Same token contract as the block above: one CSS block + one entry in
   State.availableThemes + one .theme-swatch-<id> pair below.
   ========================================================================= */

/* ---- Obsidian Gold — graphite + warm 24k gold accent ---- */
[data-theme="obsidiangold"] {
  --bg:#08080a; --bg-1:#111114; --bg-2:#1b1b1f; --bg-3:#26262b;
  --border:#333338; --border-hi:#4d4d55;
  --fg:#f3efe4; --fg-dim:#b3ad9d; --fg-mute:#726c5f;
  --accent:#e0b84b; --accent-2:#c79a2e;
  --green:#8fbf7a; --green-dim:#5f8a4d; --amber:#e0a458; --red:#d9636f; --purple:#b494e0;
  --bank-X:#8fbf7a; --bank-Y:#e0a458; --bank-M:#6fa8d6; --bank-D:#b494e0;
  --bank-T:#d9636f; --bank-C:#e0824b; --bank-S:#5fc4c0; --bank-K:#8a8577;
  --bank-P:#b494e0; --bank-I:#8fbf7a; --bank-F:#e0b84b; --bank-A:#5fc4c0;
  --shadow:0 12px 34px rgba(0,0,0,.7);
}

/* ---- Aurora — deep indigo night sky + teal / violet northern-lights glow ---- */
[data-theme="aurora"] {
  --bg:#080c18; --bg-1:#0e1526; --bg-2:#152038; --bg-3:#1d2c4a;
  --border:#2a3c60; --border-hi:#3e5580;
  --fg:#e7eefb; --fg-dim:#a3b6d6; --fg-mute:#657897;
  --accent:#2dd4bf; --accent-2:#22b8a3;
  --green:#4ade80; --green-dim:#2f9e5a; --amber:#fbbf24; --red:#fb7185; --purple:#a78bfa;
  --bank-X:#4ade80; --bank-Y:#fbbf24; --bank-M:#60a5fa; --bank-D:#a78bfa;
  --bank-T:#fb7185; --bank-C:#fb923c; --bank-S:#2dd4bf; --bank-K:#7186ac;
  --bank-P:#a78bfa; --bank-I:#4ade80; --bank-F:#f472b6; --bank-A:#2dd4bf;
  --shadow:0 12px 34px rgba(4,10,30,.7);
}

/* ---- Crimson Steel — brushed gunmetal + crimson accent ---- */
[data-theme="crimsonsteel"] {
  --bg:#0d0e10; --bg-1:#16181b; --bg-2:#1f2226; --bg-3:#292d32;
  --border:#3a3f45; --border-hi:#53595f;
  --fg:#edeff1; --fg-dim:#aab0b6; --fg-mute:#6f757b;
  --accent:#f43f5e; --accent-2:#be123c;
  --green:#22c55e; --green-dim:#178a44; --amber:#f59e0b; --red:#f43f5e; --purple:#c084fc;
  --bank-X:#22c55e; --bank-Y:#f59e0b; --bank-M:#38bdf8; --bank-D:#c084fc;
  --bank-T:#f43f5e; --bank-C:#fb7a3c; --bank-S:#2dd4bf; --bank-K:#7b8288;
  --bank-P:#c084fc; --bank-I:#22c55e; --bank-F:#f43f5e; --bank-A:#38bdf8;
  --shadow:0 12px 34px rgba(0,0,0,.65);
}

/* ---- Cyber Void — near-black violet + neon cyan / magenta ---- */
[data-theme="cybervoid"] {
  --bg:#07040d; --bg-1:#0f0919; --bg-2:#181026; --bg-3:#221836;
  --border:#382a54; --border-hi:#503c76;
  --fg:#f1ecff; --fg-dim:#b6a6df; --fg-mute:#79699e;
  --accent:#00e5ff; --accent-2:#00b8cc;
  --green:#39ff88; --green-dim:#25a85c; --amber:#ffd166; --red:#ff2ec4; --purple:#c77dff;
  --bank-X:#39ff88; --bank-Y:#ffd166; --bank-M:#00e5ff; --bank-D:#c77dff;
  --bank-T:#ff2ec4; --bank-C:#ff8f3c; --bank-S:#5cf2e6; --bank-K:#8b7ab0;
  --bank-P:#c77dff; --bank-I:#39ff88; --bank-F:#ff2ec4; --bank-A:#5cf2e6;
  --shadow:0 12px 36px rgba(0,0,0,.75), 0 0 40px rgba(0,229,255,.06);
}

/* ---- Porcelain Pro — warm ivory light theme + deep navy accent ---- */
[data-theme="porcelain"] {
  --bg:#f7f4ee; --bg-1:#ffffff; --bg-2:#f0eae0; --bg-3:#e5dccb;
  --border:#ddd0b8; --border-hi:#c3b291;
  --fg:#292319; --fg-dim:#6c6250; --fg-mute:#9a8f78;
  --accent:#1e3a5f; --accent-2:#16304e;
  --green:#3f7d4f; --green-dim:#2e5e3a; --amber:#b7791f; --red:#b03a2e; --purple:#6c4f8c;
  --bank-X:#3f7d4f; --bank-Y:#b7791f; --bank-M:#2a5d8c; --bank-D:#6c4f8c;
  --bank-T:#b03a2e; --bank-C:#c1622f; --bank-S:#1f7d7a; --bank-K:#7a7160;
  --bank-P:#6c4f8c; --bank-I:#3f7d4f; --bank-F:#a3376b; --bank-A:#1f7d7a;
  --shadow:0 10px 28px rgba(90,76,45,.18);
}

/* =========================================================================
   Theme grid + swatches (Themes tab in Settings)
   ========================================================================= */
.theme-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
  gap: 12px;
  margin-top: 12px;
}
.theme-card {
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding: 10px;
  border-radius: 10px;
  background: var(--bg-2);
  border: 1px solid var(--border);
  cursor: pointer;
  transition: border-color .12s, transform .08s, box-shadow .12s;
  position: relative;
}
.theme-card:hover {
  border-color: var(--border-hi);
  transform: translateY(-1px);
  box-shadow: 0 4px 14px rgba(0,0,0,.35);
}
.theme-card.active {
  border-color: var(--accent);
  box-shadow: 0 0 0 2px color-mix(in oklab, var(--accent) 35%, transparent);
}
.theme-label {
  font-size: 12px;
  font-weight: 600;
  color: var(--fg);
  text-align: center;
}
.theme-active-badge {
  position: absolute;
  top: 6px; right: 6px;
  font-size: 10px;
  font-weight: 700;
  padding: 2px 6px;
  border-radius: 4px;
  background: var(--accent);
  color: #000;
  letter-spacing: .3px;
}
.theme-swatch {
  height: 56px;
  border-radius: 6px;
  position: relative;
  overflow: hidden;
  border: 1px solid rgba(0,0,0,.25);
}
.theme-swatch::before,
.theme-swatch::after {
  content: '';
  position: absolute;
  border-radius: 50%;
}
.theme-swatch::before {
  width: 26px; height: 26px;
  left: 12px; top: 10px;
}
.theme-swatch::after {
  width: 14px; height: 14px;
  right: 14px; top: 12px;
  box-shadow: 0 22px 0 -2px currentColor;
}
.theme-swatch-sm {
  display: inline-block;
  width: 14px; height: 14px;
  border-radius: 50%;
  border: 1px solid rgba(0,0,0,.35);
}

/* Swatch previews — one per theme, hand-tuned to show bg + accent */
.theme-swatch-dark      { background:#0b0f14; color:#58a6ff; }
.theme-swatch-dark::before      { background:#e6edf3; }
.theme-swatch-dark::after       { background:#58a6ff; color:#58a6ff; }
.theme-swatch-light     { background:#f6f8fa; color:#0969da; }
.theme-swatch-light::before     { background:#1f2328; }
.theme-swatch-light::after      { background:#0969da; color:#0969da; }
.theme-swatch-dracula   { background:#282a36; color:#bd93f9; }
.theme-swatch-dracula::before   { background:#f8f8f2; }
.theme-swatch-dracula::after    { background:#bd93f9; color:#bd93f9; }
.theme-swatch-nord      { background:#2e3440; color:#88c0d0; }
.theme-swatch-nord::before      { background:#eceff4; }
.theme-swatch-nord::after       { background:#88c0d0; color:#88c0d0; }
.theme-swatch-monokai   { background:#272822; color:#a6e22e; }
.theme-swatch-monokai::before   { background:#f8f8f2; }
.theme-swatch-monokai::after    { background:#a6e22e; color:#a6e22e; }
.theme-swatch-solarized { background:#002b36; color:#268bd2; }
.theme-swatch-solarized::before { background:#eee8d5; }
.theme-swatch-solarized::after  { background:#268bd2; color:#268bd2; }
.theme-swatch-catppuccin { background:#1e1e2e; color:#89b4fa; }
.theme-swatch-catppuccin::before{ background:#cdd6f4; }
.theme-swatch-catppuccin::after { background:#89b4fa; color:#89b4fa; }
.theme-swatch-gruvbox   { background:#282828; color:#d79921; }
.theme-swatch-gruvbox::before   { background:#ebdbb2; }
.theme-swatch-gruvbox::after    { background:#d79921; color:#d79921; }
.theme-swatch-rosepine  { background:#191724; color:#eb6f92; }
.theme-swatch-rosepine::before  { background:#e0def4; }
.theme-swatch-rosepine::after   { background:#eb6f92; color:#eb6f92; }
.theme-swatch-github    { background:#0d1117; color:#58a6ff; }
.theme-swatch-github::before    { background:#c9d1d9; }
.theme-swatch-github::after     { background:#58a6ff; color:#58a6ff; }
.theme-swatch-tokyonight{ background:#1a1b26; color:#7aa2f7; }
.theme-swatch-tokyonight::before{ background:#c0caf5; }
.theme-swatch-tokyonight::after { background:#7aa2f7; color:#7aa2f7; }
.theme-swatch-ayu       { background:#1f2430; color:#ffcc66; }
.theme-swatch-ayu::before       { background:#cbccc6; }
.theme-swatch-ayu::after        { background:#ffcc66; color:#ffcc66; }

/* ---- Pro theme swatches ---- */
.theme-swatch-obsidiangold { background:linear-gradient(135deg,#08080a,#1b1611); color:#e0b84b; }
.theme-swatch-obsidiangold::before { background:#f3efe4; }
.theme-swatch-obsidiangold::after  { background:#e0b84b; color:#e0b84b; }
.theme-swatch-aurora   { background:linear-gradient(135deg,#080c18,#123326); color:#2dd4bf; }
.theme-swatch-aurora::before   { background:#e7eefb; }
.theme-swatch-aurora::after    { background:#a78bfa; color:#a78bfa; box-shadow:0 22px 0 -2px #2dd4bf; }
.theme-swatch-crimsonsteel { background:linear-gradient(135deg,#0d0e10,#2a1216); color:#f43f5e; }
.theme-swatch-crimsonsteel::before { background:#edeff1; }
.theme-swatch-crimsonsteel::after  { background:#f43f5e; color:#f43f5e; }
.theme-swatch-cybervoid { background:linear-gradient(135deg,#07040d,#1c0a2e); color:#00e5ff; }
.theme-swatch-cybervoid::before { background:#f1ecff; }
.theme-swatch-cybervoid::after  { background:#ff2ec4; color:#ff2ec4; box-shadow:0 22px 0 -2px #00e5ff; }
.theme-swatch-porcelain { background:linear-gradient(135deg,#f7f4ee,#ede1c8); color:#1e3a5f; }
.theme-swatch-porcelain::before { background:#292319; }
.theme-swatch-porcelain::after  { background:#1e3a5f; color:#1e3a5f; }

.theme-card.pro { border-color: color-mix(in oklab, var(--accent) 30%, var(--border)); }
.theme-card .theme-pro-badge {
  position: absolute; top: 6px; left: 6px;
  font-size: 9px; font-weight: 800; letter-spacing: .5px;
  padding: 2px 6px; border-radius: 4px;
  background: linear-gradient(135deg, #e0b84b, #b8912c);
  color: #1a1400; text-transform: uppercase;
}

/* Small circular swatch (context menu) */
.theme-swatch-sm.theme-swatch-dark      { background:#58a6ff; }
.theme-swatch-sm.theme-swatch-light     { background:#0969da; }
.theme-swatch-sm.theme-swatch-dracula   { background:#bd93f9; }
.theme-swatch-sm.theme-swatch-nord      { background:#88c0d0; }
.theme-swatch-sm.theme-swatch-monokai   { background:#a6e22e; }
.theme-swatch-sm.theme-swatch-solarized { background:#268bd2; }
.theme-swatch-sm.theme-swatch-catppuccin{ background:#89b4fa; }
.theme-swatch-sm.theme-swatch-gruvbox   { background:#d79921; }
.theme-swatch-sm.theme-swatch-rosepine  { background:#eb6f92; }
.theme-swatch-sm.theme-swatch-github    { background:#58a6ff; }
.theme-swatch-sm.theme-swatch-tokyonight{ background:#7aa2f7; }
.theme-swatch-sm.theme-swatch-ayu       { background:#ffcc66; }
.theme-swatch-sm.theme-swatch-obsidiangold { background:#e0b84b; }
.theme-swatch-sm.theme-swatch-aurora       { background:#2dd4bf; }
.theme-swatch-sm.theme-swatch-crimsonsteel { background:#f43f5e; }
.theme-swatch-sm.theme-swatch-cybervoid    { background:#00e5ff; }
.theme-swatch-sm.theme-swatch-porcelain    { background:#1e3a5f; }

/* u_13_6 — dismissible banner pills (appended; order-safe) */
.banner-dismiss, .mdp-close, .mqb-close {
  flex: 0 0 auto;
  width: 26px; height: 26px;
  padding: 0; margin-left: 4px;
  border: 0; border-radius: 6px;
  background: transparent;
  font-size: 16px; line-height: 1; font-weight: 700;
  cursor: pointer;
  display: inline-flex; align-items: center; justify-content: center;
  opacity: .75;
  transition: background .12s, opacity .12s;
}
.banner-dismiss, .mdp-close, .mqb-close { color: var(--amber); }
.banner-dismiss:hover, .mdp-close:hover, .mqb-close:hover {
  opacity: 1; background: rgba(243,156,18,.20);
}
.banner-dismiss:active, .mdp-close:active, .mqb-close:active {
  background: rgba(243,156,18,.35);
}
@media (max-width: 900px) {
  .banner-dismiss, .mdp-close, .mqb-close {
    width: 34px; height: 34px; font-size: 18px;
    touch-action: manipulation;
  }
}

/* u_13_7 ─ Device Manager: page-level scroll on mobile.
   The global body { overflow:hidden } (from i_all_13.sh) clips content
   taller than the viewport, freezing the manager list on phones.  When
   the manager is showing, we let the whole page scroll like an ordinary
   web page.  Scoped by html.wlc-manager-view / body.wlc-manager-view so
   the workspace editor keeps its overflow:hidden layout.

   Do NOT use height: 100vh / 100dvh on the shell here — on mobile
   browsers with a visible URL bar those are the LARGE viewport height
   and the bottom of the page becomes unreachable.  Let everything grow
   with content and let the viewport do the scrolling. */
html.wlc-manager-view,
body.wlc-manager-view {
  height: auto !important;
  min-height: 100vh;
  min-height: 100dvh;
  overflow: visible !important;
}
body.wlc-manager-view {
  -webkit-overflow-scrolling: touch;
  overscroll-behavior-y: contain;
}
body.wlc-manager-view .manager-shell {
  display: block !important;
  height: auto !important;
  min-height: 0 !important;
  padding-bottom: calc(24px + env(safe-area-inset-bottom, 0px));
}
body.wlc-manager-view .manager-topbar {
  position: sticky !important;
  top: 0;
  z-index: 50;
  background: var(--bg-1);
  border-bottom: 1px solid var(--border);
}
body.wlc-manager-view .manager-body {
  overflow: visible !important;
  height: auto !important;
  max-height: none !important;
  min-height: 0 !important;
}
@media (max-width: 900px) {
  body.wlc-manager-view .manager-topbar {
    padding-top: max(8px, env(safe-area-inset-top, 0px));
    padding-bottom: 8px;
  }
  body.wlc-manager-view .manager-body {
    padding: 14px 10px calc(24px + env(safe-area-inset-bottom, 0px)) !important;
  }
  /* Cards remain tappable; explicitly allow vertical panning so a
     finger-drag on a card scrolls the page instead of being trapped. */
  body.wlc-manager-view .mgr-card {
    touch-action: pan-y !important;
  }
  body.wlc-manager-view .manager-grid {
    touch-action: pan-y !important;
  }
}

/* =========================================================================
   u_13_11-monitor-badge
   -------------------------------------------------------------------------
   Every block carries a small badge in its top-right corner.  OFF (default)
   is a muted grey signal icon; ON is bright green with a pulsing glow.
   Turning the badge on adds the block's operand addresses to the tab's
   watch list, so the device streams them to the dashboard's Monitor view.
   ========================================================================= */
.monitor-badge {
  position: absolute;
  top: -10px;
  right: -10px;
  width: 20px;
  height: 20px;
  border-radius: 50%;
  box-sizing: border-box;
  border: 2px solid var(--bg-1);
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  z-index: 26;
  user-select: none;
  -webkit-user-select: none;
  -webkit-touch-callout: none;
  -webkit-tap-highlight-color: transparent;
  /* u_15_2 — instant state flip; no bouncy easing, no glow ramp. */
  transition: background .1s linear,
              opacity .1s linear,
              color .1s linear,
              border-color .1s linear;
}
.monitor-badge-glyph {
  width: 11px;
  height: 11px;
  display: block;
  pointer-events: none;
}
/* OFF — subtle, muted */
.monitor-badge.off {
  background: var(--bg-3);
  color: var(--fg-mute);
  opacity: .6;
  box-shadow: 0 1px 3px rgba(0,0,0,.35);
}
.monitor-badge.off:hover {
  opacity: 1;
  background: var(--bg-2);
  color: var(--fg-dim);
  border-color: var(--border-hi);
  transform: scale(1.18);
}
.monitor-badge.off:active { transform: scale(.98); }
/* u_15_2 — ON state: bright green, no pulse animation.  Turning a badge
   on or off is an instant visual change now. */
.monitor-badge.on {
  background: var(--green);
  color: #062a15;
  opacity: 1;
}
.monitor-badge.on:hover {
  transform: scale(1.18);
  box-shadow: 0 0 14px rgba(46,204,113,.9), 0 0 4px rgba(46,204,113,.9);
}
.monitor-badge.on:active { transform: scale(.98); }
/* u_15_2 — keyframes monitorBadgePulse removed (no pulse animation). */
/* Move the force badge to top-LEFT so it never collides with the monitor badge */
.graph-node .force-badge {
  top: -9px;
  left: -9px;
  right: auto;
}
/* Mobile: badge grows, ⋯ menu moves to bottom-right to keep corners free */
@media (max-width: 900px) {
  .monitor-badge {
    top: -12px;
    right: -12px;
    width: 24px;
    height: 24px;
    touch-action: manipulation;
  }
  .monitor-badge-glyph { width: 13px; height: 13px; }
  .graph-node .node-menu-btn {
    top: auto;
    bottom: -12px;
    right: -12px;
  }
}


/* u_13_13-inline-set */
.wlc-inline-set {
  position: absolute;
  z-index: 900;
  min-width: 200px;
  max-width: 280px;
  padding: 10px 12px;
  background: var(--bg-1);
  border: 1px solid var(--border-hi);
  border-radius: 8px;
  box-shadow: 0 10px 28px rgba(0,0,0,.55);
  font-size: 12px;
  display: flex;
  flex-direction: column;
  gap: 6px;
  font-family: var(--sans);
}
.wlc-is-row { display: flex; flex-direction: column; gap: 2px; }
.wlc-is-row label {
  font-family: var(--mono); font-size: 11px; font-weight: 700;
  color: var(--fg-dim);
  display: flex; justify-content: space-between; gap: 8px;
}
.wlc-is-cur { color: var(--fg-mute); font-weight: 400; font-family: var(--mono); }
.wlc-is-row input {
  width: 100%; box-sizing: border-box;
  padding: 5px 8px;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: 5px;
  font-family: var(--mono);
  font-size: 12px;
  color: var(--fg);
  outline: none;
}
.wlc-is-row input:focus { border-color: var(--accent); }
.wlc-is-err { color: var(--red); font-size: 11px; min-height: 0; }
.wlc-is-actions {
  display: flex; gap: 6px; justify-content: flex-end;
  margin-top: 4px;
}
.wlc-is-actions .btn.sm { padding: 4px 10px; font-size: 11px; }

/* Adaptive block width — allow the name text to use the full measured
   width without clipping. */
.graph-node .gnode-name {
  overflow: visible;
  text-overflow: clip;
}


/* u_13_14 — system M register subtitle on a block */
.gnode-special {
  font-size: 8.5px;
  font-weight: 700;
  color: var(--amber);
  text-align: center;
  width: 100%;
  padding: 0 2px;
  line-height: 1.15;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  letter-spacing: .1px;
}


/* u_13_15 — Hold checkbox inside the inline set-values popup */
.wlc-is-hold {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 11.5px;
  color: var(--fg-dim);
  margin: 6px 0 2px;
  cursor: pointer;
  user-select: none;
  -webkit-user-select: none;
}
.wlc-is-hold.disabled {
  opacity: .55;
  cursor: default;
}
.wlc-is-hold input {
  width: auto;
  margin: 0;
  accent-color: var(--accent);
  cursor: pointer;
}
.wlc-is-hold.disabled input { cursor: default; }


/* u_13_18 — holds indicator on the Monitor toolbar */
.mon-holds-badge {
  padding: 5px 12px;
  border-radius: 999px;
  font-family: var(--mono);
  font-size: 11px;
  font-weight: 800;
  letter-spacing: 1.2px;
  background: rgba(243,156,18,.18);
  color: var(--amber);
  border: 1px solid rgba(243,156,18,.45);
  white-space: nowrap;
}


/* u_13_19 — self-overwrite hint inside the inline Set values popup */
.wlc-is-hint {
  font-size: 10.5px;
  color: var(--amber);
  background: rgba(243,156,18,.10);
  border: 1px solid rgba(243,156,18,.35);
  border-radius: 4px;
  padding: 4px 8px;
  line-height: 1.35;
  margin: 4px 0 2px;
}


/* u_13_21 — thin, deep-red ring for held addresses */
.monitor-badge.held {
  box-shadow: 0 0 0 1.2px #ff1a1a !important;
  border-color: #ff1a1a !important;
  outline: none !important;
}
.monitor-badge { position: absolute; }

/* u_13_20 — live operand strip inside the Set values dialog */
.wlc-is-strip-label {
  font-size: 10px;
  text-transform: uppercase;
  letter-spacing: .6px;
  color: var(--fg-mute);
  font-weight: 700;
  margin: 6px 0 2px;
}
.wlc-is-strip {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
  padding: 4px 0 2px;
}
.wlc-is-strip-item {
  font-family: var(--mono);
  font-size: 11px;
  padding: 2px 6px;
  border-radius: 4px;
  background: var(--bg-2);
  border: 1px solid var(--border);
  color: var(--fg-dim);
  white-space: nowrap;
}
.wlc-is-strip-item.is-on  { background: rgba(46,204,113,.18); border-color: rgba(46,204,113,.5); color: var(--green); font-weight: 700; }
.wlc-is-strip-item.is-off { background: var(--bg-3); color: var(--fg-mute); }
.wlc-is-strip-item.is-const { opacity: .7; }


/* u_13_25-single-scroll
   Defensive: only .graph-canvas is ever a scroll container.  Every
   ancestor is overflow:hidden, so a stray oversize child cannot create
   a second scrollbar anywhere up the tree. */
.shell,
.workspace,
.main,
.canvas-wrap {
  overflow: hidden;
}
.canvas-wrap { min-height: 0; }
.main        { min-height: 0; }
.workspace   { min-height: 0; }

/* .graph-canvas is the one scroller.  auto shows bars only when needed. */
.graph-canvas {
  overflow: auto;
}
.graph-canvas::-webkit-scrollbar { width: 10px; height: 10px; }

/* u_13_28 — the wrapper is sized to content by _resizeSurface().  It
   should NOT clip, so marquee boxes and inline popups that extend past
   its bounds are still rendered. */
.canvas-scroll { overflow: visible; }

/* iOS Safari: keep scroll bounce off the canvas so it does not flash a
   horizontal scroll indicator when the wrap is touched. */
.graph-canvas { -webkit-overflow-scrolling: touch; overscroll-behavior: contain; }

/* =========================================================================
   Placement: Device Manager card
   Base sits just above the state row (the RUN / STOP / RESET row), so the
   bottom of the rail lines up with the RESET button.  Card padding is
   16px bottom + actions row (~40px) + gap (~12px) = ~68px from card bottom.
   ========================================================================= */
.mgr-card > .wifi-rail {
  top: auto;
  bottom: 68px;
}
.mgr-card.quiet > .wifi-rail {
  bottom: 64px;   /* QUIET badge sits slightly higher; nudge rail down */
}

/* =========================================================================
   Placement: Bound device card (sidebar)
   Base sits just above the bd-actions row (Info / Read / Reboot).
   ========================================================================= */
.bound-device-card { position: relative; }
.bound-device-card > .wifi-rail {
  top: auto;
  bottom: 56px;
}
.bound-device-card.quiet > .wifi-rail {
  bottom: 52px;
}

/* ---------- Segments ---------- */
.wifi-rail-seg {
  width: var(--seg-w);
  height: var(--seg-h);
  border-radius: 2px;
  background: var(--bg-3);
  box-shadow: inset 0 0 0 1px rgba(0,0,0,.22);
  transition: background .25s ease, opacity .25s ease,
              height .2s ease, width .2s ease;
  flex: 0 0 auto;
}

/* ---------- Signal tiers (5 segments) ----------
   sig-5 → all 5 green (excellent, >= -50)
   sig-4 → bottom 4 green (good,      >= -60)
   sig-3 → bottom 3 amber (fair,      >= -70)
   sig-2 → bottom 2 amber (weak,      >= -80)
   sig-1 → bottom 1 red   (very weak, >= -90)
   sig-0 → all dim red    (< -90, but still associated with a live device)
   offline → all dim grey (device.online === false) */
.wifi-rail.sig-5 .wifi-rail-seg[data-seg="1"],
.wifi-rail.sig-5 .wifi-rail-seg[data-seg="2"],
.wifi-rail.sig-5 .wifi-rail-seg[data-seg="3"],
.wifi-rail.sig-5 .wifi-rail-seg[data-seg="4"],
.wifi-rail.sig-5 .wifi-rail-seg[data-seg="5"] {
  background: var(--green);
  box-shadow: inset 0 0 0 1px rgba(0,0,0,.15),
              0 0 4px rgba(46,204,113,.35);
}

.wifi-rail.sig-4 .wifi-rail-seg[data-seg="1"],
.wifi-rail.sig-4 .wifi-rail-seg[data-seg="2"],
.wifi-rail.sig-4 .wifi-rail-seg[data-seg="3"],
.wifi-rail.sig-4 .wifi-rail-seg[data-seg="4"] {
  background: var(--green);
  box-shadow: inset 0 0 0 1px rgba(0,0,0,.15),
              0 0 3px rgba(46,204,113,.25);
}
.wifi-rail.sig-4 .wifi-rail-seg[data-seg="5"] { background: var(--bg-3); }

.wifi-rail.sig-3 .wifi-rail-seg[data-seg="1"],
.wifi-rail.sig-3 .wifi-rail-seg[data-seg="2"],
.wifi-rail.sig-3 .wifi-rail-seg[data-seg="3"] {
  background: var(--amber);
  box-shadow: inset 0 0 0 1px rgba(0,0,0,.15),
              0 0 3px rgba(243,156,18,.30);
}
.wifi-rail.sig-3 .wifi-rail-seg[data-seg="4"],
.wifi-rail.sig-3 .wifi-rail-seg[data-seg="5"] { background: var(--bg-3); }

.wifi-rail.sig-2 .wifi-rail-seg[data-seg="1"],
.wifi-rail.sig-2 .wifi-rail-seg[data-seg="2"] {
  background: var(--amber);
  box-shadow: inset 0 0 0 1px rgba(0,0,0,.15),
              0 0 3px rgba(243,156,18,.25);
}
.wifi-rail.sig-2 .wifi-rail-seg[data-seg="3"],
.wifi-rail.sig-2 .wifi-rail-seg[data-seg="4"],
.wifi-rail.sig-2 .wifi-rail-seg[data-seg="5"] { background: var(--bg-3); }

.wifi-rail.sig-1 .wifi-rail-seg[data-seg="1"] {
  background: var(--red);
  box-shadow: inset 0 0 0 1px rgba(0,0,0,.15),
              0 0 3px rgba(231,76,60,.35);
}
.wifi-rail.sig-1 .wifi-rail-seg[data-seg="2"],
.wifi-rail.sig-1 .wifi-rail-seg[data-seg="3"],
.wifi-rail.sig-1 .wifi-rail-seg[data-seg="4"],
.wifi-rail.sig-1 .wifi-rail-seg[data-seg="5"] { background: var(--bg-3); }

.wifi-rail.sig-0 .wifi-rail-seg {
  background: var(--red);
  opacity: .5;
  box-shadow: none;
}

.wifi-rail.offline .wifi-rail-seg {
  background: var(--fg-mute);
  opacity: .28;
  box-shadow: none;
}

/* ---------- dBm readout ---------- */
.wifi-rail-readout {
  display: flex;
  flex-direction: column;
  align-items: center;
  line-height: 1;
  margin-top: 3px;
  gap: 0;
}
.wifi-rail-dbm {
  font-family: var(--mono);
  font-size: 9px;
  font-weight: 800;
  color: var(--fg-dim);
  letter-spacing: -0.3px;
  white-space: nowrap;
}
.wifi-rail-unit {
  font-family: var(--mono);
  font-size: 6.5px;
  font-weight: 600;
  color: var(--fg-mute);
  margin-top: 1px;
  letter-spacing: .2px;
}
.wifi-rail.offline .wifi-rail-dbm,
.wifi-rail.offline .wifi-rail-unit { color: var(--fg-mute); opacity: .75; }
.wifi-rail.compact .wifi-rail-dbm { font-size: 8px; }
.wifi-rail.compact .wifi-rail-unit { font-size: 6px; }

/* ---------- Mobile: slightly larger for readability ---------- */
@media (max-width: 900px) {
  .wifi-rail { --seg-h: 15px; --seg-w: 12px; min-width: 26px; }
  .wifi-rail.compact { --seg-h: 11px; --seg-w: 10px; }
  .wifi-rail-dbm { font-size: 10px; }
  .wifi-rail-unit { font-size: 7px; }
  .mgr-card > .wifi-rail { bottom: 72px; }
  .mgr-card.quiet > .wifi-rail { bottom: 68px; }
  .bound-device-card > .wifi-rail { bottom: 60px; }
  .bound-device-card.quiet > .wifi-rail { bottom: 56px; }
}

/* =========================================================================
   u_14_2_ver_wifi_3a — vertical Nokia-style WiFi rail, frame-flush
   -------------------------------------------------------------------------
   The rail is NOT a widget.  No background, no border, no radius, no
   padding.  Only the segments are visible; each segment's right edge sits
   at the inner edge of the parent card's border, so it reads as emanating
   from the frame itself.

   The rail's top and bottom are set per placement so it spans the desired
   vertical region of the card (below ⋯ / above RESET for the manager
   card; below head / above actions for the bound card).

   QUIET mode: segments become 65% wide and 11px tall.  No additional
   frame is drawn around them — they simply get smaller and thinner.
   ========================================================================= */

/* ---------- Container: invisible wrapper, only children are seen ---------- */
.wifi-rail {
  position: absolute;
  right: 0;                       /* flush to the inner edge of card border */
  display: flex;
  flex-direction: column;
  justify-content: space-evenly;
  align-items: flex-end;          /* segments flush to the right */
  gap: 3px;
  margin: 0;
  padding: 0;
  background: transparent;
  border: 0;
  border-radius: 0;
  box-shadow: none;
  z-index: 4;
  pointer-events: none;           /* let clicks pass through to the card */
  user-select: none;
  -webkit-user-select: none;
}

/* ---------- Segments ---------- */
.wifi-rail-seg {
  width: 100%;                    /* full rail width, right edge at border */
  height: 14px;
  border-radius: 0;               /* sharp on all corners — no widget look */
  background: var(--bg-3);
  box-shadow: none;
  transition: background .25s ease, opacity .25s ease,
              height .2s ease, width .2s ease;
  flex: 0 0 auto;
}

/* ---------- dBm readout ----------
   Sits below the segments, right-aligned so it too hugs the frame.
   Overhangs the rail container slightly (min-width) so two-digit numbers
   like "-66" fit; the rail itself stays narrow. */
.wifi-rail-readout {
  display: flex;
  flex-direction: column;
  align-items: flex-end;          /* right-align the readout */
  line-height: 1;
  margin-top: 3px;
  gap: 0;
  min-width: 100%;
  white-space: nowrap;
}
.wifi-rail-dbm {
  font-family: var(--mono);
  font-size: 9px;
  font-weight: 800;
  color: var(--fg-dim);
  letter-spacing: -0.4px;
}
.wifi-rail-unit {
  font-family: var(--mono);
  font-size: 6px;
  font-weight: 600;
  color: var(--fg-mute);
  letter-spacing: .2px;
  margin-top: 1px;
}
.wifi-rail.offline .wifi-rail-dbm,
.wifi-rail.offline .wifi-rail-unit { color: var(--fg-mute); opacity: .7; }

/* =========================================================================
   Placement — Device Manager card
   Top: 46px  — just below the head row (16px pad + 30px ⋯ button)
   Bottom: 96px — 16px pad + 34px actions + 12px gap + 32px state row + 2px
   Span: whatever remains between those two anchors.
   Rail width 14px fits inside the card's 18px right padding.
   ========================================================================= */
.mgr-card > .wifi-rail {
  top: 46px;
  bottom: 96px;
  width: 14px;
}
.mgr-card.quiet > .wifi-rail {
  /* QUIET badge is at top-right of the head row; the rail itself does not
     move, but its segments get thinner via .compact below. */
  top: 46px;
  bottom: 96px;
}

/* =========================================================================
   Placement — Bound device card (workspace sidebar)
   Top: 40px  — below the head row (10px pad + ~28px bd-head)
   Bottom: 52px — 10px pad + 30px actions + 12px gap
   Rail width 10px fits inside the card's 12px right padding.
   ========================================================================= */
.bound-device-card > .wifi-rail {
  top: 40px;
  bottom: 52px;
  width: 10px;
}
.bound-device-card.quiet > .wifi-rail {
  top: 40px;
  bottom: 52px;
}

/* =========================================================================
   QUIET / debug-off — segments get thinner and shorter, no extra frame.
   Applied in BOTH card types so the rail's presence shrinks gracefully
   wherever the QUIET badge appears.
   ========================================================================= */
.wifi-rail.compact .wifi-rail-seg {
  width: 65%;
  height: 11px;
}
.wifi-rail.compact .wifi-rail-dbm  { font-size: 8px; }
.wifi-rail.compact .wifi-rail-unit { font-size: 5.5px; }

/* =========================================================================
   Signal tiers (5 segments, bottom = 1, top = 5)
     sig-5 → all 5 green        (excellent,  >= -50)
     sig-4 → bottom 4 green     (good,       >= -60)
     sig-3 → bottom 3 amber     (fair,       >= -70)
     sig-2 → bottom 2 amber     (weak,       >= -80)
     sig-1 → bottom 1 red       (very weak,  >= -90)
     sig-0 → all dim red        (still associated with an online device)
     offline → all dim grey     (dev.online === false)
   ========================================================================= */
.wifi-rail.sig-5 .wifi-rail-seg[data-seg="1"],
.wifi-rail.sig-5 .wifi-rail-seg[data-seg="2"],
.wifi-rail.sig-5 .wifi-rail-seg[data-seg="3"],
.wifi-rail.sig-5 .wifi-rail-seg[data-seg="4"],
.wifi-rail.sig-5 .wifi-rail-seg[data-seg="5"] { background: var(--green); }

.wifi-rail.sig-4 .wifi-rail-seg[data-seg="1"],
.wifi-rail.sig-4 .wifi-rail-seg[data-seg="2"],
.wifi-rail.sig-4 .wifi-rail-seg[data-seg="3"],
.wifi-rail.sig-4 .wifi-rail-seg[data-seg="4"] { background: var(--green); }
.wifi-rail.sig-4 .wifi-rail-seg[data-seg="5"] { background: var(--bg-3); }

.wifi-rail.sig-3 .wifi-rail-seg[data-seg="1"],
.wifi-rail.sig-3 .wifi-rail-seg[data-seg="2"],
.wifi-rail.sig-3 .wifi-rail-seg[data-seg="3"] { background: var(--amber); }
.wifi-rail.sig-3 .wifi-rail-seg[data-seg="4"],
.wifi-rail.sig-3 .wifi-rail-seg[data-seg="5"] { background: var(--bg-3); }

.wifi-rail.sig-2 .wifi-rail-seg[data-seg="1"],
.wifi-rail.sig-2 .wifi-rail-seg[data-seg="2"] { background: var(--amber); }
.wifi-rail.sig-2 .wifi-rail-seg[data-seg="3"],
.wifi-rail.sig-2 .wifi-rail-seg[data-seg="4"],
.wifi-rail.sig-2 .wifi-rail-seg[data-seg="5"] { background: var(--bg-3); }

.wifi-rail.sig-1 .wifi-rail-seg[data-seg="1"] { background: var(--red); }
.wifi-rail.sig-1 .wifi-rail-seg[data-seg="2"],
.wifi-rail.sig-1 .wifi-rail-seg[data-seg="3"],
.wifi-rail.sig-1 .wifi-rail-seg[data-seg="4"],
.wifi-rail.sig-1 .wifi-rail-seg[data-seg="5"] { background: var(--bg-3); }

.wifi-rail.sig-0 .wifi-rail-seg { background: var(--red); opacity: .5; }

.wifi-rail.offline .wifi-rail-seg { background: var(--fg-mute); opacity: .28; }

/* =========================================================================
   Mobile: slightly larger touch-friendly sizes
   ========================================================================= */
@media (max-width: 900px) {
  .mgr-card > .wifi-rail { top: 50px; bottom: 104px; width: 16px; }
  .bound-device-card > .wifi-rail { top: 44px; bottom: 58px; width: 12px; }
  .wifi-rail-seg { height: 15px; }
  .wifi-rail.compact .wifi-rail-seg { height: 12px; width: 65%; }
  .wifi-rail-dbm  { font-size: 10px; }
  .wifi-rail-unit { font-size: 6.5px; }
}

/* =========================================================================
   u_14_2_ver_wifi_3b — vertical Nokia-style WiFi rail, 8 segments
   -------------------------------------------------------------------------
   Eight stacked segments, bottom = weakest, top = strongest.  Segment
   width has been reduced ~60% vs v3a.  Heights are computed by flexbox
   (flex: 1 1 0; min-height: 3px) so the rail ALWAYS fits its container —
   the segments shrink rather than push the readout onto the button row
   below.  This is the fix for the mobile overlap with RESET / REBOOT.

   The rail itself has no background, border, or padding — only the
   segments are visible, and their right edge sits at the inner edge of
   the parent card's border.

   QUIET behaviour:
     • .mgr-card .wifi-rail.compact → NO rule.  The bar is unaffected.
     • .bound-device-card .wifi-rail.compact → segments thin to 65%.
   ========================================================================= */

/* ---------- Container: invisible wrapper ---------- */
.wifi-rail {
  position: absolute;
  right: 0;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  align-items: flex-end;
  gap: 2px;
  margin: 0;
  padding: 0;
  background: transparent;
  border: 0;
  box-shadow: none;
  z-index: 4;
  pointer-events: none;
  user-select: none;
  -webkit-user-select: none;
  overflow: visible;
}

/* ---------- Segments: flex-sized, never overflow ---------- */
.wifi-rail-seg {
  flex: 1 1 0;
  min-height: 3px;
  max-height: 16px;
  width: 100%;
  border-radius: 0;
  background: var(--bg-3);
  transition: background .25s ease, opacity .25s ease, width .2s ease;
}

/* ---------- dBm readout: fixed size, right-aligned ---------- */
.wifi-rail-readout {
  flex: 0 0 auto;
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  line-height: 1;
  margin-top: 3px;
  white-space: nowrap;
}
.wifi-rail-dbm {
  font-family: var(--mono);
  font-size: 9px;
  font-weight: 800;
  color: var(--fg-dim);
  letter-spacing: -0.4px;
}
.wifi-rail-unit {
  font-family: var(--mono);
  font-size: 6px;
  font-weight: 600;
  color: var(--fg-mute);
  letter-spacing: .2px;
  margin-top: 1px;
}
.wifi-rail.offline .wifi-rail-dbm,
.wifi-rail.offline .wifi-rail-unit { color: var(--fg-mute); opacity: .7; }

/* =========================================================================
   Placement — Device Manager card
   Desktop: top 46 px (below ⋯), bottom 100 px (above RESET row).
   Mobile : top 50 px, bottom 130 px — more clearance so the readout
            never touches the RESET button on short cards.
   Width  : 6 px desktop, 7 px mobile (~60% narrower than v3a's 14/16).
   ========================================================================= */
.mgr-card > .wifi-rail {
  top: 46px;
  bottom: 100px;
  width: 6px;
}

/* =========================================================================
   Placement — Bound device card (workspace sidebar)
   Desktop: top 40 px (below head), bottom 58 px (above Info/Read/Reboot).
   Mobile : top 44 px, bottom 80 px — fixes REBOOT / dBm overlap.
   Width  : 4 px desktop, 5 px mobile (~60% narrower than v3a's 10/12).
   ========================================================================= */
.bound-device-card > .wifi-rail {
  top: 40px;
  bottom: 58px;
  width: 4px;
}

/* =========================================================================
   QUIET — bound card only.  Manager card ignores .compact entirely.
   ========================================================================= */
.bound-device-card .wifi-rail.compact .wifi-rail-seg {
  width: 65%;
  min-width: 3px;
}
.bound-device-card .wifi-rail.compact .wifi-rail-dbm  { font-size: 8px; }
.bound-device-card .wifi-rail.compact .wifi-rail-unit { font-size: 5.5px; }

/* =========================================================================
   Signal tiers (8 segments, bottom = 1, top = 8)
     8, 7, 6 → green  (excellent / good)
     5, 4, 3 → amber  (fair / weak)
     2, 1    → red    (very weak)
     0       → dim red
     offline → dim grey
   Uses nth-child(n+K) where K = 9 - tier, since DOM order is 8..1 then
   the readout.  Bottom segments are the higher nth-child indices.
   ========================================================================= */
.wifi-rail.sig-8 .wifi-rail-seg { background: var(--green); }

.wifi-rail.sig-7 .wifi-rail-seg:nth-child(n+2) { background: var(--green); }
.wifi-rail.sig-6 .wifi-rail-seg:nth-child(n+3) { background: var(--green); }
.wifi-rail.sig-5 .wifi-rail-seg:nth-child(n+4) { background: var(--amber); }
.wifi-rail.sig-4 .wifi-rail-seg:nth-child(n+5) { background: var(--amber); }
.wifi-rail.sig-3 .wifi-rail-seg:nth-child(n+6) { background: var(--amber); }
.wifi-rail.sig-2 .wifi-rail-seg:nth-child(n+7) { background: var(--red); }
.wifi-rail.sig-1 .wifi-rail-seg:nth-child(n+8) { background: var(--red); }

.wifi-rail.sig-0 .wifi-rail-seg { background: var(--red); opacity: .5; }
.wifi-rail.offline .wifi-rail-seg { background: var(--fg-mute); opacity: .28; }

/* =========================================================================
   Mobile — the mobile rules only override anchors, never segment count
   or flex behaviour (which already fixes the overlap at every size).
   ========================================================================= */
@media (max-width: 900px) {
  .mgr-card > .wifi-rail {
    top: 50px;
    bottom: 130px;
    width: 7px;
  }
  .bound-device-card > .wifi-rail {
    top: 44px;
    bottom: 80px;
    width: 5px;
  }
  .wifi-rail-dbm  { font-size: 10px; }
  .wifi-rail-unit { font-size: 6.5px; }
  .bound-device-card .wifi-rail.compact .wifi-rail-dbm  { font-size: 8.5px; }
  .bound-device-card .wifi-rail.compact .wifi-rail-unit { font-size: 5.5px; }
}

/* =========================================================================
   u_14_2_ver_wifi_3c — vertical Nokia-style WiFi rail, fixed-size
   -------------------------------------------------------------------------
   Eight stacked segments, bottom = weakest, top = strongest.  The rail
   has NO background, border, radius, or padding — only the segments are
   visible, and their right edge sits at the inner edge of the parent
   card's border.

   IMPORTANT: this version has NO QUIET / .compact behaviour.  The rail's
   appearance is identical whether Debug is on or off, on desktop or
   mobile, in the Device Manager card or the Bound device card.  The
   thinner segment width and smaller font that used to appear only when
   QUIET was on are now the default everywhere.

   Segment heights are flex-computed (flex: 1 1 0; min-height: 3px) so
   the rail always fits its container — segments shrink rather than push
   the readout onto the button rows below.
   ========================================================================= */

/* ---------- Container: invisible wrapper ---------- */
.wifi-rail {
  position: absolute;
  right: 0;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  align-items: flex-end;
  gap: 2px;
  margin: 0;
  padding: 0;
  background: transparent;
  border: 0;
  box-shadow: none;
  z-index: 4;
  pointer-events: none;
  user-select: none;
  -webkit-user-select: none;
  overflow: visible;
}

/* ---------- Segments: flex-sized, always 65% of container width ----------
   65% is the value that used to appear only in QUIET mode.  It is now the
   only width the rail uses.  Segment heights are flex-computed. */
.wifi-rail-seg {
  flex: 1 1 0;
  min-height: 3px;
  max-height: 16px;
  width: 65%;
  min-width: 3px;
  border-radius: 0;
  background: var(--bg-3);
  transition: background .25s ease, opacity .25s ease;
}

/* ---------- dBm readout: fixed size, right-aligned ----------
   Font sizes are the ones that used to appear only in QUIET mode. */
.wifi-rail-readout {
  flex: 0 0 auto;
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  line-height: 1;
  margin-top: 3px;
  white-space: nowrap;
}
.wifi-rail-dbm {
  font-family: var(--mono);
  font-size: 8px;
  font-weight: 800;
  color: var(--fg-dim);
  letter-spacing: -0.4px;
}
.wifi-rail-unit {
  font-family: var(--mono);
  font-size: 5.5px;
  font-weight: 600;
  color: var(--fg-mute);
  letter-spacing: .2px;
  margin-top: 1px;
}
.wifi-rail.offline .wifi-rail-dbm,
.wifi-rail.offline .wifi-rail-unit { color: var(--fg-mute); opacity: .7; }

/* =========================================================================
   Placement — Device Manager card
   Desktop: top 46 px (below ⋯), bottom 100 px (above RESET row).
   Mobile : top 50 px, bottom 130 px — extra clearance for the RESET button.
   Width  : 6 px desktop, 7 px mobile — the container width, not the
            segment width.  Segments inside are 65% of this.
   ========================================================================= */
.mgr-card > .wifi-rail {
  top: 46px;
  bottom: 100px;
  width: 6px;
}

/* =========================================================================
   Placement — Bound device card (workspace sidebar)
   Desktop: top 40 px (below head), bottom 58 px (above Info/Read/Reboot).
   Mobile : top 44 px, bottom 80 px — extra clearance for REBOOT.
   Width  : 4 px desktop, 5 px mobile.
   ========================================================================= */
.bound-device-card > .wifi-rail {
  top: 40px;
  bottom: 58px;
  width: 4px;
}

/* =========================================================================
   Signal tiers (8 segments, bottom = 1, top = 8)
     8, 7, 6 → green  (excellent / good)
     5, 4, 3 → amber  (fair / weak)
     2, 1    → red    (very weak)
     0       → dim red
     offline → dim grey
   DOM order is 8..1 top-to-bottom, then the readout.  Bottom segments
   have the higher nth-child index.
   ========================================================================= */
.wifi-rail.sig-8 .wifi-rail-seg { background: var(--green); }

.wifi-rail.sig-7 .wifi-rail-seg:nth-child(n+2) { background: var(--green); }
.wifi-rail.sig-6 .wifi-rail-seg:nth-child(n+3) { background: var(--green); }
.wifi-rail.sig-5 .wifi-rail-seg:nth-child(n+4) { background: var(--amber); }
.wifi-rail.sig-4 .wifi-rail-seg:nth-child(n+5) { background: var(--amber); }
.wifi-rail.sig-3 .wifi-rail-seg:nth-child(n+6) { background: var(--amber); }
.wifi-rail.sig-2 .wifi-rail-seg:nth-child(n+7) { background: var(--red); }
.wifi-rail.sig-1 .wifi-rail-seg:nth-child(n+8) { background: var(--red); }

.wifi-rail.sig-0 .wifi-rail-seg { background: var(--red); opacity: .5; }
.wifi-rail.offline .wifi-rail-seg { background: var(--fg-mute); opacity: .28; }

/* =========================================================================
   Mobile — only anchors change.  Segment widths, dBm sizes, and
   everything else are the same as desktop so the visual identity is
   identical across viewports.
   ========================================================================= */
@media (max-width: 900px) {
  .mgr-card > .wifi-rail {
    top: 50px;
    bottom: 130px;
    width: 7px;
  }
  .bound-device-card > .wifi-rail {
    top: 44px;
    bottom: 80px;
    width: 5px;
  }
  /* No font / width overrides here — segments and dBm text stay at the
     desktop sizes so the rail is visually identical everywhere. */
}

/* =========================================================================
   u_14_2_ver_wifi_3e — vertical Nokia-style WiFi rail + rotated %
   -------------------------------------------------------------------------
   Two-column body:
     .wifi-rail-pct   (left)  — rotated percentage, mono font, tier-coloured
     .wifi-rail-segs  (right) — 8 stacked segments, right-flush to card edge
   Below the body: .wifi-rail-readout with the dBm number and unit.

   No QUIET-driven resizing.  Same look in both cards and both viewports.
   ========================================================================= */

/* ---------- Container: invisible wrapper ---------- */
.wifi-rail {
  position: absolute;
  right: 0;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  align-items: stretch;
  gap: 0;
  margin: 0;
  padding: 0;
  background: transparent;
  border: 0;
  border-radius: 0;
  box-shadow: none;
  z-index: 4;
  pointer-events: none;
  user-select: none;
  -webkit-user-select: none;
  overflow: visible;
}

/* ---------- Body: pct (left) | segs (right) ---------- */
.wifi-rail-body {
  flex: 1 1 auto;
  display: flex;
  flex-direction: row;
  align-items: stretch;
  gap: 3px;
  min-height: 0;
}

/* ---------- Segments column (right, right-flush) ---------- */
.wifi-rail-segs {
  /* u_14_2_ver_wifi_3g — pin the segment column to the right edge of the
     body so segments always touch the card frame, independent of what
     fills the space to their left. */
  margin-left: auto;
  flex: 0 0 auto;
  width: 6px;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  gap: 2px;
  min-height: 0;
}
.bound-device-card .wifi-rail-segs { width: 4px; }

.wifi-rail-seg {
  flex: 1 1 0;
  min-height: 3px;
  max-height: 16px;
  width: 100%;
  border-radius: 0;
  background: var(--bg-3);
  transition: background .25s ease, opacity .25s ease;
}

/* ---------- Percentage column (left, rotated) ---------- */
.wifi-rail-pct {
  /* u_14_2_ver_wifi_3k — plain horizontal text, no rotation.
     Anchored to the TOP of the rail body so it sits alongside segment-8,
     the topmost (= strongest-signal) segment.  Right-aligned so its right
     edge hugs the segment column with no gap. */
  writing-mode: horizontal-tb;
  text-orientation: mixed;
  transform: none;

  align-self: flex-start;           /* top of the rail body */
  text-align: right;
  flex: 0 0 auto;
  margin: 0;
  padding: 0;

  font-family: var(--mono);
  font-size: 15px;
  font-weight: 800;
  letter-spacing: -0.4px;
  color: var(--fg-dim);
  line-height: 1;
  white-space: nowrap;
  overflow: visible;
  text-overflow: clip;
  transition: color .25s ease, opacity .25s ease;
}
.bound-device-card .wifi-rail-pct {
  font-size: 14px;
}

/* ---------- dBm readout below ---------- */
.wifi-rail-readout {
  flex: 0 0 auto;
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  line-height: 1;
  margin-top: 3px;
  white-space: nowrap;
}
.wifi-rail-dbm {
  font-family: var(--mono);
  font-size: 8px;
  font-weight: 800;
  color: var(--fg-dim);
  letter-spacing: -0.4px;
}
.wifi-rail-unit {
  font-family: var(--mono);
  font-size: 5.5px;
  font-weight: 600;
  color: var(--fg-mute);
  letter-spacing: .2px;
  margin-top: 1px;
}
.wifi-rail.offline .wifi-rail-dbm,
.wifi-rail.offline .wifi-rail-unit { color: var(--fg-mute); opacity: .7; }

/* =========================================================================
   Placement — Device Manager card
   Top 46 px (below ⋯).  Bottom 100 px (above RESET row).
   Width 16 px = 6 (segs) + 3 (gap) + ~7 (rotated pct column).
   ========================================================================= */
.mgr-card > .wifi-rail {
  top: 46px;
  bottom: 100px;
  width: 26px;
}

/* =========================================================================
   Placement — Bound device card (workspace sidebar)
   Top 40 px (below head).  Bottom 58 px (above Info/Read/Reboot).
   Width 13 px = 4 (segs) + 3 (gap) + ~6 (rotated pct column).
   ========================================================================= */
.bound-device-card > .wifi-rail {
  top: 40px;
  bottom: 58px;
  width: 24px;
}

/* =========================================================================
   Signal tiers — segments
   DOM order inside .wifi-rail-segs is 8..1 top-to-bottom, so nth-child
   indices correspond to segments from top: n=1 is seg-8, n=8 is seg-1.
   ========================================================================= */
.wifi-rail.sig-8 .wifi-rail-seg { background: var(--green); }
.wifi-rail.sig-7 .wifi-rail-seg:nth-child(n+2) { background: var(--green); }
.wifi-rail.sig-6 .wifi-rail-seg:nth-child(n+3) { background: var(--green); }
.wifi-rail.sig-5 .wifi-rail-seg:nth-child(n+4) { background: var(--amber); }
.wifi-rail.sig-4 .wifi-rail-seg:nth-child(n+5) { background: var(--amber); }
.wifi-rail.sig-3 .wifi-rail-seg:nth-child(n+6) { background: var(--amber); }
.wifi-rail.sig-2 .wifi-rail-seg:nth-child(n+7) { background: var(--red); }
.wifi-rail.sig-1 .wifi-rail-seg:nth-child(n+8) { background: var(--red); }
.wifi-rail.sig-0 .wifi-rail-seg { background: var(--red); opacity: .5; }
.wifi-rail.offline .wifi-rail-seg { background: var(--fg-mute); opacity: .28; }

/* =========================================================================
   Signal tiers — percentage text colour
   ========================================================================= */
.wifi-rail.sig-8 .wifi-rail-pct,
.wifi-rail.sig-7 .wifi-rail-pct,
.wifi-rail.sig-6 .wifi-rail-pct { color: var(--green); }

.wifi-rail.sig-5 .wifi-rail-pct,
.wifi-rail.sig-4 .wifi-rail-pct,
.wifi-rail.sig-3 .wifi-rail-pct { color: var(--amber); }

.wifi-rail.sig-2 .wifi-rail-pct,
.wifi-rail.sig-1 .wifi-rail-pct { color: var(--red); }

.wifi-rail.sig-0 .wifi-rail-pct { color: var(--red); opacity: .6; }
.wifi-rail.offline .wifi-rail-pct { color: var(--fg-mute); opacity: .6; }

/* =========================================================================
   Mobile — anchors only; container widths stay as desktop so the %
   column fits identically on every viewport.
   ========================================================================= */
@media (max-width: 900px) {
  .mgr-card > .wifi-rail {
    top: 50px;
    bottom: 130px;
  }
  .bound-device-card > .wifi-rail {
    top: 44px;
    bottom: 80px;
  }
}

/* u_14_2_ver_wifi_3k — keep segments column pinned to the right edge */
.wifi-rail-body > .wifi-rail-segs { margin-left: auto; }

/* =========================================================================
   u_14_2_ver_wifi_3c — vertical Nokia-style WiFi rail, fixed-size
   -------------------------------------------------------------------------
   Eight stacked segments, bottom = weakest, top = strongest.  The rail
   has NO background, border, radius, or padding — only the segments are
   visible, and their right edge sits at the inner edge of the parent
   card's border.

   IMPORTANT: this version has NO QUIET / .compact behaviour.  The rail's
   appearance is identical whether Debug is on or off, on desktop or
   mobile, in the Device Manager card or the Bound device card.  The
   thinner segment width and smaller font that used to appear only when
   QUIET was on are now the default everywhere.

   Segment heights are flex-computed (flex: 1 1 0; min-height: 3px) so
   the rail always fits its container — segments shrink rather than push
   the readout onto the button rows below.
   ========================================================================= */

/* ---------- Container: invisible wrapper ---------- */
.wifi-rail {
  position: absolute;
  right: 0;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  align-items: flex-end;
  gap: 2px;
  margin: 0;
  padding: 0;
  background: transparent;
  border: 0;
  box-shadow: none;
  z-index: 4;
  pointer-events: none;
  user-select: none;
  -webkit-user-select: none;
  overflow: visible;
}

/* ---------- Segments: flex-sized, always 65% of container width ----------
   65% is the value that used to appear only in QUIET mode.  It is now the
   only width the rail uses.  Segment heights are flex-computed. */
.wifi-rail-seg {
  flex: 1 1 0;
  min-height: 3px;
  max-height: 16px;
  width: 65%;
  min-width: 3px;
  border-radius: 0;
  background: var(--bg-3);
  transition: background .25s ease, opacity .25s ease;
}

/* ---------- dBm readout: fixed size, right-aligned ----------
   Font sizes are the ones that used to appear only in QUIET mode. */
.wifi-rail-readout {
  flex: 0 0 auto;
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  line-height: 1;
  margin-top: 3px;
  white-space: nowrap;
}
.wifi-rail-dbm {
  font-family: var(--mono);
  font-size: 8px;
  font-weight: 800;
  color: var(--fg-dim);
  letter-spacing: -0.4px;
}
.wifi-rail-unit {
  font-family: var(--mono);
  font-size: 5.5px;
  font-weight: 600;
  color: var(--fg-mute);
  letter-spacing: .2px;
  margin-top: 1px;
}
.wifi-rail.offline .wifi-rail-dbm,
.wifi-rail.offline .wifi-rail-unit { color: var(--fg-mute); opacity: .7; }

/* =========================================================================
   Placement — Device Manager card
   Desktop: top 46 px (below ⋯), bottom 100 px (above RESET row).
   Mobile : top 50 px, bottom 130 px — extra clearance for the RESET button.
   Width  : 6 px desktop, 7 px mobile — the container width, not the
            segment width.  Segments inside are 65% of this.
   ========================================================================= */
.mgr-card > .wifi-rail {
  top: 46px;
  bottom: 100px;
  width: 6px;
}

/* =========================================================================
   Placement — Bound device card (workspace sidebar)
   Desktop: top 40 px (below head), bottom 58 px (above Info/Read/Reboot).
   Mobile : top 44 px, bottom 80 px — extra clearance for REBOOT.
   Width  : 4 px desktop, 5 px mobile.
   ========================================================================= */
.bound-device-card > .wifi-rail {
  top: 40px;
  bottom: 58px;
  width: 4px;
}

/* =========================================================================
   Signal tiers (8 segments, bottom = 1, top = 8)
     8, 7, 6 → green  (excellent / good)
     5, 4, 3 → amber  (fair / weak)
     2, 1    → red    (very weak)
     0       → dim red
     offline → dim grey
   DOM order is 8..1 top-to-bottom, then the readout.  Bottom segments
   have the higher nth-child index.
   ========================================================================= */
.wifi-rail.sig-8 .wifi-rail-seg { background: var(--green); }

.wifi-rail.sig-7 .wifi-rail-seg:nth-child(n+2) { background: var(--green); }
.wifi-rail.sig-6 .wifi-rail-seg:nth-child(n+3) { background: var(--green); }
.wifi-rail.sig-5 .wifi-rail-seg:nth-child(n+4) { background: var(--amber); }
.wifi-rail.sig-4 .wifi-rail-seg:nth-child(n+5) { background: var(--amber); }
.wifi-rail.sig-3 .wifi-rail-seg:nth-child(n+6) { background: var(--amber); }
.wifi-rail.sig-2 .wifi-rail-seg:nth-child(n+7) { background: var(--red); }
.wifi-rail.sig-1 .wifi-rail-seg:nth-child(n+8) { background: var(--red); }

.wifi-rail.sig-0 .wifi-rail-seg { background: var(--red); opacity: .5; }
.wifi-rail.offline .wifi-rail-seg { background: var(--fg-mute); opacity: .28; }

/* =========================================================================
   Mobile — only anchors change.  Segment widths, dBm sizes, and
   everything else are the same as desktop so the visual identity is
   identical across viewports.
   ========================================================================= */
@media (max-width: 900px) {
  .mgr-card > .wifi-rail {
    top: 50px;
    bottom: 130px;
    width: 7px;
  }
  .bound-device-card > .wifi-rail {
    top: 44px;
    bottom: 80px;
    width: 5px;
  }
  /* No font / width overrides here — segments and dBm text stay at the
     desktop sizes so the rail is visually identical everywhere. */
}

/* =========================================================================
   u_14_2_ver_wifi_3c — vertical Nokia-style WiFi rail, fixed-size
   -------------------------------------------------------------------------
   Eight stacked segments, bottom = weakest, top = strongest.  The rail
   has NO background, border, radius, or padding — only the segments are
   visible, and their right edge sits at the inner edge of the parent
   card's border.

   IMPORTANT: this version has NO QUIET / .compact behaviour.  The rail's
   appearance is identical whether Debug is on or off, on desktop or
   mobile, in the Device Manager card or the Bound device card.  The
   thinner segment width and smaller font that used to appear only when
   QUIET was on are now the default everywhere.

   Segment heights are flex-computed (flex: 1 1 0; min-height: 3px) so
   the rail always fits its container — segments shrink rather than push
   the readout onto the button rows below.
   ========================================================================= */

/* ---------- Container: invisible wrapper ---------- */
.wifi-rail {
  position: absolute;
  right: 0;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  align-items: flex-end;
  gap: 2px;
  margin: 0;
  padding: 0;
  background: transparent;
  border: 0;
  box-shadow: none;
  z-index: 4;
  pointer-events: none;
  user-select: none;
  -webkit-user-select: none;
  overflow: visible;
}

/* ---------- Segments: flex-sized, always 65% of container width ----------
   65% is the value that used to appear only in QUIET mode.  It is now the
   only width the rail uses.  Segment heights are flex-computed. */
.wifi-rail-seg {
  flex: 1 1 0;
  min-height: 3px;
  max-height: 16px;
  width: 65%;
  min-width: 3px;
  border-radius: 0;
  background: var(--bg-3);
  transition: background .25s ease, opacity .25s ease;
}

/* ---------- dBm readout: fixed size, right-aligned ----------
   Font sizes are the ones that used to appear only in QUIET mode. */
.wifi-rail-readout {
  flex: 0 0 auto;
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  line-height: 1;
  margin-top: 3px;
  white-space: nowrap;
}
.wifi-rail-dbm {
  font-family: var(--mono);
  font-size: 8px;
  font-weight: 800;
  color: var(--fg-dim);
  letter-spacing: -0.4px;
}
.wifi-rail-unit {
  font-family: var(--mono);
  font-size: 5.5px;
  font-weight: 600;
  color: var(--fg-mute);
  letter-spacing: .2px;
  margin-top: 1px;
}
.wifi-rail.offline .wifi-rail-dbm,
.wifi-rail.offline .wifi-rail-unit { color: var(--fg-mute); opacity: .7; }

/* =========================================================================
   Placement — Device Manager card
   Desktop: top 46 px (below ⋯), bottom 100 px (above RESET row).
   Mobile : top 50 px, bottom 130 px — extra clearance for the RESET button.
   Width  : 6 px desktop, 7 px mobile — the container width, not the
            segment width.  Segments inside are 65% of this.
   ========================================================================= */
.mgr-card > .wifi-rail {
  top: 46px;
  bottom: 100px;
  width: 6px;
}

/* =========================================================================
   Placement — Bound device card (workspace sidebar)
   Desktop: top 40 px (below head), bottom 58 px (above Info/Read/Reboot).
   Mobile : top 44 px, bottom 80 px — extra clearance for REBOOT.
   Width  : 4 px desktop, 5 px mobile.
   ========================================================================= */
.bound-device-card > .wifi-rail {
  top: 40px;
  bottom: 58px;
  width: 4px;
}

/* =========================================================================
   Signal tiers (8 segments, bottom = 1, top = 8)
     8, 7, 6 → green  (excellent / good)
     5, 4, 3 → amber  (fair / weak)
     2, 1    → red    (very weak)
     0       → dim red
     offline → dim grey
   DOM order is 8..1 top-to-bottom, then the readout.  Bottom segments
   have the higher nth-child index.
   ========================================================================= */
.wifi-rail.sig-8 .wifi-rail-seg { background: var(--green); }

.wifi-rail.sig-7 .wifi-rail-seg:nth-child(n+2) { background: var(--green); }
.wifi-rail.sig-6 .wifi-rail-seg:nth-child(n+3) { background: var(--green); }
.wifi-rail.sig-5 .wifi-rail-seg:nth-child(n+4) { background: var(--amber); }
.wifi-rail.sig-4 .wifi-rail-seg:nth-child(n+5) { background: var(--amber); }
.wifi-rail.sig-3 .wifi-rail-seg:nth-child(n+6) { background: var(--amber); }
.wifi-rail.sig-2 .wifi-rail-seg:nth-child(n+7) { background: var(--red); }
.wifi-rail.sig-1 .wifi-rail-seg:nth-child(n+8) { background: var(--red); }

.wifi-rail.sig-0 .wifi-rail-seg { background: var(--red); opacity: .5; }
.wifi-rail.offline .wifi-rail-seg { background: var(--fg-mute); opacity: .28; }

/* =========================================================================
   Mobile — only anchors change.  Segment widths, dBm sizes, and
   everything else are the same as desktop so the visual identity is
   identical across viewports.
   ========================================================================= */
@media (max-width: 900px) {
  .mgr-card > .wifi-rail {
    top: 50px;
    bottom: 130px;
    width: 7px;
  }
  .bound-device-card > .wifi-rail {
    top: 44px;
    bottom: 80px;
    width: 5px;
  }
  /* No font / width overrides here — segments and dBm text stay at the
     desktop sizes so the rail is visually identical everywhere. */
}


/* =========================================================================
   u_15_1 — Device Manager drag-to-reorder
   ========================================================================= */
.mgr-card-grip {
  width: 30px; height: 30px;
  padding: 0; margin: 0;
  border: 1px solid transparent; border-radius: 6px;
  background: transparent;
  color: var(--fg-mute);
  cursor: grab;
  font-size: 16px; line-height: 1;
  display: inline-flex; align-items: center; justify-content: center;
  touch-action: none;
  user-select: none; -webkit-user-select: none;
  transition: background .12s, color .12s, border-color .12s;
}
.mgr-card-grip:hover {
  background: var(--bg-2);
  border-color: var(--border);
  color: var(--fg);
}
.mgr-card-grip:active { cursor: grabbing; }

.mgr-card-dragging {
  opacity: 0.4;
}
.mgr-card-ghost {
  box-shadow: 0 12px 40px rgba(0,0,0,.6) !important;
  border-color: var(--accent) !important;
  border-style: dashed !important;
  transition: none !important;
}

@media (max-width: 900px) {
  .mgr-card-grip {
    width: 38px; height: 38px; font-size: 20px;
    touch-action: none;
  }
}


/* =========================================================================
   u_15_3 — Device Manager search highlight
   ========================================================================= */
mark.mgr-match {
  background: rgba(243,156,18,.35);
  color: inherit;
  padding: 0 1px;
  border-radius: 2px;
  font-weight: inherit;
}
[data-theme="light"] mark.mgr-match { background: rgba(243,156,18,.45); }

/* =========================================================================
   u_15_3 — Monitor toolbar: icon-only buttons in a single row.
   LIVE badge, device label and HOLDS text badge are gone; the release
   button carries the hold count in its title.
   ========================================================================= */
.mon-toolbar {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 12px;
  flex-wrap: nowrap;
  overflow-x: auto;
  overflow-y: hidden;
  -webkit-overflow-scrolling: touch;
}
.mon-btn-row {
  display: flex;
  align-items: center;
  gap: 6px;
  flex: 0 0 auto;
}
.mon-icon-btn {
  flex: 0 0 auto;
  width: 40px;
  height: 40px;
  padding: 0;
  border-radius: 8px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 18px;
  line-height: 1;
  background: var(--bg-2);
  border: 1px solid var(--border);
  color: var(--fg);
  cursor: pointer;
  user-select: none;
  -webkit-user-select: none;
  transition: background .1s linear, border-color .1s linear, color .1s linear;
}
.mon-icon-btn:hover:not(:disabled) {
  background: var(--bg-3);
  border-color: var(--border-hi);
}
.mon-icon-btn:active:not(:disabled) {
  background: var(--bg-3);
}
.mon-icon-btn:disabled {
  opacity: .4;
  cursor: not-allowed;
}
.mon-icon-btn.active {
  background: var(--accent-2);
  border-color: var(--accent-2);
  color: #fff;
  box-shadow: 0 0 8px rgba(31,111,235,.45);
}
.mon-stats {
  flex: 0 0 auto;
  font-family: var(--mono);
  font-size: 12px;
  color: var(--fg-dim);
  white-space: nowrap;
}
/* Hide any leftover references to the old monitor layout. */
.mon-live-badge, .mon-dev-label, .mon-holds-badge { display: none !important; }

@media (max-width: 900px) {
  .mon-toolbar {
    padding: 6px 8px;
    gap: 6px;
  }
  .mon-icon-btn {
    width: 42px;
    height: 42px;
    font-size: 20px;
    touch-action: manipulation;
  }
  .mon-btn-row { gap: 5px; }
  .mon-stats { font-size: 11px; }
}

/* =========================================================================
   u_15_3 — Simulate toolbar: single scrollable row on mobile.
   Buttons keep their natural size; the toolbar scrolls horizontally if
   the total width exceeds the viewport.  Applies to the simulate toolbar
   ONLY — the monitor toolbar has its own compact layout above.
   ========================================================================= */
@media (max-width: 900px) {
  .sim-toolbar:not(.mon-toolbar) {
    flex-wrap: nowrap !important;
    overflow-x: auto;
    overflow-y: hidden;
    -webkit-overflow-scrolling: touch;
    padding: 6px 8px !important;
    gap: 6px !important;
    row-gap: 0 !important;
  }
  .sim-toolbar:not(.mon-toolbar) .btn {
    flex: 0 0 auto !important;
    min-width: 0 !important;
    min-height: 36px !important;
    padding: 6px 10px !important;
    font-size: 13px !important;
    white-space: nowrap;
  }
  .sim-toolbar:not(.mon-toolbar) .speed-group {
    flex: 0 0 auto !important;
    padding: 4px 10px !important;
    gap: 8px !important;
    min-height: 36px;
    white-space: nowrap;
  }
  .sim-toolbar:not(.mon-toolbar) input[type=range] {
    width: 110px !important;
  }
  .sim-toolbar:not(.mon-toolbar) .speed-val { min-width: 48px; }
  .sim-toolbar:not(.mon-toolbar) .sim-state-badge {
    font-size: 11px;
    padding: 5px 12px;
    flex: 0 0 auto;
  }
  .sim-toolbar:not(.mon-toolbar) .sim-stats {
    flex: 0 0 auto;
    white-space: nowrap;
    font-size: 11px;
  }
  .sim-toolbar:not(.mon-toolbar) .spacer {
    flex: 0 0 6px !important;
  }
}

/* =========================================================================
   u_15_4 — Tools bar: single row, horizontal scroll when it overflows.
   The bar contains the view toggles, zoom controls, zone tools, the
   marquee filter and (in read-only mode) the READ-ONLY indicator.  It
   no longer wraps onto multiple lines on narrow screens; instead the
   user pans the bar horizontally.
   ========================================================================= */
.view-toggle {
  flex-wrap: nowrap;
  overflow-x: auto;
  overflow-y: hidden;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: thin;
}
.view-toggle::-webkit-scrollbar { height: 6px; }
.view-toggle::-webkit-scrollbar-thumb {
  background: var(--bg-3);
  border-radius: 3px;
}
.view-toggle > * { flex: 0 0 auto; }
/* The "Read-only" pill (margin-left:auto in JS) must not push the row
   taller; it can scroll off the end when the bar is narrow. */
.view-toggle > span[style*="margin-left:auto"] {
  margin-left: 12px !important;
}
@media (max-width: 900px) {
  .view-toggle { padding: 6px 8px; gap: 6px; }
  .view-toggle .tool-btn,
  .view-toggle .btn.ghost.sm { padding: 6px 10px; font-size: 12px; min-height: 34px; }
  .view-toggle .tool-select { font-size: 12px; min-height: 34px; }
  .view-toggle .tool-color { width: 34px; height: 34px; }
}


/* =========================================================================
   u_15_7 — Monitor IO view (grid + HMI)
   ========================================================================= */
.io-view {
  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
  min-height: 0;
  background: var(--bg);
  overflow: hidden;
}
.io-modebar {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 12px;
  background: var(--bg-1);
  border-bottom: 1px solid var(--border);
  flex-wrap: nowrap;
  overflow-x: auto;
}
.io-mode-btn {
  padding: 6px 14px;
  border: 1px solid var(--border);
  background: var(--bg-2);
  color: var(--fg-dim);
  border-radius: 6px;
  cursor: pointer;
  font-size: 12.5px;
  font-weight: 600;
  white-space: nowrap;
  flex: 0 0 auto;
}
.io-mode-btn.active {
  background: var(--accent-2);
  color: #fff;
  border-color: var(--accent-2);
}
.io-hint {
  font-size: 12px;
  color: var(--fg-mute);
  white-space: nowrap;
  flex: 0 0 auto;
}
.io-grid {
  flex: 1 1 auto;
  overflow-y: auto;
  padding: 14px 16px 40px;
  display: flex;
  flex-direction: column;
  gap: 18px;
}
.io-group { display: flex; flex-direction: column; gap: 8px; }
.io-group-title {
  font-size: 11px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .6px;
  color: var(--fg-mute);
  border-bottom: 1px solid var(--border);
  padding-bottom: 4px;
}
.io-tiles {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(88px, 1fr));
  gap: 8px;
}
.io-tile-wrap { display: flex; flex-direction: column; gap: 2px; }
.io-tile-wrap .io-tile-label { font-size: 11px; color: var(--fg-mute); }
.io-tile {
  min-height: 56px;
  padding: 8px 10px;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--bg-2);
  color: var(--fg);
  cursor: pointer;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 2px;
  font-family: var(--mono);
  transition: background .1s linear, border-color .1s linear;
}
.io-tile:hover:not(:disabled) { background: var(--bg-3); }
.io-tile-label { font-size: 11px; color: var(--fg-mute); }
.io-tile-value { font-size: 15px; font-weight: 700; color: var(--fg-dim); }
.io-tile.on { background: var(--green); border-color: var(--green); color: #001a0d; }
.io-tile.on .io-tile-value { color: #001a0d; }
.io-tile.on .io-tile-label { color: rgba(0,26,13,.7); }
.io-bank-X .io-tile.on { background: var(--bank-X); border-color: var(--bank-X); }
.io-bank-Y .io-tile.on { background: var(--bank-Y); border-color: var(--bank-Y); }
.io-bank-M .io-tile.on { background: var(--bank-M); border-color: var(--bank-M); }
.io-bank-T .io-tile.on { background: var(--bank-T); border-color: var(--bank-T); }
.io-bank-C .io-tile.on { background: var(--bank-C); border-color: var(--bank-C); }
.io-tile.io-word {
  cursor: text;
  text-align: center;
  font-size: 15px;
  font-weight: 700;
  color: var(--fg);
  font-family: var(--mono);
}
.io-tile.io-word:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 2px rgba(88,166,255,.25);
}
.io-empty {
  padding: 40px 20px;
  text-align: center;
  color: var(--fg-mute);
  font-size: 13px;
}
.io-hmi-wrap {
  flex: 1 1 auto;
  display: grid;
  grid-template-columns: 160px 1fr 240px;
  min-height: 0;
  overflow: hidden;
}
.io-hmi-palette {
  border-right: 1px solid var(--border);
  background: var(--bg-1);
  padding: 10px;
  overflow-y: auto;
}
.io-hmi-pal-title {
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: .6px;
  font-weight: 700;
  color: var(--fg-mute);
  margin-bottom: 8px;
}
.io-hmi-pal-item {
  padding: 10px 12px;
  background: var(--bg-2);
  border: 1px solid var(--border);
  border-radius: 8px;
  font-size: 12.5px;
  font-weight: 600;
  cursor: grab;
  margin-bottom: 6px;
  user-select: none;
  -webkit-user-select: none;
}
.io-hmi-pal-item:hover { background: var(--bg-3); border-color: var(--border-hi); }
.io-hmi-canvas {
  position: relative;
  overflow: auto;
  background-color: var(--bg);
  background-image:
    linear-gradient(rgba(255,255,255,.045) 1px, transparent 1px),
    linear-gradient(90deg, rgba(255,255,255,.045) 1px, transparent 1px);
  background-size: 20px 20px;
  min-height: 0;
}
[data-theme="light"] .io-hmi-canvas {
  background-image:
    linear-gradient(rgba(0,0,0,.055) 1px, transparent 1px),
    linear-gradient(90deg, rgba(0,0,0,.055) 1px, transparent 1px);
}
.io-hmi-side {
  border-left: 1px solid var(--border);
  background: var(--bg-1);
  padding: 12px 14px;
  overflow-y: auto;
}
.io-hmi-side-title {
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: .6px;
  font-weight: 700;
  color: var(--fg-mute);
  margin-bottom: 10px;
}
.io-hmi-field { display: flex; flex-direction: column; gap: 4px; margin-bottom: 10px; }
.io-hmi-field label { font-size: 11px; color: var(--fg-mute); }
.io-hmi-field input {
  padding: 8px 10px;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: 6px;
  color: var(--fg);
  font-family: var(--mono);
  font-size: 13px;
  outline: none;
}
.io-hmi-field input:focus { border-color: var(--accent); }
.io-hmi-hint { font-size: 12px; color: var(--fg-dim); line-height: 1.5; }
.io-hmi-obj {
  position: absolute;
  background: var(--bg-2);
  border: 2px solid var(--border-hi);
  border-radius: 10px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 4px;
  cursor: grab;
  user-select: none;
  -webkit-user-select: none;
  touch-action: none;
  padding: 6px;
  box-shadow: 0 2px 8px rgba(0,0,0,.35);
  transition: border-color .1s linear;
}
.io-hmi-obj.selected { border-color: var(--accent); box-shadow: 0 0 0 2px rgba(88,166,255,.35); }
.io-obj-label { font-size: 11px; color: var(--fg-dim); text-align: center; }
.io-obj-addr { font-size: 10px; color: var(--fg-mute); font-family: var(--mono); }
.io-lamp-light {
  width: 46px; height: 46px; border-radius: 50%;
  background: var(--bg-3);
  border: 3px solid var(--border-hi);
  transition: background .1s linear, box-shadow .1s linear;
}
.io-lamp-light.on {
  background: radial-gradient(circle at 35% 30%, #a7ffb6, var(--green) 65%);
  box-shadow: 0 0 16px rgba(46,204,113,.85), inset 0 0 8px rgba(255,255,255,.45);
}
.io-switch-btn {
  min-width: 78px;
  padding: 8px 12px;
  font-family: var(--mono);
  font-size: 14px;
  font-weight: 800;
  letter-spacing: 1px;
  color: var(--fg-dim);
  background: var(--bg-3);
  border: 2px solid var(--border-hi);
  border-radius: 8px;
  cursor: pointer;
}
.io-switch-btn.on {
  background: var(--green);
  color: #001a0d;
  border-color: var(--green);
  box-shadow: 0 0 12px rgba(46,204,113,.55);
}
.io-num-value {
  font-family: var(--mono);
  font-size: 22px;
  font-weight: 800;
  color: var(--green);
  padding: 4px 10px;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: 6px;
  min-width: 90px;
  text-align: center;
}
.io-slider-row { width: 100%; }
.io-slider-input { width: 100%; accent-color: var(--accent); }
@media (max-width: 900px) {
  .io-hmi-wrap { grid-template-columns: 120px 1fr; }
  .io-hmi-side {
    grid-column: 1 / -1;
    border-left: 0;
    border-top: 1px solid var(--border);
    max-height: 34vh;
  }
  .io-tiles { grid-template-columns: repeat(auto-fill, minmax(74px, 1fr)); }
  .io-tile { min-height: 52px; }
  .io-hmi-pal-item { padding: 12px 10px; font-size: 12px; }
}
.gnode-out-value.pending {
  background: var(--bg-3);
  color: var(--fg-mute);
  border-color: var(--border);
  box-shadow: none;
}

/* =========================================================================
   u_16h1_1 — patch additions
   ========================================================================= */

/* ---- Toggle buttons: visible "collapsed" state ------------------------ */
.panel-toggle.collapsed {
  background: var(--accent-2);
  border-color: var(--accent);
  color: #fff;
  box-shadow: 0 0 12px rgba(88,166,255,.75), 0 0 4px rgba(88,166,255,.5) inset;
  animation: wlcTogglePulse 1.6s ease-in-out infinite;
}
.panel-toggle.collapsed:hover {
  background: var(--accent);
  border-color: var(--accent);
  box-shadow: 0 0 18px rgba(88,166,255,1);
  animation: none;
}
.panel-toggle.collapsed::after {
  content: '';
  position: absolute;
  inset: -3px;
  border: 1px solid rgba(88,166,255,.35);
  border-radius: inherit;
  pointer-events: none;
}
@keyframes wlcTogglePulse {
  0%,100% { box-shadow: 0 0 12px rgba(88,166,255,.75); }
  50%     { box-shadow: 0 0 18px rgba(88,166,255,1), 0 0 4px rgba(88,166,255,.8) inset; }
}
.panel-toggle.hmi-pos { transition: left .18s ease, background .12s, border-color .12s; }

/* ---- HMI canvas: element selection ring ------------------------------- */
.io-hmi-obj {
  background: transparent; border: none; border-radius: 0;
  padding: 2px; box-shadow: none;
  transition: box-shadow .12s, outline-color .12s;
}
.io-hmi-obj.selected {
  outline: 2px dashed var(--accent);
  outline-offset: 3px;
  background: rgba(88,166,255,.04);
}

/* ---- Element visuals — no frame --------------------------------------- */
.io-lamp-light {
  width: 46px; height: 46px; border-radius: 50%;
  background: #1a1f29; border: 2px solid #3a3f45;
  box-shadow: inset 0 2px 6px rgba(0,0,0,.55);
  transition: background .12s, box-shadow .12s, border-color .12s;
  align-self: center;
}
.io-btn {
  font: inherit; font-size: 12px; font-weight: 600;
  padding: 6px 12px; border-radius: 8px;
  border: 1px solid var(--border);
  background: var(--bg-2); color: var(--fg);
  cursor: pointer; min-width: 60px; align-self: center;
  box-shadow: 0 1px 3px rgba(0,0,0,.35);
  transition: background .12s, color .12s, border-color .12s;
  touch-action: manipulation;
}
.io-btn:hover { background: var(--bg-3); }
.io-btn:active { transform: translateY(1px); }
.io-btn-word { background: rgba(88,166,255,.14); border-color: rgba(88,166,255,.4); color: var(--accent); }
.io-num-value {
  font-family: var(--mono); font-size: 20px; font-weight: 800;
  color: var(--green); padding: 2px 10px; background: var(--bg);
  border-radius: 6px; border: 1px solid var(--border);
  text-align: center; min-width: 70px; align-self: center;
}
.io-char-value {
  font-family: var(--mono); font-size: 13px; font-weight: 700;
  color: var(--accent); padding: 4px 10px; background: var(--bg);
  border: 1px solid var(--border); border-radius: 6px;
  text-align: center; align-self: center; min-width: 80px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.io-color-swatch {
  width: 42px; height: 42px; border-radius: 50%;
  background: var(--bg-3); border: 2px solid var(--border-hi);
  display: flex; align-items: center; justify-content: center;
  font-family: var(--mono); font-size: 10px; font-weight: 800;
  color: #fff; align-self: center; transition: background .12s;
}
.io-range-bar {
  width: 100%; height: 12px; border-radius: 6px;
  background: var(--bg-3); overflow: hidden; border: 1px solid var(--border);
}
.io-range-fill {
  height: 100%; background: linear-gradient(90deg, var(--green-dim), var(--green));
  transition: width .15s;
}
.io-meter {
  width: 90px; height: 90px; position: relative; align-self: center;
  border-radius: 50%;
  background: radial-gradient(circle at 50% 80%, var(--bg-2), var(--bg));
  border: 3px solid var(--border-hi); overflow: hidden;
}
.io-meter-needle {
  position: absolute; left: 50%; bottom: 50%;
  width: 2px; height: 40px; background: var(--red);
  transform-origin: 50% 100%;
  transition: transform .18s ease-out; border-radius: 2px;
}
.io-bar {
  width: 100%; height: 100%; background: var(--bg-3);
  border-radius: 6px; position: relative; overflow: hidden;
  border: 1px solid var(--border);
}
.io-bar-fill {
  position: absolute; bottom: 0; left: 0; right: 0;
  background: linear-gradient(180deg, var(--green), var(--green-dim));
  transition: height .15s;
}
.io-pipe {
  width: 100%; height: 100%; background: var(--bg-3);
  border-radius: 4px 4px 8px 8px; position: relative;
  overflow: hidden; border: 1px solid var(--border);
}
.io-pipe-fill {
  position: absolute; bottom: 0; left: 0; right: 0;
  background: linear-gradient(180deg, #58a6ff, #1f6feb);
  transition: height .15s;
}
.io-pie { display: block; }
.io-dyn-line { align-self: center; border-radius: 3px; transition: width .15s, background .15s; }
.io-dyn-rect, .io-dyn-ellipse {
  width: 100%; height: 100%; background: var(--accent-2);
  opacity: .85; transition: transform .15s; align-self: center;
}
.io-dyn-rect { border-radius: 6px; }
.io-dyn-ellipse { border-radius: 50%; }
.io-state-graphic {
  width: 60px; height: 60px; border-radius: 50%;
  background: var(--bg-2); border: 2px dashed var(--border-hi);
  display: flex; align-items: center; justify-content: center;
  font-family: var(--mono); font-size: 22px; font-weight: 800;
  color: var(--accent); align-self: center;
}
.io-slider-row { width: 100%; padding: 0 4px; }
.io-slider-input { width: 100%; accent-color: var(--accent); }
.io-entry-input {
  width: 100%; padding: 6px 8px; box-sizing: border-box;
  background: var(--bg); color: var(--fg);
  font-family: var(--mono); font-size: 13px;
  border: 1px solid var(--border); border-radius: 6px; align-self: stretch;
}
.io-select {
  width: 100%; padding: 6px 8px; box-sizing: border-box;
  background: var(--bg); color: var(--fg);
  border: 1px solid var(--border); border-radius: 6px; align-self: stretch;
}

/* ---- Grouped palette ------------------------------------------------- */
.io-hmi-pal-group {
  font-size: 10px; font-weight: 800; letter-spacing: .5px;
  text-transform: uppercase; color: var(--fg-mute);
  padding: 10px 4px 4px;
  border-bottom: 1px solid var(--border); margin-bottom: 4px;
}

/* ---- Properties sidebar in HMI mode --------------------------------- */
.io-hmi-actions { display: flex; gap: 6px; margin-top: 8px; flex-wrap: wrap; }
.io-hmi-color-row { display: flex; flex-direction: row !important; align-items: center; gap: 10px; }
.io-hmi-color-row label { flex: 1; }
.io-hmi-color-row input[type=color] {
  width: 42px; height: 30px; padding: 2px; border-radius: 6px;
  background: var(--bg-2); border: 1px solid var(--border); cursor: pointer;
}

/* ---- Marquee box ---------------------------------------------------- */
.io-hmi-marquee { pointer-events: none; }

/* ---- SVG child shape fixups ----------------------------------------- */
.io-hmi-obj svg { display: block; margin: 0 auto; }
.io-hmi-obj.io-obj-rect > svg,
.io-hmi-obj.io-obj-circle > svg,
.io-hmi-obj.io-obj-line > svg,
.io-hmi-obj.io-obj-diamond > svg,
.io-hmi-obj.io-obj-triangle > svg,
.io-hmi-obj.io-obj-rightTri > svg,
.io-hmi-obj.io-obj-pentagon > svg,
.io-hmi-obj.io-obj-hexagon > svg,
.io-hmi-obj.io-obj-star > svg,
.io-hmi-obj.io-obj-polygon > svg,
.io-hmi-obj.io-obj-arc > svg,
.io-hmi-obj.io-obj-scale > svg,
.io-hmi-obj.io-obj-table > svg,
.io-hmi-obj.io-obj-hollowCircle > svg { position: static; inset: auto; }

/* ---- Mobile adjustments --------------------------------------------- */
@media (max-width: 900px) {
  .io-hmi-pal-item { min-height: 40px; padding: 12px 12px; font-size: 13px; }
  .io-hmi-pal-group { font-size: 11px; }
  .io-btn { min-height: 40px; font-size: 13px; }
  .panel-toggle.collapsed { width: 22px; height: 58px; font-size: 15px; }
}

/* =========================================================================
   u_17_6 — HMI overhaul
   ========================================================================= */
.toolbar-view-btn { flex: 0 0 auto !important; }
.editor-tabs .tab { position: relative; transition: background .12s, color .12s; }
.editor-tabs .tab[style*="--tab-color"] {
  background: color-mix(in oklab, var(--tab-color) 22%, transparent);
  border-color: color-mix(in oklab, var(--tab-color) 50%, var(--border));
}
.editor-tabs .tab[style*="--tab-color"]:hover {
  background: color-mix(in oklab, var(--tab-color) 32%, transparent);
}
.editor-tabs .tab[style*="--tab-color"].active {
  background: color-mix(in oklab, var(--tab-color) 38%, transparent);
  border-color: var(--tab-color);
  box-shadow: 0 -1px 0 0 var(--tab-color) inset;
}
.editor-tabs .tab-name { display:inline-block; }
.editor-tabs .tab-name-input { vertical-align: middle; }

.io-hmi-canvas { position: relative; overflow: auto; }
.io-hmi-canvas-scale { position: relative; min-width: 100%; min-height: 100%; }

.io-hmi-area {
  position: absolute; box-sizing: border-box; z-index: 1;
  pointer-events: auto; cursor: move; touch-action: none;
  transition: box-shadow .12s;
}
.io-hmi-area:hover    { box-shadow: 0 0 0 1px rgba(88,166,255,.35); }
.io-hmi-area.selected { box-shadow: 0 0 0 1px var(--accent), 0 0 14px rgba(88,166,255,.45); }
.io-hmi-area-resize   { z-index: 90; }

.io-hmi-wrap { display: grid; grid-template-columns: 180px 1fr 340px;
               min-height: 0; overflow: hidden; }
.io-hmi-wrap.hmi-view-only { grid-template-columns: 0 1fr 0; }
.io-hmi-palette { display: flex; flex-direction: column; min-height: 0;
                  overflow: hidden; background: var(--bg-1);
                  border-right: 1px solid var(--border); }
.io-hmi-pal-fixed { flex: 0 0 auto; background: var(--bg-1);
                    border-bottom: 1px solid var(--border); padding-bottom: 6px; }
.io-hmi-pal-title { padding: 10px 12px 6px; font-size: 11px;
                    text-transform: uppercase; letter-spacing: .8px;
                    font-weight: 700; color: var(--fg-mute); }
.io-hmi-pal-search {
  width: calc(100% - 16px); margin: 0 8px 4px;
  padding: 6px 10px; background: var(--bg);
  border: 1px solid var(--border); border-radius: 6px;
  color: var(--fg); font-size: 12px; outline: none; box-sizing: border-box;
}
.io-hmi-pal-search:focus { border-color: var(--accent); }
.io-hmi-pal-list { flex: 1 1 auto; overflow-y: auto; overflow-x: hidden;
                   min-height: 0; scrollbar-gutter: stable; scrollbar-width: thin; }
.io-hmi-pal-list::-webkit-scrollbar { width: 6px; }
.io-hmi-pal-list::-webkit-scrollbar-thumb {
  background: rgba(139,150,165,.30); border-radius: 3px;
}
.io-hmi-side {
  width: 340px !important; min-width: 340px; max-width: 340px;
  overflow-y: auto; overflow-x: hidden;
  padding: 14px 16px 24px; background: var(--bg-1);
  border-left: 1px solid var(--border);
  scrollbar-gutter: stable; scrollbar-width: thin; box-sizing: border-box;
}
.io-hmi-side::-webkit-scrollbar { width: 6px; }
.io-hmi-side::-webkit-scrollbar-thumb {
  background: rgba(139,150,165,.30); border-radius: 3px;
}
.io-hmi-side-title { font-size: 13px; font-weight: 700; color: var(--fg);
                     margin-bottom: 12px; padding-bottom: 6px;
                     border-bottom: 1px solid var(--border); }
.io-hmi-field { display: flex; flex-direction: column; margin-bottom: 12px; gap: 4px; }
.io-hmi-field-head { display: flex; align-items: center;
                     justify-content: space-between; gap: 8px; }
.io-hmi-field-head > label:first-child {
  font-size: 11px; color: var(--fg-mute);
  text-transform: uppercase; letter-spacing: .4px; flex: 1 1 auto;
}
.io-hmi-check { display: inline-flex; align-items: center; gap: 4px;
  font-size: 10.5px; color: var(--fg-mute); text-transform: none;
  letter-spacing: 0; cursor: pointer; user-select: none; }
.io-hmi-check input[type="checkbox"] { margin: 0; accent-color: var(--accent); cursor: pointer; }
.io-hmi-field > label { font-size: 11px; color: var(--fg-mute);
                        text-transform: uppercase; letter-spacing: .4px; }
.io-hmi-field > input, .io-hmi-field > select {
  width: 100%; padding: 6px 9px; background: var(--bg);
  border: 1px solid var(--border); border-radius: 6px;
  color: var(--fg); font-family: var(--mono); font-size: 12px;
  outline: none; box-sizing: border-box;
}
.io-hmi-field > input:focus, .io-hmi-field > select:focus { border-color: var(--accent); }
.io-hmi-field.io-hmi-color-row { flex-direction: row !important; align-items: center; }
.io-hmi-field.io-hmi-color-row > label { flex: 1; }
.io-hmi-field.io-hmi-color-row > input[type="color"] {
  width: 48px; height: 30px; padding: 2px; cursor: pointer;
}
.io-hmi-obj { overflow: visible !important; }
.io-hmi-obj-resize {
  position: absolute; width: 14px; height: 14px;
  background: var(--bg-1); border: 2px solid var(--accent);
  border-radius: 3px; z-index: 60;
  box-shadow: 0 1px 4px rgba(0,0,0,.4); touch-action: none;
}
.io-hmi-resize-nw { top: -7px;    left: -7px;   cursor: nwse-resize; }
.io-hmi-resize-ne { top: -7px;    right: -7px;  cursor: nesw-resize; }
.io-hmi-resize-sw { bottom: -7px; left: -7px;   cursor: nesw-resize; }
.io-hmi-resize-se { bottom: -7px; right: -7px;  cursor: nwse-resize; }
.io-hmi-obj.selected .io-hmi-obj-resize { display: block; }
.io-hmi-obj .io-hmi-obj-resize { display: none; }
.io-hmi-guides { position: absolute; top: 0; left: 0; width: 0; height: 0;
                 pointer-events: none; z-index: 500; }
.io-hmi-guide { position: absolute; background: var(--amber);
                pointer-events: none; box-shadow: 0 0 4px rgba(243,156,18,.8); }
.io-hmi-guide-v { width: 1px; top: 0; height: 8000px; }
.io-hmi-guide-h { height: 1px; left: 0; width: 8000px; }
.io-hmi-obj > *:not(.io-hmi-obj-resize):not(.io-hmi-guides) {
  max-width: 100%; max-height: 100%;
}
.io-hmi-obj .io-btn, .io-hmi-obj .io-lamp-light,
.io-hmi-obj .io-num-value, .io-hmi-obj .io-char-value,
.io-hmi-obj .io-color-swatch, .io-hmi-obj .io-range-bar,
.io-hmi-obj .io-bar, .io-hmi-obj .io-pipe, .io-hmi-obj .io-meter,
.io-hmi-obj .io-entry-input, .io-hmi-obj .io-select {
  width: 100%; height: 100%; min-width: 0; min-height: 0; box-sizing: border-box;
}
.io-hmi-obj .io-num-value, .io-hmi-obj .io-char-value, .io-hmi-obj .io-color-swatch {
  display: flex; align-items: center; justify-content: center;
}
.io-hmi-obj .io-slider-row { width: 100%; padding: 0; }
.io-hmi-obj svg { display: block; max-width: 100%; max-height: 100%; }
.io-hmi-obj .io-pie, .io-hmi-obj .io-trend { width: 100% !important; height: 100% !important; }
.panel-toggle.hmi-pos { z-index: 300; }
@media (max-width: 900px) {
  .io-hmi-wrap { grid-template-columns: 140px 1fr 280px; }
  .io-hmi-side { width: 280px !important; min-width: 280px; padding: 12px; }
}
@media (max-width: 640px) {
  .io-hmi-wrap { grid-template-columns: 1fr; grid-template-rows: 130px 1fr 1fr; }
  .io-hmi-palette { border-right: none; border-bottom: 1px solid var(--border); }
  .io-hmi-side { width: 100% !important; min-width: 0;
                 border-left: none; border-top: 1px solid var(--border); }
}


/* =========================================================================
   u_17_7 — refinements
   ========================================================================= */

/* 1. Toolbar height is identical in every view -------------------------- */
.view-toggle {
  height: 42px;
  min-height: 42px;
  max-height: 42px;
  align-items: center;
  padding: 6px 10px;
  box-sizing: border-box;
  flex-wrap: nowrap;
  overflow-x: auto;
  overflow-y: hidden;
}
.view-toggle > * { flex-shrink: 0; }
.view-toggle .tool-btn,
.view-toggle .btn.ghost.sm,
.view-toggle .tool-select,
.view-toggle .tool-color {
  height: 30px;
  min-height: 30px;
  max-height: 30px;
  box-sizing: border-box;
  display: inline-flex;
  align-items: center;
  line-height: 1;
}
.view-toggle .tool-color { padding: 2px; }
.view-toggle .tool-sep { height: 24px; align-self: center; }

/* 6. hmi-view-only: hide BOTH palette and properties panes -------------- */
.io-hmi-wrap.hmi-view-only { grid-template-columns: 1fr; }
.io-hmi-wrap.hmi-view-only .io-hmi-palette,
.io-hmi-wrap.hmi-view-only .io-hmi-side {
  display: none !important;
  width: 0 !important;
  min-width: 0 !important;
  max-width: 0 !important;
  padding: 0 !important;
  overflow: hidden !important;
}

/* 3+4. Area / object z-order --------------------------------------------- */
.io-hmi-area { z-index: 1 !important; }
.io-hmi-obj  { z-index: 10 !important; }
.io-hmi-area.locked {
  cursor: default !important;
  box-shadow: 0 0 0 1px var(--amber) !important;
  opacity: 0.96;
}
.io-hmi-area.locked:hover { box-shadow: 0 0 0 2px var(--amber) !important; }

/* 5. HMI canvas scroll only when needed --------------------------------- */
.io-hmi-canvas {
  overflow: auto;
  scrollbar-gutter: stable;
}
.io-hmi-canvas::-webkit-scrollbar { width: 10px; height: 10px; }
.io-hmi-canvas::-webkit-scrollbar-thumb {
  background: rgba(139,150,165,.35);
  border-radius: 6px;
  border: 2px solid var(--bg);
}

/* 7. Program tab close button (top-right corner) ----------------------- */
.editor-tabs .tab {
  position: relative;
  padding-right: 24px !important;
}
.editor-tabs .tab-close {
  position: absolute;
  top: 2px;
  right: 2px;
  width: 16px;
  height: 16px;
  line-height: 1;
  text-align: center;
  font-size: 13px;
  font-weight: 700;
  border-radius: 50%;
  color: var(--fg-mute);
  cursor: pointer;
  opacity: 0.4;
  transition: background .12s, color .12s, opacity .12s;
  display: flex;
  align-items: center;
  justify-content: center;
  pointer-events: auto;
  user-select: none;
  -webkit-user-select: none;
}
.editor-tabs .tab:hover .tab-close { opacity: 1; }
.editor-tabs .tab-close:hover {
  background: var(--red);
  color: #fff;
  opacity: 1;
}

/* Inline confirmation modal --------------------------------------------- */
.wlc-inline-confirm-back {
  animation: wlcInlineFade .12s ease;
}
@keyframes wlcInlineFade { from { opacity: 0; } }


/* =========================================================================
   u_17_8 — defensive
   ========================================================================= */

/* HMI view-only: absolutely one-column, no side panes anywhere in the tree */
.io-hmi-wrap.hmi-view-only {
  grid-template-columns: 1fr !important;
  grid-template-rows: 1fr !important;
}
.io-hmi-wrap.hmi-view-only > .io-hmi-palette,
.io-hmi-wrap.hmi-view-only > .io-hmi-side {
  display: none !important;
  visibility: hidden !important;
  width: 0 !important;
  min-width: 0 !important;
  max-width: 0 !important;
  padding: 0 !important;
  margin: 0 !important;
  overflow: hidden !important;
  border: 0 !important;
}
.io-hmi-wrap.hmi-view-only > .io-hmi-canvas {
  grid-column: 1 / -1;
}

/* Small focus ring on emoji buttons (a11y) */
#wlcTabCloseConfirm button:focus {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
}


/* =========================================================================
   u_17_9 — view-only body class + thin palette scrollbar
   ========================================================================= */

/* When body has wlc-hmi-view-only:
   hide rightbar, palette, properties; canvas fills the whole area. */

body.wlc-hmi-view-only .io-hmi-wrap {
  grid-template-columns: 1fr !important;
  grid-template-rows: 1fr !important;
}
body.wlc-hmi-view-only .io-hmi-palette,
body.wlc-hmi-view-only .io-hmi-side {
  display: none !important;
  visibility: hidden !important;
  width: 0 !important;
  min-width: 0 !important;
  max-width: 0 !important;
  padding: 0 !important;
  margin: 0 !important;
  border: 0 !important;
  overflow: hidden !important;
}
body.wlc-hmi-view-only .io-hmi-canvas {
  grid-column: 1 / -1 !important;
  grid-row:    1 / -1 !important;
}

/* Thin palette scrollbar so it does not visually compete with the toggle */
.io-hmi-pal-list {
  scrollbar-gutter: auto;
  scrollbar-width: thin;
}
.io-hmi-pal-list::-webkit-scrollbar { width: 4px; }
.io-hmi-pal-list::-webkit-scrollbar-track { background: transparent; }
.io-hmi-pal-list::-webkit-scrollbar-thumb {
  background: rgba(139,150,165,.35);
  border-radius: 2px;
}

/* HMI toggle: clearly a toggle, sits exactly on the palette edge */
.panel-toggle.hmi-pos {
  z-index: 300;
  width: 14px;
  height: 52px;
  border-radius: 4px;
  font-size: 12px;
  font-weight: 800;
  line-height: 1;
  box-shadow: 0 2px 8px rgba(0,0,0,.45);
}
.panel-toggle.hmi-pos.collapsed {
  background: var(--accent-2);
  border-color: var(--accent);
  color: #fff;
}


/* =========================================================================
   u_17_10 — view-only body class (bulletproof)
   -------------------------------------------------------------------------
   Only the canvas remains inside .io-hmi-wrap when body has
   wlc-hmi-view-only.  The workspace rightbar (Device / Watch / Health)
   is NOT touched by any rule here — it stays exactly as the user left it.
   ========================================================================= */

body.wlc-hmi-view-only .io-hmi-wrap {
  grid-template-columns: 1fr !important;
  grid-template-rows: 1fr !important;
}
body.wlc-hmi-view-only .io-hmi-palette,
body.wlc-hmi-view-only .io-hmi-side {
  display: none !important;
  visibility: hidden !important;
  width: 0 !important;
  min-width: 0 !important;
  max-width: 0 !important;
  padding: 0 !important;
  margin: 0 !important;
  border: 0 !important;
  overflow: hidden !important;
}
body.wlc-hmi-view-only .io-hmi-canvas {
  grid-column: 1 / -1 !important;
  grid-row: 1 / -1 !important;
}

/* Toggle button look */
.panel-toggle.hmi-pos {
  z-index: 300;
  width: 14px;
  height: 52px;
  border-radius: 4px;
  font-size: 12px;
  font-weight: 800;
  line-height: 1;
  box-shadow: 0 2px 8px rgba(0,0,0,.45);
}
.panel-toggle.hmi-pos.collapsed {
  background: var(--accent-2);
  border-color: var(--accent);
  color: #fff;
}

/* Thin palette scrollbar so it does not resemble the toggle */
.io-hmi-pal-list::-webkit-scrollbar { width: 4px; }
.io-hmi-pal-list::-webkit-scrollbar-track { background: transparent; }
.io-hmi-pal-list::-webkit-scrollbar-thumb {
  background: rgba(139,150,165,.35);
  border-radius: 2px;
}

/* =========================================================================
   u_18_12 — hide scrollbars on the topbar and program tab bar, and allow
   wheel-based horizontal scrolling (see app.js for the wheel handler).
   ========================================================================= */
.topbar,
.editor-tabs {
  scrollbar-width: none;                 /* Firefox */
  -ms-overflow-style: none;              /* old IE/Edge */
}
.topbar::-webkit-scrollbar,
.editor-tabs::-webkit-scrollbar {
  width: 0;
  height: 0;
  display: none;                         /* Chromium / WebKit */
}

/* u_18_13 - HMI file name + fullscreen HMI */
.hmi-file-name-display {
  font-family: var(--mono);
  font-size: 12px;
  font-weight: 600;
  padding: 4px 12px;
  border-radius: 6px;
  background: color-mix(in oklab, var(--fg) 5%, transparent);
  border: 1px solid var(--border);
  color: var(--fg);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 40vw;
  cursor: pointer;
  user-select: none;
  -webkit-user-select: none;
  transition: border-color .12s, background .12s;
}
.hmi-file-name-display:hover {
  border-color: var(--border-hi);
  background: color-mix(in oklab, var(--fg) 9%, transparent);
}
.hmi-file-name-input {
  width: 100%;
  min-width: 140px;
  padding: 3px 8px;
  font: inherit;
  font-family: var(--mono);
  font-weight: 600;
  text-align: center;
  background: var(--bg);
  border: 1px solid var(--accent);
  border-radius: 4px;
  outline: none;
  color: var(--fg);
  box-sizing: border-box;
}
.io-hmi-ctx .ctx-item.active {
  background: var(--accent-2);
  color: #fff;
}
.io-hmi-ctx .io-hmi-search-row {
  cursor: pointer;
}

/* =========================================================================
   u_18_16 — fullscreen HMI.  When body has wlc-hmi-screen-active, hide
   every piece of app chrome that lives outside #app so only the frame
   from renderHMIScreen() remains visible.
   ========================================================================= */
body.wlc-hmi-screen-active > .toast-wrap,
body.wlc-hmi-screen-active > .ctx-menu:not(.io-hmi-ctx),
body.wlc-hmi-screen-active > .device-switcher,
body.wlc-hmi-screen-active > .node-tooltip,
body.wlc-hmi-screen-active > .mobile-nav,
body.wlc-hmi-screen-active > .sidebar-backdrop {
  display: none !important;
}
body.wlc-hmi-screen-active {
  overflow: hidden !important;
  background: #000 !important;
}
body.wlc-hmi-screen-active #app {
  overflow: hidden !important;
  background: #000 !important;
}
.hmi-fullscreen-frame {
  box-shadow: 0 0 40px rgba(0,0,0,.85);
}

/* =========================================================================
   u_18_18 — object hit pads, area hotzones, fullscreen header
   ========================================================================= */

/* 6. Bigger touch / click area around each HMI object.
   The hit pad is a first child with a negative inset; it captures clicks
   in the padding ring around the object without covering the object's
   own inner content (buttons, inputs). */
.io-hmi-obj {
  /* leave positioning / size alone */
}
.io-hmi-obj .io-hmi-obj-hitpad {
  position: absolute;
  inset: -6px;
  border-radius: 8px;
  background: transparent;
  z-index: 0;
  pointer-events: auto;
}

/* Visible hover ring so the user can see what they are about to grab */
.io-hmi-obj:hover::after {
  content: '';
  position: absolute;
  inset: -3px;
  border-radius: 8px;
  border: 1px dashed var(--accent);
  opacity: .55;
  pointer-events: none;
  z-index: 30;
}
.io-hmi-obj.selected:hover::after {
  border-color: var(--accent);
  border-style: solid;
  opacity: .85;
}

/* 3. HMI area resize hotzones (invisible) */
.io-hmi-area-hotzone {
  background: transparent;
  /* make sure they sit above content but only in the corners */
  z-index: 200 !important;
}
.io-hmi-area { touch-action: none; }
.io-hmi-area-hotzone { touch-action: none; }

/* 1-2. Fullscreen HMI header */
.hmi-fullscreen-header {
  font-family: var(--sans);
}
#hmiFsHeaderCenter { color: #e6edf3; }
#hmiFsHeaderRight  { font-variant-numeric: tabular-nums; }
.hmi-fullscreen-frame { box-shadow: 0 0 40px rgba(0,0,0,.85); }

/* Larger resize handles on objects so they are easier to grab */
.io-hmi-obj-resize {
  width: 18px !important;
  height: 18px !important;
  border-width: 3px !important;
}

/* =========================================================================
   u_19_1 — HMI improvements
   ========================================================================= */

/* (5) Invisible hit ring around objects for easier selection.
   The CSS rule for .io-hmi-obj-hitpad already existed in u_17_6 but no
   DOM element was ever created for it.  u_19_1 injects the element and
   enlarges the ring. */
.io-hmi-obj > .io-hmi-obj-hitpad {
  position: absolute;
  inset: -9px;
  background: transparent;
  border-radius: 12px;
  z-index: 0;
  pointer-events: auto;
}
.io-hmi-obj > *:not(.io-hmi-obj-hitpad):not(.io-hmi-obj-resize) {
  z-index: 1;
}
.io-hmi-obj.selected {
  outline: 2px dashed var(--accent);
  outline-offset: 4px;
}
.io-hmi-obj .io-hmi-obj-resize {
  width: 20px !important;
  height: 20px !important;
  border-width: 3px !important;
}

/* (11) Locked HMI area becomes a click-through background so a marquee
   drag inside it selects objects normally. */
.io-hmi-area.locked,
.io-hmi-area.locked > * {
  pointer-events: none !important;
}

/* (2) Fullscreen HMI header overlay — semi-transparent, tinted. */
.hmi-fullscreen-header {
  background: linear-gradient(180deg, rgba(0,0,0,.65), rgba(0,0,0,.25)) !important;
  border-bottom: 1px solid rgba(255,255,255,.06) !important;
}

/* (8)(14) HMI toolbar action buttons. */
.io-modebar .io-tool-btn {
  padding: 6px 10px;
  border: 1px solid var(--border);
  background: var(--bg-2);
  color: var(--fg);
  border-radius: 6px;
  cursor: pointer;
  font-size: 13px;
  display: inline-flex;
  align-items: center;
  gap: 4px;
  min-height: 30px;
  white-space: nowrap;
}
.io-modebar .io-tool-btn:hover { background: var(--bg-3); border-color: var(--border-hi); }
.io-modebar .io-tool-btn:active { transform: translateY(1px); }
.io-modebar .io-tool-btn:disabled { opacity: .4; cursor: not-allowed; }

/* (7) Inline Set Value popup (no browser prompt). */
.io-hmi-setvalue {
  position: fixed;
  z-index: 2147483647;
  background: var(--bg-1);
  border: 1px solid var(--border-hi);
  border-radius: 8px;
  padding: 10px 12px;
  box-shadow: 0 12px 32px rgba(0,0,0,.6);
  display: flex; flex-direction: column; gap: 8px;
  min-width: 200px;
  color: var(--fg);
  font-family: var(--sans);
}
.io-hmi-setvalue input {
  width: 100%; padding: 6px 8px; box-sizing: border-box;
  background: var(--bg); border: 1px solid var(--border);
  border-radius: 5px; color: var(--fg);
  font-family: var(--mono); font-size: 13px; outline: none;
}
.io-hmi-setvalue .err { color: var(--red); font-size: 11.5px; min-height: 14px; }

/* u_19_2 HMI refinements */

/* Hide the u_19_1 injected toolbar group inside the small HMI modebar.
   The buttons are moving to the main tools bar (view-toggle row).
   Only our injected group is a direct <div> child; the modebar's own
   children are <button> and <span>. */
.io-modebar > div { display: none !important; }

/* Fullscreen HMI header — width matches the frame, semi-transparent */
.hmi-fs-header {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 0 10px;
  background: rgba(0,0,0,.55);
  border-bottom: 1px solid rgba(255,255,255,.08);
  color: #e6edf3;
  font-family: var(--sans);
  font-size: 13px;
  box-sizing: border-box;
}
.hmi-fs-exit-btn {
  flex: 0 0 auto;
  background: transparent;
  color: #e6edf3;
  border: 1px solid rgba(255,255,255,.18);
  border-radius: 5px;
  padding: 4px 10px;
  cursor: pointer;
  font-size: 12px;
  display: inline-flex;
  align-items: center;
  gap: 4px;
  transition: background .12s, border-color .12s, color .12s;
}
.hmi-fs-exit-btn:hover {
  background: rgba(231,76,60,.35);
  border-color: rgba(231,76,60,.65);
  color: #fff;
}
.hmi-fs-center {
  flex: 1 1 auto;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  min-width: 0;
  white-space: nowrap;
  overflow: hidden;
}
.hmi-fs-dot {
  width: 10px; height: 10px; border-radius: 50%;
  flex: 0 0 auto;
  background: #8b96a5;
  box-shadow: 0 0 0 2px rgba(255,255,255,.10);
  transition: background .2s, box-shadow .2s;
}
.hmi-fs-text {
  overflow: hidden; text-overflow: ellipsis;
}
.hmi-fs-wifi {
  flex: 0 0 auto;
  font-family: var(--mono);
  font-weight: 700;
  letter-spacing: .3px;
  color: #5b6878;
  transition: color .2s;
}

/* Prevent scroll-anchor jitter inside the HMI canvas */
.io-hmi-canvas { overflow-anchor: none; }

/* Narrower right-click menu (was 380-480 px) */
.io-hmi-ctx {
  min-width: 280px !important;
  max-width: 340px !important;
}

/* u_19_3 refinements */

/* (1) Watch panel — no internal scrollbar; the rightbar scrolls instead
   if the whole sidebar overflows. */
.panel-body#watchBody {
  max-height: none !important;
  overflow: visible !important;
}

/* (3) Kill scroll-anchor jitter inside the toolbar strips so a rebuild
   cannot adjust their scrollLeft/Top on its own. */
.view-toggle,
.editor-tabs,
.topbar {
  overflow-anchor: none;
}

/* (2) Right-click menu — always narrower now, and the palette-only
   version never needs the old 480 px ceiling. */
.io-hmi-ctx {
  min-width: 280px !important;
  max-width: 340px !important;
}

/* =========================================================================
   u_19_4 mobile HMI — portrait refinements
   ========================================================================= */

/* The mobile nav now carries up to 8 items in HMI mode (Palette, Editor,
   Sim, Monitor, IO, Edit OB, Devices, More).  Keep labels legible. */
@media (max-width: 900px) {
  .mobile-nav-item {
    padding: 6px 1px;
    min-width: 0;
  }
  .mobile-nav-item .mnav-label {
    font-size: 9px;
    line-height: 1.05;
    max-width: 100%;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    padding: 0 1px;
    box-sizing: border-box;
  }
  .mobile-nav-item .mnav-icon { font-size: 18px; }
  .mobile-nav-item.active .mnav-label { font-weight: 700; }
}
@media (max-width: 420px) {
  .mobile-nav-item .mnav-label { font-size: 8.5px; }
  .mobile-nav-item .mnav-icon  { font-size: 17px; }
}

/* -------------------------------------------------------------------------
   Mobile HMI layout — canvas fills the area, palette and properties are
   slide-in drawers.  This block overrides the older
   @media (max-width: 640px) 3-row grid.
   ------------------------------------------------------------------------- */
@media (max-width: 900px) {
  .io-hmi-wrap.mobile-hmi {
    display: block !important;
    position: relative !important;
    width: 100% !important;
    height: 100% !important;
    grid-template-columns: none !important;
    grid-template-rows: none !important;
    padding: 0 !important;
    overflow: hidden !important;
  }
  .io-hmi-wrap.mobile-hmi .io-hmi-canvas {
    width: 100% !important;
    height: 100% !important;
    border: 0 !important;
    grid-column: auto !important;
    grid-row: auto !important;
  }

  /* ---- Palette drawer (left) ---- */
  .io-hmi-wrap.mobile-hmi .io-hmi-palette {
    position: fixed !important;
    top: 0 !important;
    left: 0 !important;
    bottom: calc(64px + env(safe-area-inset-bottom, 0px)) !important;
    width: 88vw !important;
    max-width: 340px !important;
    min-width: 0 !important;
    z-index: 150 !important;
    background: var(--bg-1) !important;
    border-right: 1px solid var(--border-hi) !important;
    border-bottom: 0 !important;
    display: flex !important;
    flex-direction: column !important;
    padding: 0 !important;
    transform: translateX(-100%);
    transition: transform .22s ease, box-shadow .22s ease;
    box-shadow: none;
  }
  .io-hmi-wrap.mobile-hmi.mobile-palette-open .io-hmi-palette {
    transform: translateX(0);
    box-shadow: 6px 0 24px rgba(0,0,0,.55);
  }

  /* ---- Properties drawer (right) ---- */
  .io-hmi-wrap.mobile-hmi .io-hmi-side {
    position: fixed !important;
    top: 0 !important;
    right: 0 !important;
    bottom: calc(64px + env(safe-area-inset-bottom, 0px)) !important;
    left: auto !important;
    width: 90vw !important;
    max-width: 360px !important;
    min-width: 0 !important;
    z-index: 150 !important;
    background: var(--bg-1) !important;
    border-left: 1px solid var(--border-hi) !important;
    border-top: 0 !important;
    display: block !important;
    padding: 12px 14px 24px !important;
    overflow-y: auto !important;
    transform: translateX(100%);
    transition: transform .22s ease, box-shadow .22s ease;
    box-shadow: none;
  }
  .io-hmi-wrap.mobile-hmi.mobile-side-open .io-hmi-side {
    transform: translateX(0);
    box-shadow: -6px 0 24px rgba(0,0,0,.55);
  }

  /* Slightly larger touch targets inside the drawers */
  .io-hmi-wrap.mobile-hmi .io-hmi-pal-item {
    min-height: 42px;
    padding: 11px 12px;
    font-size: 13.5px;
  }
  .io-hmi-wrap.mobile-hmi .io-hmi-pal-group {
    font-size: 11px;
    padding: 10px 6px 4px;
  }
  .io-hmi-wrap.mobile-hmi .io-hmi-side-title {
    font-size: 13.5px;
    padding-bottom: 8px;
  }
  .io-hmi-wrap.mobile-hmi .io-hmi-field {
    margin-bottom: 10px;
  }
  .io-hmi-wrap.mobile-hmi .io-hmi-field > input,
  .io-hmi-wrap.mobile-hmi .io-hmi-field > select {
    min-height: 40px;
    font-size: 15px;
    padding: 8px 10px;
  }
}

/* Ensure the mobile nav sits above the drawers */
@media (max-width: 900px) {
  .mobile-nav { z-index: 180 !important; }
}

/* =========================================================================
   u_19_5 mobile + tab refinements
   ========================================================================= */

/* (Mobile-2) Edit OB drawer — match the Devices drawer exactly.
   The .rightbar on mobile is 92vw / max 380 px; the properties drawer
   must adopt the same outer frame, border and shadow so the two feel
   identical.  Inner padding is normalised so it does not fight the
   panel styling. */
@media (max-width: 900px) {
  .io-hmi-wrap.mobile-hmi .io-hmi-side {
    width: 92vw !important;
    max-width: 380px !important;
    min-width: 0 !important;
    padding: 0 !important;
    background: var(--bg-1) !important;
    border-left: 1px solid var(--border-hi) !important;
    box-shadow: none;
    transform: translateX(100%);
    transition: transform .22s ease, box-shadow .22s ease;
    overflow-y: auto !important;
    -webkit-overflow-scrolling: touch;
  }
  .io-hmi-wrap.mobile-hmi.mobile-side-open .io-hmi-side {
    transform: translateX(0);
    box-shadow: -6px 0 24px rgba(0,0,0,.55);
  }
  /* Give the drawer body the same padding rhythm as a .panel-body */
  .io-hmi-wrap.mobile-hmi .io-hmi-side > * {
    padding-left: 14px;
    padding-right: 14px;
  }
  .io-hmi-wrap.mobile-hmi .io-hmi-side-title {
    padding: 12px 14px 10px !important;
    margin: 0 !important;
    background: var(--bg-1);
    border-bottom: 1px solid var(--border);
    font-size: 13px;
    font-weight: 600;
  }

  /* (Mobile-3) The nav "Edit OB" button uses a monochrome text glyph.
     Force a consistent icon size across all mobile nav items so the emoji
     does not render at a different optical weight. */
  .mobile-nav-item .mnav-icon {
    font-size: 20px;
    line-height: 1;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-height: 22px;
  }

  /* (Tab-4) Resize handles must sit above any SVG content. */
  .io-hmi-obj .io-hmi-obj-resize {
    z-index: 120 !important;
  }

  /* (Tab-1) Buttons rendered as <div> so drag can start on them.
     Give them a pointer cursor to make the affordance obvious. */
  .io-hmi-obj > [data-part="btn"] { cursor: pointer; }
}

/* Desktop too — handles above SVG content in every viewport. */
.io-hmi-obj .io-hmi-obj-resize { z-index: 120 !important; }
.io-hmi-obj > [data-part="btn"] { cursor: pointer; }

/* =========================================================================
   u_19_6 — cross-device sync + mobile HMI fixes
   ========================================================================= */

/* (Mobile-2a) Open / Save — hide the text label on phones so only the
   emoji remains.  The label lives in a <span class="io-mode-text"> that
   the u_19_6 JS post-processor inserts. */
@media (max-width: 900px) {
  .io-modebar .io-mode-btn .io-mode-text {
    display: none !important;
  }
  .io-modebar .io-mode-btn {
    padding: 6px 8px !important;
    min-width: 0 !important;
  }
}

/* (Mobile-2b) Edit OB properties drawer — bulletproof full-height.
   Several declarations are given as fallbacks so this works even if
   env() or calc() is unsupported.  Only the last valid declaration is
   used by the browser. */
@media (max-width: 900px) {
  .io-hmi-wrap.mobile-hmi > .io-hmi-side,
  body .io-hmi-wrap.mobile-hmi > .io-hmi-side {
    position: fixed !important;
    top: 0 !important;
    right: 0 !important;
    left: auto !important;
    bottom: 64px !important;
    bottom: calc(64px + env(safe-area-inset-bottom, 0px)) !important;
    height: auto !important;
    min-height: 0 !important;
    max-height: none !important;
    width: 92vw !important;
    max-width: 380px !important;
    min-width: 0 !important;
    box-sizing: border-box !important;
    display: block !important;
    overflow-y: auto !important;
    overflow-x: hidden !important;
    -webkit-overflow-scrolling: touch;
    z-index: 150 !important;
    background: var(--bg-1) !important;
    border-left: 1px solid var(--border-hi) !important;
    padding: 0 !important;
    transform: translateX(100%);
    transition: transform .22s ease, box-shadow .22s ease;
  }
  .io-hmi-wrap.mobile-hmi.mobile-side-open > .io-hmi-side {
    transform: translateX(0) !important;
    box-shadow: -6px 0 24px rgba(0,0,0,.55);
  }

  /* Fill the drawer with a panel-style header + body rhythm so the
     content does not look "short" the way a bare list would. */
  .io-hmi-wrap.mobile-hmi .io-hmi-side-title {
    margin: 0 !important;
    padding: 12px 14px 12px !important;
    border-bottom: 1px solid var(--border);
    background: var(--bg-1);
    font-size: 13.5px;
    font-weight: 600;
    position: sticky;
    top: 0;
    z-index: 2;
  }
  .io-hmi-wrap.mobile-hmi .io-hmi-side > .io-hmi-tabs {
    padding: 0 8px !important;
    background: var(--bg-1);
    border-bottom: 1px solid var(--border);
    position: sticky;
    top: 48px;
    z-index: 2;
  }
  .io-hmi-wrap.mobile-hmi .io-hmi-side > .io-hmi-tab-content {
    padding: 12px 14px 24px !important;
  }

  /* Bigger touch-friendly inputs so the panel actually feels full */
  .io-hmi-wrap.mobile-hmi .io-hmi-field > input,
  .io-hmi-wrap.mobile-hmi .io-hmi-field > select,
  .io-hmi-wrap.mobile-hmi .io-hmi-field input[type="text"],
  .io-hmi-wrap.mobile-hmi .io-hmi-field input[type="number"] {
    min-height: 42px !important;
    font-size: 15px !important;
    padding: 9px 11px !important;
  }
  .io-hmi-wrap.mobile-hmi .io-hmi-field > label {
    font-size: 11.5px;
    margin-bottom: 4px;
  }
  .io-hmi-wrap.mobile-hmi .io-hmi-field { margin-bottom: 12px; }

  /* Colour rows: bigger swatches */
  .io-hmi-wrap.mobile-hmi .io-hmi-field.io-hmi-color-row > input[type="color"],
  .io-hmi-wrap.mobile-hmi .io-hmi-field [data-color-key] {
    min-width: 56px !important;
    min-height: 40px !important;
  }
}

/* =========================================================================
   u_19_6 — Cross-device "Loading from server…" overlay
   ========================================================================= */
.io-hmi-sync-overlay {
  position: absolute;
  inset: 0;
  display: flex; align-items: center; justify-content: center;
  background: rgba(0,0,0,.35);
  z-index: 90;
  pointer-events: none;
  font-family: var(--sans);
  font-size: 13px;
  color: var(--fg);
}
.io-hmi-sync-overlay span {
  padding: 8px 14px;
  background: var(--bg-1);
  border: 1px solid var(--border-hi);
  border-radius: 8px;
  box-shadow: 0 8px 24px rgba(0,0,0,.5);
}

/* =========================================================================
   u_19_7 — inline file picker (HMI .wlch + editor .wlc)
   ========================================================================= */
.inline-file-picker {
  min-width: 280px;
  max-width: 360px;
  max-height: 60vh;
  overflow-y: auto;
  padding: 6px;
  -webkit-overflow-scrolling: touch;
  animation: inlinePickerIn .12s ease;
}
@keyframes inlinePickerIn {
  from { opacity: 0; transform: translateY(-4px); }
}
.inline-file-picker .ifp-header {
  font-size: 10px;
  text-transform: uppercase;
  letter-spacing: .6px;
  color: var(--fg-mute);
  padding: 6px 10px 4px;
  font-weight: 700;
  border-bottom: 1px solid var(--border);
  margin-bottom: 4px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 6px;
}
.inline-file-picker .ifp-count {
  font-family: var(--mono);
  font-size: 10.5px;
  color: var(--fg-mute);
  text-transform: none;
  letter-spacing: 0;
  font-weight: 400;
}
.inline-file-picker .ifp-row {
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: 8px 10px;
  border-radius: 6px;
  cursor: pointer;
  transition: background .1s;
}
.inline-file-picker .ifp-row:hover { background: var(--bg-2); }
.inline-file-picker .ifp-row.current {
  background: color-mix(in oklab, var(--accent) 10%, transparent);
}
.inline-file-picker .ifp-row.current .ifp-name { color: var(--accent); }
.inline-file-picker .ifp-name-row {
  display: flex;
  align-items: baseline;
  gap: 6px;
}
.inline-file-picker .ifp-name {
  font-size: 13px;
  font-weight: 600;
  color: var(--fg);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  flex: 1 1 auto;
}
.inline-file-picker .ifp-current {
  font-size: 12px;
  font-weight: 700;
  color: var(--accent);
  flex: 0 0 auto;
}
.inline-file-picker .ifp-meta {
  font-size: 10.5px;
  color: var(--fg-mute);
  font-family: var(--mono);
  padding-left: 0;
}
.inline-file-picker .ifp-empty {
  padding: 16px 12px;
  text-align: center;
  color: var(--fg-mute);
  font-size: 12px;
  line-height: 1.5;
}
.inline-file-picker .ifp-actions {
  border-top: 1px solid var(--border);
  margin-top: 6px;
  padding-top: 4px;
}
@media (max-width: 900px) {
  .inline-file-picker { min-width: 260px; max-width: calc(100vw - 24px); }
  .inline-file-picker .ifp-row { padding: 12px 10px; min-height: 46px; }
  .inline-file-picker .ifp-name { font-size: 14px; }
}

/* =========================================================================
   u_19_9 — HMI manager button + mobile auto-fit polish
   ========================================================================= */

/* Small pulse while the HMI-file prefetch is in flight, so the Device
   Manager feels alive when a fresh login has to look up files. */
.mgr-card-actions .mgr-btn.hmi-btn-pending {
  opacity: .55;
}

/* On mobile the HMI canvas gets an extra frame of padding so the auto-fit
   result is visibly framed, not edge-to-edge. */
@media (max-width: 900px) {
  .io-hmi-wrap.mobile-hmi .io-hmi-canvas {
    padding: 0 !important;
  }
}

/* =========================================================================
   u_19_15b polish
   ========================================================================= */

/* The u_19_12 Close button label.  On mobile we keep only the emoji, so
   the button looks like the Open / Save buttons next to it. */
@media (max-width: 900px) {
  .io-modebar .io-mode-btn .io-mode-text {
    display: none !important;
  }
  .io-modebar .io-mode-btn {
    padding: 6px 8px !important;
    min-width: 0 !important;
  }
}
