:root{
  --board: #0A0A0A;
  --board2: #141414;
  --board3: #1C1C1C;
  --sunken: #000000;
  --ink: #F5F5F0;
  --ink-soft: #9A9A94;
  --ink-faint: #5C5C58;
  --line: #262626;
  --line-strong: #3A3A3A;
  --led-off: #2A2A2A;
  --led-on: #FF4136;
  --led-glow: rgba(255,65,54,.5);
  --font: 'Space Mono', ui-monospace, 'SFMono-Regular', monospace;
  --radius: 3px;
}

*{box-sizing:border-box;}
html,body{height:100%;}
body{
  margin:0;
  font-family: var(--font);
  font-size: 12px;
  background: var(--board);
  color: var(--ink);
  overflow:hidden;
}

#toolbar{
  display:flex; align-items:center; justify-content:space-between;
  gap:12px; padding:8px 14px; background:var(--board);
  border-bottom:1px solid var(--line-strong);
  height:44px;
}
.brand{display:flex; align-items:center; gap:8px;}
.brand-dot{width:9px;height:9px;border-radius:50%;background:var(--led-on); box-shadow:0 0 8px var(--led-glow);}
.brand-name{font-weight:700; letter-spacing:.08em; text-transform:uppercase; font-size:12px;}
.brand-sub{color:var(--ink-faint); font-size:10.5px; letter-spacing:.02em;}

.toolbar-actions{display:flex; align-items:center; gap:8px;}
.sep{width:1px;height:20px;background:var(--line-strong);}
.mini-label{color:var(--ink-faint); font-size:10.5px; display:flex; align-items:center; gap:4px; text-transform:uppercase; letter-spacing:.04em;}
.mini-label input{width:40px; background:var(--sunken); border:1px solid var(--line-strong); color:var(--ink); border-radius:3px; padding:3px 4px; font-family:var(--font);}
.mini-label input[type="range"]{
  -webkit-appearance:none; appearance:none; width:90px; height:20px; padding:0; background:transparent; border:none;
}
.mini-label input[type="range"]::-webkit-slider-runnable-track{height:4px; background:var(--line-strong); border-radius:2px;}
.mini-label input[type="range"]::-webkit-slider-thumb{
  -webkit-appearance:none; width:14px; height:14px; margin-top:-5px; border-radius:50%;
  background:var(--led-on); border:2px solid var(--board); cursor:grab;
}
.mini-label input[type="range"]::-moz-range-track{height:4px; background:var(--line-strong); border-radius:2px;}
.mini-label input[type="range"]::-moz-range-thumb{width:12px; height:12px; border-radius:50%; background:var(--led-on); border:2px solid var(--board); cursor:grab;}

.btn{
  font-family:var(--font); font-weight:700; letter-spacing:.03em; text-transform:uppercase;
  background:var(--board3); color:var(--ink); border:1px solid var(--line-strong);
  border-radius:3px; padding:6px 12px; cursor:pointer; font-size:11px;
}
.btn:hover{border-color:var(--ink-faint);}
.btn:active{transform:translateY(1px);}
.btn:disabled{opacity:.35; cursor:default; transform:none;}
.btn-primary{background:var(--board3);}
.btn-accent{background:var(--led-on); border-color:var(--led-on); color:#1a0503;}
.btn-danger{color:var(--led-on); border-color:var(--led-on); background:transparent;}
.btn-icon{background:transparent; border:none; color:var(--ink-faint); font-size:16px; cursor:pointer;}

#workspace{position:relative; height:calc(100% - 44px); display:flex;}

#canvas-viewport{
  position:relative; flex:1; overflow:auto; background:
    radial-gradient(circle at 1px 1px, #1c1c1c 1px, transparent 1px) 0 0/22px 22px, var(--board);
}
#canvas-inner{position:relative; width:4200px; height:2600px; transform-origin:0 0;}
#wires-svg{position:absolute; left:0; top:0; width:100%; height:100%; pointer-events:none; overflow:visible; z-index:5;}
#wires-svg path{pointer-events:stroke; cursor:pointer;}
#nodes-layer{position:absolute; left:0; top:0; width:100%; height:100%; z-index:1;}

#grid-overlay{
  position:fixed; z-index:50;
  background:rgba(0,0,0,.7);
  display:grid;
}
#grid-overlay[hidden]{display:none;}
.grid-cell{
  border:1px dashed var(--line-strong);
  display:flex; align-items:center; justify-content:center;
  color:var(--ink-faint); font-size:15px; font-family:var(--font); cursor:pointer;
}
.grid-cell:hover{background:rgba(255,65,54,.12); color:var(--ink); border-color:var(--led-on);}
.grid-hint{
  position:absolute; top:10px; left:50%; transform:translateX(-50%);
  background:var(--board3); border:1px solid var(--line-strong); padding:6px 12px; border-radius:3px;
  font-size:11px; color:var(--ink-soft); z-index:2; font-family:var(--font);
}

