/* Generous invisible hit areas, restrained visible ports. Scoped to the audio patch. */
#graphViewport .port {
  width: 44px;
  height: 44px;
  margin: 0;
  padding: 0;
  top: 56%;
  border: 0;
  background: transparent;
  box-shadow: none;
  transform: translateY(-50%) scale(var(--patch-port-scale, 1));
  transform-origin: center;
  touch-action: none;
  -webkit-tap-highlight-color: transparent;
}
#graphViewport .port.in { left: -22px; }
#graphViewport .port.out { right: -22px; }
#graphViewport .port::before {
  content: '';
  position: absolute;
  width: 12px;
  height: 12px;
  left: 16px;
  top: 16px;
  border: 1.5px solid var(--node-color);
  border-radius: 50%;
  background: #141811;
  transition: box-shadow .16s ease, background .16s ease;
}
#graphViewport .port.out::before { background: var(--node-color); }
#graphViewport .port:hover::before,
#graphViewport .port:focus-visible::before,
#graphViewport .port.pending::before { box-shadow: 0 0 0 8px #d6e8bd18; }
#graphViewport .node { transition: border-color .16s ease, box-shadow .16s ease, opacity .16s ease; }
#graphViewport .node.patch-connect-target {
  border-color: #c8ddb2;
  box-shadow: 0 0 0 4px #c8ddb211, 0 0 24px #bacc9d16;
  cursor: crosshair;
}
#graphViewport .patch-connect-target .node-header { cursor: crosshair; }
#graphViewport .patch-connect-target .port.in::before { box-shadow: 0 0 0 8px #d6e8bd1c; }
#graphViewport .node.patch-connect-near {
  border-color: #edf7dc;
  box-shadow: 0 0 0 6px #deedbf2b, 0 0 36px #bacc9d24;
}
#graphViewport .patch-connect-near .port.in::before { background: #edf7dc; box-shadow: 0 0 0 9px #d6e8bd30; }
#graphViewport .node.patch-connect-unavailable { opacity: .35; }
#graphViewport .node.patch-connect-source { border-color: var(--node-color); }
.patch-cable-preview { position: absolute; inset: 0; width: 100%; height: 100%; z-index: 8; pointer-events: none; opacity: 0; overflow: hidden; }
.patch-cable-preview.visible { opacity: .8; }
.patch-cable-preview path { fill: none; stroke: #d6e8bd; stroke-width: 1.5; stroke-linecap: round; stroke-dasharray: 5 5; }
.patch-cable-preview.snapped path { stroke: #edf7dc; stroke-width: 2; stroke-dasharray: none; }
.patch-connect-cancel { position: absolute; z-index: 9; top: 19px; right: 20px; min-width: 68px; min-height: 44px; padding: 10px 13px; font-size: 11px; letter-spacing: .04em; background: #171d14ed; border-color: #687b56; backdrop-filter: blur(12px); }
.patch-connecting .canvas-annotation > span:last-child { color: #a8b696; }
@media (prefers-reduced-motion: reduce) {
  #graphViewport .port::before, #graphViewport .node { transition: none; }
}

/* All node actions remain available without a hidden hold gesture. */
.node-actions { display: flex; flex-wrap: wrap; gap: 10px; }
.node-actions button { min-height: 44px; padding: 10px 18px; }