/* ---------------- Module (node) ---------------- */
.module{
  position:absolute; width:172px; background:var(--board2);
  border:1px solid var(--line-strong); border-radius:var(--radius);
  box-shadow:0 4px 16px rgba(0,0,0,.6);
  user-select:none; padding:9px;
}
.module::before{
  content:''; position:absolute; top:0; left:13px; right:13px; height:2px;
  background:var(--acc);
}
.module.selected{outline:2px dashed var(--ink); outline-offset:2px;}
.module.bypassed{opacity:.55;}

.mhead{display:flex; align-items:center; justify-content:space-between; padding-top:3px; cursor:grab; position:relative;}
.mhead:active{cursor:grabbing;}
.mhead-left{display:flex; align-items:center; gap:3px; min-width:0;}
.mname{min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; font-family:var(--font); font-weight:700; font-size:11px; letter-spacing:.01em; text-transform:uppercase; color:var(--acc);}
.mdel{background:none; border:none; color:var(--ink-faint); opacity:.7; cursor:pointer; font-size:13px; line-height:1; font-family:var(--font);}
.mdel:hover{opacity:1; color:var(--ink);}
.scopewrap{margin-top:7px; border:1px solid var(--line-strong); border-radius:3px; overflow:hidden; background:#000;}
.scopewrap canvas{display:block; width:100%; height:56px;}
.mvideo-canvas{width:100%; height:auto; display:block; margin-top:2px; background:#000; border-radius:3px;}
.mvideo-actions{display:flex; justify-content:flex-end; width:100%; margin-top:5px;}
.mvideo-fullscreen{font-size:8.5px; padding:3px 6px;}
.mtag{
  display:block; font-size:8.5px; color:var(--ink-faint); letter-spacing:.05em; text-transform:uppercase;
  margin:3px 0 7px; padding-bottom:6px; border-bottom:1px solid var(--line); font-family:var(--font);
}

.jackgroups{display:flex; justify-content:space-between; padding-bottom:7px;}
.jackcol{display:flex; flex-direction:column; gap:4px; min-width:0;}
.jackcol.out{align-items:flex-end;}
.jack{display:flex; align-items:center; gap:5px; padding-block:2px; font-size:8.5px; letter-spacing:.02em; text-transform:uppercase; color:var(--ink-faint); font-family:var(--font); cursor:crosshair;}
.jack.out{flex-direction:row-reverse;}
.nub{width:11px; height:11px; border-radius:50%; flex:none; border:2px solid var(--acc); cursor:crosshair; background:var(--sunken);}
.jack.out .nub{background:var(--acc);}
.jack.cv .nub{border-style:dashed;}
.nub:hover{box-shadow:0 0 0 3px rgba(245,245,240,.15);}
/* While dragging a new wire, the closest 'in' jack within snap range lights
   up — the wire will land here if the mouse is released right now, so you
   don't need to hit the 11px dot itself. */
.nub.jack-target{background:var(--ink); box-shadow:0 0 0 5px rgba(245,245,240,.4); border-color:var(--ink);}

.mbody{
  display:flex; flex-wrap:wrap; gap:8px 6px; align-items:flex-start;
  padding-top:7px; border-top:1px dashed var(--line);
}
/* Wide nodes (NYX): grouped knob sections laid out in two columns. */
.module.wide{width:392px;}
.module.compact.wide{width:270px;}
.module.wide .mbody{display:grid; grid-template-columns:1fr 1fr; gap:10px 14px; align-items:start;}
.module.wide .mgrp:last-child{grid-column:1 / -1;}
.mgrp{display:flex; flex-wrap:wrap; gap:6px 6px; align-items:flex-start; min-width:0;}
.mgroup{flex-basis:100%; font-family:var(--font); font-size:8px; letter-spacing:.09em; text-transform:uppercase; color:var(--ink-faint); border-bottom:1px solid var(--line); padding-bottom:2px;}
.module.wide .selectfield{flex:1 1 70px; min-width:70px;}
.module.wide .jackgroups{align-items:flex-start;}
.module.wide .jackcol.in{flex-direction:row; flex-wrap:wrap; gap:4px 14px; flex:1;}

/* Rotary knob */
.knobwrap{display:flex; flex-direction:column; align-items:center; gap:2px; width:36px;}
.knob{
  width:30px; height:30px; border-radius:50%; position:relative; cursor:grab;
  background:conic-gradient(from -135deg,
    var(--acc) calc(var(--t,0)*270deg),
    var(--line-strong) calc(var(--t,0)*270deg) 270deg,
    transparent 270deg 360deg);
}
.knob:active{cursor:grabbing;}
.knob::after{content:''; position:absolute; inset:5px; border-radius:50%; background:var(--sunken);}
.knob .ind{position:absolute; left:50%; top:3px; width:2px; height:8px; background:var(--acc); transform-origin:50% 12px; margin-left:-1px; border-radius:1px; z-index:1;}
.klabel{font-size:7.5px; letter-spacing:.02em; text-transform:uppercase; color:var(--ink-faint); font-family:var(--font); white-space:nowrap;}
.kval{font-size:8px; color:var(--ink-soft); font-family:var(--font); font-variant-numeric:tabular-nums;}

/* Toggle switch */
.switchwrap{display:flex; flex-direction:column; align-items:center; gap:3px; width:34px;}
.fswitch{width:20px; height:20px; border-radius:50%; border:2px solid var(--line-strong); background:var(--sunken); cursor:pointer; display:flex; align-items:center; justify-content:center; flex:none;}
.fswitch .led{width:6px; height:6px; border-radius:50%; background:var(--led-off);}
.fswitch.engaged{border-color:var(--acc);}
.fswitch.engaged .led{background:var(--acc); box-shadow:0 0 4px 0 var(--led-glow);}

/* Live taping: Record / Play-loop buttons beside the bypass switch. Built on
   .fswitch so they share its size and compact scaling; glyphs are pure CSS. */
.loopbtn{width:16px; height:16px; padding:0; border-width:1.5px;}
.loopbtn .glyph{display:block;}
.loopbtn.rec .glyph{width:6px; height:6px; border-radius:50%; background:#7a2a26;}
.loopbtn.rec:hover .glyph{background:#c8382f;}
.loopbtn.rec.engaged{border-color:#FF4136; animation:recpulse 1s ease-in-out infinite;}
.loopbtn.rec.engaged .glyph{background:#FF4136; box-shadow:0 0 5px 1px rgba(255,65,54,.7);}
.loopbtn.play .glyph{width:0; height:0; margin-left:2px; border-style:solid; border-width:3.5px 0 3.5px 6px; border-color:transparent transparent transparent var(--ink-soft);}
.loopbtn.play:hover .glyph{border-left-color:var(--ink);}
.loopbtn.play.engaged .glyph{border-left-color:var(--acc);}
.loopbtn.play.empty{opacity:.4;}
.loopbtn.clr .glyph{width:8px; height:8px; position:relative;}
.loopbtn.clr .glyph::before,.loopbtn.clr .glyph::after{content:''; position:absolute; left:0; right:0; top:3.25px; height:1.5px; background:var(--ink-soft);}
.loopbtn.clr .glyph::before{transform:rotate(45deg);}
.loopbtn.clr .glyph::after{transform:rotate(-45deg);}
.loopbtn.clr:hover .glyph::before,.loopbtn.clr:hover .glyph::after{background:#c8382f;}
.loopbtn.clr.empty{opacity:.4;}
@keyframes recpulse{50%{box-shadow:0 0 6px 1px rgba(255,65,54,.6);}}
.loopbar{position:absolute; left:0; right:0; bottom:-4px; height:2px; background:transparent; pointer-events:none;}
.loopbar.trimmable{background:var(--line-strong);}
.loopwin{position:absolute; top:0; bottom:0; left:0; width:100%;}
.loopbar.trimmable .loopwin{background:var(--ink-soft); opacity:.55;}
.loopwin i{display:block; height:100%; width:0;}
.loopbar.recording i{background:#FF4136;}
.loopbar.playing i{background:var(--acc);}
.loopbar.playing .loopwin{opacity:1;}
/* Trim handles: centred on the window's ends; a wider invisible hit area (::before) keeps them easy to grab. */
.loophandle{display:none; position:absolute; top:-5px; width:5px; height:12px; margin-left:-2.5px; border-radius:2px; background:var(--acc); cursor:ew-resize; pointer-events:auto; touch-action:none;}
.loophandle::before{content:''; position:absolute; inset:-3px -6px;}
.loopbar.trimmable .loophandle{display:block;}
.loophandle.start{left:var(--ts);}
.loophandle.end{left:var(--te);}
.loophandle:hover,.loophandle.dragging{box-shadow:0 0 4px 1px var(--led-glow);}
@keyframes loopfill{from{width:0;} to{width:100%;}}

/* Select field */
.selectfield{flex-basis:100%;}
.mselect{
  font-family:var(--font); font-size:9.5px; padding:4px 5px; border:1px solid var(--line-strong);
  border-radius:3px; background:var(--sunken); color:var(--ink); width:100%;
}

.mtest{margin-top:2px; font-size:9px; padding:3px 6px; align-self:flex-start;}

/* Compact mode: every node shrinks to its tightest layout. Scoped to the
   `.compact` class on the module itself (set directly by renderNode() in
   canvas.js, which also skips creating the scope canvas at all rather than
   just hiding it) — not a body-level ancestor class, so there's no cascade
   path for this to silently miss. Two exceptions, both unconditional: Video
   Output's own canvas is untouched (it's the node's actual output, not
   incidental monitoring, and it can't go fullscreen while display:none),
   and Output always gets its scope regardless of Compact (it's the master
   signal). Null is always compact itself — it has nothing on it that
   compacting would hide. Controls otherwise stay just big enough to grab
   with a mouse; everything that's pure whitespace or secondary text goes. */
.module.compact{width:132px; padding:6px;}
.module.compact .mtag{display:none;}
.module.compact .mhead{padding-top:1px;}
.module.compact .jackgroups{padding-bottom:4px;}
.module.compact .jackcol{gap:3px;}
.module.compact .jack{font-size:7.5px; gap:3px;}
.module.compact .nub{width:9px; height:9px; border-width:1.5px;}
.module.compact .mbody{padding-top:4px; gap:5px 4px;}
.module.compact .knobwrap{width:28px; gap:1px;}
.module.compact .knob{width:22px; height:22px;}
.module.compact .knob::after{inset:4px;}
.module.compact .knob .ind{top:2px; height:6px;}
.module.compact .klabel{font-size:6.5px;}
.module.compact .kval{font-size:7px;}
.module.compact .switchwrap{width:26px; gap:2px;}
.module.compact .fswitch{width:16px; height:16px; border-width:1.5px;}
.module.compact .fswitch .led{width:5px; height:5px;}
.module.compact .loopbtn{width:13px; height:13px; border-width:1.5px;}
.module.compact .loopbtn.rec .glyph{width:4px; height:4px;}
.module.compact .loopbtn.play .glyph{margin-left:1px; border-width:2.5px 0 2.5px 4px;}
.module.compact .loopbtn.clr .glyph{width:6px; height:6px;}
.module.compact .loopbtn.clr .glyph::before,.module.compact .loopbtn.clr .glyph::after{top:2.25px;}
.module.compact .mhead-left{gap:3px;}
.module.compact .mselect{font-size:8.5px; padding:3px 4px;}
.module.compact .mvideo-actions{margin-top:3px;}
/* Output's scope is forced on even when its own card is compacted (see
   renderNode()) — give it a shorter trace to match the tighter card. */
.module.compact .scopewrap canvas{height:40px;}

/* Node menu */
#node-menu{
  width:260px; background:var(--board2); border-left:1px solid var(--line-strong);
  display:flex; flex-direction:column;
}
#node-menu[hidden]{display:none;}
.menu-head{display:flex; align-items:center; gap:6px; padding:8px; border-bottom:1px solid var(--line-strong);}
.menu-head input{flex:1; background:var(--sunken); border:1px solid var(--line-strong); color:var(--ink); border-radius:3px; padding:6px 8px; font-family:var(--font);}
.menu-list{overflow:auto; padding:6px;}
.menu-section{margin-bottom:8px;}
.menu-section-title{font-size:9.5px; text-transform:uppercase; letter-spacing:.1em; color:var(--ink-faint); padding:6px 4px 4px; font-family:var(--font); border-top:1px solid var(--line-strong);}
.menu-item{
  display:flex; align-items:center; gap:8px; padding:7px 8px; border-radius:3px; cursor:pointer;
}
.menu-item:hover{background:var(--board3);}
.menu-item-dot{width:9px;height:9px;border-radius:50%; flex:none;}
.menu-item-name{font-weight:700; font-family:var(--font); font-size:11.5px; text-transform:uppercase; letter-spacing:.02em;}
.menu-item-desc{color:var(--ink-faint); font-size:10px; margin-left:auto; text-align:right; font-family:var(--font);}

#toast-stack{position:fixed; right:14px; bottom:14px; display:flex; flex-direction:column; gap:6px; z-index:200;}
.toast{background:var(--board3); border:1px solid var(--line-strong); padding:8px 12px; border-radius:3px; font-size:11px; max-width:280px; box-shadow:0 4px 14px rgba(0,0,0,.5); font-family:var(--font);}
.toast.error{border-color:var(--led-on); color:#ff9c96;}

::-webkit-scrollbar{width:10px; height:10px;}
::-webkit-scrollbar-thumb{background:var(--line-strong); border-radius:6px;}
::-webkit-scrollbar-track{background:transparent;}
