/* this gets exported as style.css and can be used for the default theming */
/* these are the necessary styles for React/Svelte Flow, they get used by base.css and style.css */
.react-flow {
  direction: ltr;

  --xy-edge-stroke-default: #b1b1b7;
  --xy-edge-stroke-width-default: 1;
  --xy-edge-stroke-selected-default: #555;

  --xy-connectionline-stroke-default: #b1b1b7;
  --xy-connectionline-stroke-width-default: 1;

  --xy-attribution-background-color-default: rgba(255, 255, 255, 0.5);

  --xy-minimap-background-color-default: #fff;
  --xy-minimap-mask-background-color-default: rgba(240, 240, 240, 0.6);
  --xy-minimap-mask-stroke-color-default: transparent;
  --xy-minimap-mask-stroke-width-default: 1;
  --xy-minimap-node-background-color-default: #e2e2e2;
  --xy-minimap-node-stroke-color-default: transparent;
  --xy-minimap-node-stroke-width-default: 2;

  --xy-background-color-default: transparent;
  --xy-background-pattern-dots-color-default: #91919a;
  --xy-background-pattern-lines-color-default: #eee;
  --xy-background-pattern-cross-color-default: #e2e2e2;
  background-color: var(--xy-background-color, var(--xy-background-color-default));
  --xy-node-color-default: inherit;
  --xy-node-border-default: 1px solid #1a192b;
  --xy-node-background-color-default: #fff;
  --xy-node-group-background-color-default: rgba(240, 240, 240, 0.25);
  --xy-node-boxshadow-hover-default: 0 1px 4px 1px rgba(0, 0, 0, 0.08);
  --xy-node-boxshadow-selected-default: 0 0 0 0.5px #1a192b;
  --xy-node-border-radius-default: 3px;

  --xy-handle-background-color-default: #1a192b;
  --xy-handle-border-color-default: #fff;

  --xy-selection-background-color-default: rgba(0, 89, 220, 0.08);
  --xy-selection-border-default: 1px dotted rgba(0, 89, 220, 0.8);

  --xy-controls-button-background-color-default: #fefefe;
  --xy-controls-button-background-color-hover-default: #f4f4f4;
  --xy-controls-button-color-default: inherit;
  --xy-controls-button-color-hover-default: inherit;
  --xy-controls-button-border-color-default: #eee;
  --xy-controls-box-shadow-default: 0 0 2px 1px rgba(0, 0, 0, 0.08);

  --xy-edge-label-background-color-default: #ffffff;
  --xy-edge-label-color-default: inherit;
  --xy-resize-background-color-default: #3367d9;
}
.react-flow.dark {
  --xy-edge-stroke-default: #3e3e3e;
  --xy-edge-stroke-width-default: 1;
  --xy-edge-stroke-selected-default: #727272;

  --xy-connectionline-stroke-default: #b1b1b7;
  --xy-connectionline-stroke-width-default: 1;

  --xy-attribution-background-color-default: rgba(150, 150, 150, 0.25);

  --xy-minimap-background-color-default: #141414;
  --xy-minimap-mask-background-color-default: rgba(60, 60, 60, 0.6);
  --xy-minimap-mask-stroke-color-default: transparent;
  --xy-minimap-mask-stroke-width-default: 1;
  --xy-minimap-node-background-color-default: #2b2b2b;
  --xy-minimap-node-stroke-color-default: transparent;
  --xy-minimap-node-stroke-width-default: 2;

  --xy-background-color-default: #141414;
  --xy-background-pattern-dots-color-default: #555;
  --xy-background-pattern-lines-color-default: #333;
  --xy-background-pattern-cross-color-default: #333;
  --xy-node-color-default: #f8f8f8;
  --xy-node-border-default: 1px solid #3c3c3c;
  --xy-node-background-color-default: #1e1e1e;
  --xy-node-group-background-color-default: rgba(240, 240, 240, 0.25);
  --xy-node-boxshadow-hover-default: 0 1px 4px 1px rgba(255, 255, 255, 0.08);
  --xy-node-boxshadow-selected-default: 0 0 0 0.5px #999;

  --xy-handle-background-color-default: #bebebe;
  --xy-handle-border-color-default: #1e1e1e;

  --xy-selection-background-color-default: rgba(200, 200, 220, 0.08);
  --xy-selection-border-default: 1px dotted rgba(200, 200, 220, 0.8);

  --xy-controls-button-background-color-default: #2b2b2b;
  --xy-controls-button-background-color-hover-default: #3e3e3e;
  --xy-controls-button-color-default: #f8f8f8;
  --xy-controls-button-color-hover-default: #fff;
  --xy-controls-button-border-color-default: #5b5b5b;
  --xy-controls-box-shadow-default: 0 0 2px 1px rgba(0, 0, 0, 0.08);

  --xy-edge-label-background-color-default: #141414;
  --xy-edge-label-color-default: #f8f8f8;
}
.react-flow__background {
  background-color: var(--xy-background-color-props, var(--xy-background-color, var(--xy-background-color-default)));
  pointer-events: none;
  z-index: -1;
}
.react-flow__container {
  position: absolute;
  width: 100%;
  height: 100%;
  top: 0;
  left: 0;
}
.react-flow__pane {
  z-index: 1;
  touch-action: none;
}
.react-flow__pane.draggable {
    cursor: grab;
  }
.react-flow__pane.dragging {
    cursor: grabbing;
  }
.react-flow__pane.selection {
    cursor: pointer;
  }
.react-flow__viewport {
  transform-origin: 0 0;
  z-index: 2;
  pointer-events: none;
}
.react-flow__renderer {
  z-index: 4;
}
.react-flow__selection {
  z-index: 6;
}
.react-flow__nodesselection-rect:focus,
.react-flow__nodesselection-rect:focus-visible {
  outline: none;
}
.react-flow__edge-path {
  stroke: var(--xy-edge-stroke, var(--xy-edge-stroke-default));
  stroke-width: var(--xy-edge-stroke-width, var(--xy-edge-stroke-width-default));
  fill: none;
}
.react-flow__connection-path {
  stroke: var(--xy-connectionline-stroke, var(--xy-connectionline-stroke-default));
  stroke-width: var(--xy-connectionline-stroke-width, var(--xy-connectionline-stroke-width-default));
  fill: none;
}
.react-flow .react-flow__edges {
  position: absolute;
}
.react-flow .react-flow__edges svg {
    overflow: visible;
    position: absolute;
    pointer-events: none;
  }
.react-flow__edge {
  pointer-events: visibleStroke;
}
.react-flow__edge.selectable {
    cursor: pointer;
  }
.react-flow__edge.animated path {
    stroke-dasharray: 5;
    animation: dashdraw 0.5s linear infinite;
  }
.react-flow__edge.animated path.react-flow__edge-interaction {
    stroke-dasharray: none;
    animation: none;
  }
.react-flow__edge.inactive {
    pointer-events: none;
  }
.react-flow__edge.selected,
  .react-flow__edge:focus,
  .react-flow__edge:focus-visible {
    outline: none;
  }
.react-flow__edge.selected .react-flow__edge-path,
  .react-flow__edge.selectable:focus .react-flow__edge-path,
  .react-flow__edge.selectable:focus-visible .react-flow__edge-path {
    stroke: var(--xy-edge-stroke-selected, var(--xy-edge-stroke-selected-default));
  }
.react-flow__edge-textwrapper {
    pointer-events: all;
  }
.react-flow__edge .react-flow__edge-text {
    pointer-events: none;
    -webkit-user-select: none;
       -moz-user-select: none;
            user-select: none;
  }
/* Arrowhead marker styles - use CSS custom properties as default */
.react-flow__arrowhead polyline {
  stroke: var(--xy-edge-stroke, var(--xy-edge-stroke-default));
}
.react-flow__arrowhead polyline.arrowclosed {
  fill: var(--xy-edge-stroke, var(--xy-edge-stroke-default));
}
.react-flow__connection {
  pointer-events: none;
}
.react-flow__connection .animated {
    stroke-dasharray: 5;
    animation: dashdraw 0.5s linear infinite;
  }
svg.react-flow__connectionline {
  z-index: 1001;
  overflow: visible;
  position: absolute;
}
.react-flow__nodes {
  pointer-events: none;
  transform-origin: 0 0;
}
.react-flow__node {
  position: absolute;
  -webkit-user-select: none;
     -moz-user-select: none;
          user-select: none;
  pointer-events: all;
  transform-origin: 0 0;
  box-sizing: border-box;
  cursor: default;
}
.react-flow__node.selectable {
    cursor: pointer;
  }
.react-flow__node.draggable {
    cursor: grab;
    pointer-events: all;
  }
.react-flow__node.draggable.dragging {
      cursor: grabbing;
    }
.react-flow__nodesselection {
  z-index: 3;
  transform-origin: left top;
  pointer-events: none;
}
.react-flow__nodesselection-rect {
    position: absolute;
    pointer-events: all;
    cursor: grab;
  }
.react-flow__handle {
  position: absolute;
  pointer-events: none;
  min-width: 5px;
  min-height: 5px;
  width: 6px;
  height: 6px;
  background-color: var(--xy-handle-background-color, var(--xy-handle-background-color-default));
  border: 1px solid var(--xy-handle-border-color, var(--xy-handle-border-color-default));
  border-radius: 100%;
}
.react-flow__handle.connectingfrom {
    pointer-events: all;
  }
.react-flow__handle.connectionindicator {
    pointer-events: all;
    cursor: crosshair;
  }
.react-flow__handle-bottom {
    top: auto;
    left: 50%;
    bottom: 0;
    transform: translate(-50%, 50%);
  }
.react-flow__handle-top {
    top: 0;
    left: 50%;
    transform: translate(-50%, -50%);
  }
.react-flow__handle-left {
    top: 50%;
    left: 0;
    transform: translate(-50%, -50%);
  }
.react-flow__handle-right {
    top: 50%;
    right: 0;
    transform: translate(50%, -50%);
  }
.react-flow__edgeupdater {
  cursor: move;
  pointer-events: all;
}
.react-flow__pane.selection .react-flow__panel {
  pointer-events: none;
}
.react-flow__panel {
  position: absolute;
  z-index: 5;
  margin: 15px;
}
.react-flow__panel.top {
    top: 0;
  }
.react-flow__panel.bottom {
    bottom: 0;
  }
.react-flow__panel.top.center, .react-flow__panel.bottom.center {
      left: 50%;
      transform: translateX(-15px) translateX(-50%);
    }
.react-flow__panel.left {
    left: 0;
  }
.react-flow__panel.right {
    right: 0;
  }
.react-flow__panel.left.center, .react-flow__panel.right.center {
      top: 50%;
      transform: translateY(-15px) translateY(-50%);
    }
.react-flow__attribution {
  font-size: 10px;
  background: var(--xy-attribution-background-color, var(--xy-attribution-background-color-default));
  padding: 2px 3px;
  margin: 0;
}
.react-flow__attribution a {
    text-decoration: none;
    color: #999;
  }
@keyframes dashdraw {
  from {
    stroke-dashoffset: 10;
  }
}
.react-flow__edgelabel-renderer {
  position: absolute;
  width: 100%;
  height: 100%;
  pointer-events: none;
  -webkit-user-select: none;
     -moz-user-select: none;
          user-select: none;
  left: 0;
  top: 0;
}
.react-flow__viewport-portal {
  position: absolute;
  width: 100%;
  height: 100%;
  left: 0;
  top: 0;
  -webkit-user-select: none;
     -moz-user-select: none;
          user-select: none;
}
.react-flow__minimap {
  background: var(
    --xy-minimap-background-color-props,
    var(--xy-minimap-background-color, var(--xy-minimap-background-color-default))
  );
}
.react-flow__minimap-svg {
    display: block;
  }
.react-flow__minimap-mask {
    fill: var(
      --xy-minimap-mask-background-color-props,
      var(--xy-minimap-mask-background-color, var(--xy-minimap-mask-background-color-default))
    );
    stroke: var(
      --xy-minimap-mask-stroke-color-props,
      var(--xy-minimap-mask-stroke-color, var(--xy-minimap-mask-stroke-color-default))
    );
    stroke-width: var(
      --xy-minimap-mask-stroke-width-props,
      var(--xy-minimap-mask-stroke-width, var(--xy-minimap-mask-stroke-width-default))
    );
  }
.react-flow__minimap-node {
    fill: var(
      --xy-minimap-node-background-color-props,
      var(--xy-minimap-node-background-color, var(--xy-minimap-node-background-color-default))
    );
    stroke: var(
      --xy-minimap-node-stroke-color-props,
      var(--xy-minimap-node-stroke-color, var(--xy-minimap-node-stroke-color-default))
    );
    stroke-width: var(
      --xy-minimap-node-stroke-width-props,
      var(--xy-minimap-node-stroke-width, var(--xy-minimap-node-stroke-width-default))
    );
  }
.react-flow__background-pattern.dots {
    fill: var(
      --xy-background-pattern-color-props,
      var(--xy-background-pattern-color, var(--xy-background-pattern-dots-color-default))
    );
  }
.react-flow__background-pattern.lines {
    stroke: var(
      --xy-background-pattern-color-props,
      var(--xy-background-pattern-color, var(--xy-background-pattern-lines-color-default))
    );
  }
.react-flow__background-pattern.cross {
    stroke: var(
      --xy-background-pattern-color-props,
      var(--xy-background-pattern-color, var(--xy-background-pattern-cross-color-default))
    );
  }
.react-flow__controls {
  display: flex;
  flex-direction: column;
  box-shadow: var(--xy-controls-box-shadow, var(--xy-controls-box-shadow-default));
}
.react-flow__controls.horizontal {
    flex-direction: row;
  }
.react-flow__controls-button {
    display: flex;
    justify-content: center;
    align-items: center;
    height: 26px;
    width: 26px;
    padding: 4px;
    border: none;
    background: var(--xy-controls-button-background-color, var(--xy-controls-button-background-color-default));
    border-bottom: 1px solid
      var(
        --xy-controls-button-border-color-props,
        var(--xy-controls-button-border-color, var(--xy-controls-button-border-color-default))
      );
    color: var(
      --xy-controls-button-color-props,
      var(--xy-controls-button-color, var(--xy-controls-button-color-default))
    );
    cursor: pointer;
    -webkit-user-select: none;
       -moz-user-select: none;
            user-select: none;
  }
.react-flow__controls-button svg {
      width: 100%;
      max-width: 12px;
      max-height: 12px;
      fill: currentColor;
    }
.react-flow__edge.updating .react-flow__edge-path {
      stroke: #777;
    }
.react-flow__edge-text {
    font-size: 10px;
  }
.react-flow__node.selectable:focus,
  .react-flow__node.selectable:focus-visible {
    outline: none;
  }
.react-flow__node-input,
.react-flow__node-default,
.react-flow__node-output,
.react-flow__node-group {
  padding: 10px;
  border-radius: var(--xy-node-border-radius, var(--xy-node-border-radius-default));
  width: 150px;
  font-size: 12px;
  color: var(--xy-node-color, var(--xy-node-color-default));
  text-align: center;
  border: var(--xy-node-border, var(--xy-node-border-default));
  background-color: var(--xy-node-background-color, var(--xy-node-background-color-default));
}
.react-flow__node-input.selectable:hover, .react-flow__node-default.selectable:hover, .react-flow__node-output.selectable:hover, .react-flow__node-group.selectable:hover {
      box-shadow: var(--xy-node-boxshadow-hover, var(--xy-node-boxshadow-hover-default));
    }
.react-flow__node-input.selectable.selected,
    .react-flow__node-input.selectable:focus,
    .react-flow__node-input.selectable:focus-visible,
    .react-flow__node-default.selectable.selected,
    .react-flow__node-default.selectable:focus,
    .react-flow__node-default.selectable:focus-visible,
    .react-flow__node-output.selectable.selected,
    .react-flow__node-output.selectable:focus,
    .react-flow__node-output.selectable:focus-visible,
    .react-flow__node-group.selectable.selected,
    .react-flow__node-group.selectable:focus,
    .react-flow__node-group.selectable:focus-visible {
      box-shadow: var(--xy-node-boxshadow-selected, var(--xy-node-boxshadow-selected-default));
    }
.react-flow__node-group {
  background-color: var(--xy-node-group-background-color, var(--xy-node-group-background-color-default));
}
.react-flow__nodesselection-rect,
.react-flow__selection {
  background: var(--xy-selection-background-color, var(--xy-selection-background-color-default));
  border: var(--xy-selection-border, var(--xy-selection-border-default));
}
.react-flow__nodesselection-rect:focus,
  .react-flow__nodesselection-rect:focus-visible,
  .react-flow__selection:focus,
  .react-flow__selection:focus-visible {
    outline: none;
  }
.react-flow__controls-button:hover {
      background: var(
        --xy-controls-button-background-color-hover-props,
        var(--xy-controls-button-background-color-hover, var(--xy-controls-button-background-color-hover-default))
      );
      color: var(
        --xy-controls-button-color-hover-props,
        var(--xy-controls-button-color-hover, var(--xy-controls-button-color-hover-default))
      );
    }
.react-flow__controls-button:disabled {
      pointer-events: none;
    }
.react-flow__controls-button:disabled svg {
        fill-opacity: 0.4;
      }
.react-flow__controls-button:last-child {
    border-bottom: none;
  }
.react-flow__controls.horizontal .react-flow__controls-button {
    border-bottom: none;
    border-right: 1px solid
      var(
        --xy-controls-button-border-color-props,
        var(--xy-controls-button-border-color, var(--xy-controls-button-border-color-default))
      );
  }
.react-flow__controls.horizontal .react-flow__controls-button:last-child {
    border-right: none;
  }
.react-flow__resize-control {
  position: absolute;
}
.react-flow__resize-control.left,
.react-flow__resize-control.right {
  cursor: ew-resize;
}
.react-flow__resize-control.top,
.react-flow__resize-control.bottom {
  cursor: ns-resize;
}
.react-flow__resize-control.top.left,
.react-flow__resize-control.bottom.right {
  cursor: nwse-resize;
}
.react-flow__resize-control.bottom.left,
.react-flow__resize-control.top.right {
  cursor: nesw-resize;
}
/* handle styles */
.react-flow__resize-control.handle {
  width: 5px;
  height: 5px;
  border: 1px solid #fff;
  border-radius: 1px;
  background-color: var(--xy-resize-background-color, var(--xy-resize-background-color-default));
  translate: -50% -50%;
}
.react-flow__resize-control.handle.left {
  left: 0;
  top: 50%;
}
.react-flow__resize-control.handle.right {
  left: 100%;
  top: 50%;
}
.react-flow__resize-control.handle.top {
  left: 50%;
  top: 0;
}
.react-flow__resize-control.handle.bottom {
  left: 50%;
  top: 100%;
}
.react-flow__resize-control.handle.top.left {
  left: 0;
}
.react-flow__resize-control.handle.bottom.left {
  left: 0;
}
.react-flow__resize-control.handle.top.right {
  left: 100%;
}
.react-flow__resize-control.handle.bottom.right {
  left: 100%;
}
/* line styles */
.react-flow__resize-control.line {
  border-color: var(--xy-resize-background-color, var(--xy-resize-background-color-default));
  border-width: 0;
  border-style: solid;
}
.react-flow__resize-control.line.left,
.react-flow__resize-control.line.right {
  width: 1px;
  transform: translate(-50%, 0);
  top: 0;
  height: 100%;
}
.react-flow__resize-control.line.left {
  left: 0;
  border-left-width: 1px;
}
.react-flow__resize-control.line.right {
  left: 100%;
  border-right-width: 1px;
}
.react-flow__resize-control.line.top,
.react-flow__resize-control.line.bottom {
  height: 1px;
  transform: translate(0, -50%);
  left: 0;
  width: 100%;
}
.react-flow__resize-control.line.top {
  top: 0;
  border-top-width: 1px;
}
.react-flow__resize-control.line.bottom {
  border-bottom-width: 1px;
  top: 100%;
}
.react-flow__edge-textbg {
  fill: var(--xy-edge-label-background-color, var(--xy-edge-label-background-color-default));
}
.react-flow__edge-text {
  fill: var(--xy-edge-label-color, var(--xy-edge-label-color-default));
}
/* Handles, matching the official app: the hit area is a large transparent box
   over the row; the visible mark is a short HORIZONTAL line pointing inward,
   drawn by ::after. The mark is invisible until the pointer is near the handle
   (handle hover / while connecting), NOT on node hover or selection. */
.react-flow__handle {
  background: transparent !important;
  border: none !important;
  width: 40px !important;
  height: 30px !important;
  transition: none;
}

.react-flow__handle::after {
  content: '';
  position: absolute;
  top: 50%;
  width: 8px;
  height: 3px;
  border-radius: 2px;
  background: #495057;
  transform: translateY(-50%);
  opacity: 0;
  transition: opacity 0.15s ease-in-out;
  pointer-events: none;
}

/* Left-side handles: the line points inward (to the right). */
.react-flow__handle-left::after {
  left: 12px;
}

/* Right-side handles: the line points inward (to the left). */
.react-flow__handle-right::after {
  right: 12px;
}

/* Top-side handles: the mark is VERTICAL and points inward (downwards). */
.react-flow__handle-top::after {
  left: 50%;
  top: 12px;
  width: 3px;
  height: 8px;
  transform: translateX(-50%);
}

/* Bottom-side handles: the mark is VERTICAL and points inward (upwards). */
.react-flow__handle-bottom::after {
  left: 50%;
  bottom: 12px;
  width: 3px;
  height: 8px;
  transform: translateX(-50%);
}

.react-flow__handle:hover::after,
.react-flow__handle.connectionindicator:hover::after,
.react-flow__handle.connectionindicator.connecting::after,
.react-flow__handle.connectionindicator.valid::after {
  opacity: 1;
}

/* Inline components (diode/resistor) are only 30x30. Match the official: the
   hit area is a WIDE transparent box overlapping the card (mark drawn OUTSIDE
   the card by the shared ::after rule), while the glyph is raised above the
   handles so the centre still drags. Do NOT narrow it, or the mark ends up
   inside the card and the port becomes unreachable. */
.react-flow__handle.inline-handle {
  width: 45px !important;
  height: 30px !important;
}

/* Splice ports sit at the node centre: keep a small square so the raised dot and
   the surrounding card remain draggable. */
.react-flow__handle.splice-handle {
  width: 50px !important;
  height: 30px !important;
}

.react-flow__handle.splice-handle::after {
  display: none;
}

/* Pass-through conductors (cable cores / twisted wires) are connectable rows:
   dragging from one sets that conductor's own endpoint. Keep the hit area
   narrow (the node is only 60 px wide) so the card stays draggable, and show
   the same hover mark as any other handle. */
.react-flow__handle.passthrough-handle {
  width: 20px !important;
  height: 30px !important;
}

/* Mate handle: invisible hit area on the header side. At rest it shows no mark;
   while connecting (or on the active/valid connection) it draws a double-arrow
   mark, which is where the mate's arrow-tip read comes from. */
.react-flow__handle.mate-handle {
  background: transparent !important;
  border: none !important;
  width: 40px !important;
  height: 30px !important;
}

.react-flow__handle.mate-handle::after {
  content: '';
  position: absolute;
  top: 50%;
  width: 12px;
  height: 12px;
  background: #868e96;
  opacity: 0;
  transition: opacity 0.15s ease-in-out;
  pointer-events: none;
  /* Left-pointing triangle by default (left side of the header). */
  clip-path: polygon(100% 0, 0 50%, 100% 100%);
}

/* Right-side mate handle: arrow points outward (to the right). */
.react-flow__handle.mate-handle.react-flow__handle-right::after {
  right: 6px;
  left: auto;
  transform: translateY(-50%);
  clip-path: polygon(0 0, 100% 50%, 0 100%);
}

.react-flow__handle.mate-handle.react-flow__handle-left::after {
  left: 6px;
  right: auto;
  transform: translateY(-50%);
  clip-path: polygon(100% 0, 0 50%, 100% 100%);
}

/* Top/bottom mate handles (rotated nodes): vertical arrows. */
.react-flow__handle.mate-handle.react-flow__handle-top::after {
  left: 50%;
  top: 6px;
  bottom: auto;
  transform: translateX(-50%);
  clip-path: polygon(0 100%, 50% 0, 100% 100%);
}

.react-flow__handle.mate-handle.react-flow__handle-bottom::after {
  left: 50%;
  bottom: 6px;
  top: auto;
  transform: translateX(-50%);
  clip-path: polygon(0 0, 50% 100%, 100% 0);
}

.react-flow__handle.mate-handle:hover::after,
.react-flow__handle.mate-handle.connectionindicator:hover::after,
.react-flow__handle.mate-handle.connectionindicator.connecting::after,
.react-flow__handle.mate-handle.connectionindicator.valid::after {
  opacity: 1;
}

/* An existing mate: its header side keeps the arrow marker visible for good. */
.react-flow__handle.mate-handle.mate-on::after {
  opacity: 1;
}

/* Layout connectors/terminals are only 30×30. The two user handles (`Bundle`
   on the body face, `LayoutMate` on the tab face) are small boxes centred on
   the node edge — big enough to grab, small enough to keep the node draggable.
   No inward mark: the glyph/stub already reads as the connection. */
.react-flow__handle.layout-handle {
  width: 14px !important;
  height: 14px !important;
  background: transparent !important;
  border: none !important;
  border-radius: 4px;
}

.react-flow__handle.layout-handle::after {
  display: none;
}

/* Edge animations */
.react-flow__edge-path {
  transition: stroke-width 0.2s;
}

.react-flow__edge:hover .react-flow__edge-path {
  stroke-width: 4;
}

/* Nodes draw their own card/border; remove React Flow's default wrapper chrome
   (otherwise transparent nodes like groups show a second outline). */
.react-flow__node {
  background: transparent;
  border: none;
  border-radius: 0;
  padding: 0;
  transition: box-shadow 0.2s;
}

.react-flow__node:hover {
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
}

/* Selected entity: blue ring, matching the official selection chrome. */
.react-flow__node.selected {
  box-shadow: 0 0 0 2px #228be6;
  border-radius: 8px;
}

.react-flow__node.selected:hover {
  box-shadow: 0 0 0 2px #228be6, 0 4px 12px rgba(0, 0, 0, 0.15);
}

/* Connector cavity rows: clickable sub-entity with a selection highlight. */
.cavity-row:hover {
  background: #f8f9fa;
}

.cavity-row.selected {
  background: #e7f5ff;
}

.cavity-grip {
  position: absolute;
  right: 5px;
  top: 50%;
  width: 6px;
  height: 6px;
  transform: translateY(-50%) rotate(45deg);
  background: #ced4da;
  opacity: 0;
  transition: opacity 0.15s;
}

.react-flow__node:hover .cavity-grip,
.cavity-row.selected .cavity-grip {
  opacity: 0.9;
}

/* Wire/bundle waypoint (the faint Tabler "+"): draggable on the grid. Raise its
   visibility on hover/selection so it is easy to grab, keeping the official's
   0.1 resting opacity. */
.react-flow__node.layout-point {
  cursor: grab;
}

.react-flow__node.layout-point.dragging,
.react-flow__node.layout-point:active {
  cursor: grabbing;
}

.react-flow__node.layout-point:hover svg,
.react-flow__node.layout-point.selected svg {
  opacity: 0.75 !important;
}

/* Selected-net conductor overlay (ConductorOverlay): one continuous path per
   conductor across its whole route, drawn in the viewport portal above the
   bundles and default nodes (the official 'internal edge' layer) but below
   elevated/selected nodes. */
.react-flow__viewport-portal {
  z-index: 4;
}

/* Connector Node */
.connector-node {
  background: white;
  border: 1px solid #e5e7eb;
  border-radius: 8px;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08);
  min-width: 120px;
}

.connector-header {
  background: #f4f5f7;
  padding: 8px 12px;
  border-radius: 8px 8px 0 0;
  display: flex;
  justify-content: space-between;
  align-items: center;
  border-bottom: 1px solid #e5e7eb;
}

.connector-label {
  font-size: 12.5px;
  font-weight: 700;
  color: #1f2937;
}

.connector-icon {
  color: #6b7280;
  font-size: 14px;
}

.connector-body {
  padding: 4px 0;
}

.cavity-row {
  display: flex;
  align-items: center;
  padding: 6px 12px;
  border-bottom: 1px solid #f1f2f4;
  position: relative;
  height: 30px;
}

.cavity-row:last-child {
  border-bottom: none;
}

.cavity-number {
  font-size: 11px;
  color: #9ca3af;
  width: 20px;
}

.cavity-signal {
  font-size: 12.5px;
  color: #1f2937;
  flex: 1;
}

.shell-row {
  background: #f9fafb;
}

.shell-icon {
  font-size: 14px;
  color: #6b7280;
  width: 20px;
  text-align: center;
}

/* Terminal Node */
.terminal-node {
  display: flex;
  align-items: center;
  position: relative;
}

.terminal-body {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 12px;
  background: white;
  border: 1px solid #e5e7eb;
  border-radius: 15px;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08);
}

.terminal-stub {
  width: 16px;
  height: 16px;
  background: #3f4653;
  border-radius: 3px;
}

.terminal-ring {
  width: 14px;
  height: 14px;
  border: 5px solid #c3c9d1;
  border-radius: 50%;
  background: white;
}

.terminal-label {
  font-size: 13px;
  font-weight: 700;
  color: #1f2937;
}

/* Branch Point Node */
.branch-point-node {
  width: 24px;
  height: 24px;
  position: relative;
}

.branch-point-body {
  width: 100%;
  height: 100%;
  background: #aab2bd;
  border-radius: 50%;
  border: 1.5px solid #8f98a3;
}

/* Inline Nodes */
.inline-node {
  display: flex;
  align-items: center;
  position: relative;
}

.splice-node .splice-dot {
  width: 12px;
  height: 12px;
  border-radius: 50%;
  border: 1px solid #1f2937;
}

.diode-node .diode-symbol {
  font-size: 16px;
  color: #ff8a00;
  padding: 4px;
}

.resistor-node .resistor-symbol {
  width: 14px;
  height: 10px;
  border: 2px solid #e5484d;
  border-radius: 2px;
}

/* Bundle Edge Labels */
.bundle-label {
  background: white;
  padding: 2px 6px;
  border-radius: 4px;
  font-size: 12px;
  font-weight: 600;
  color: #2b3038;
  white-space: nowrap;
}

.bundle-badge {
  background: white;
  padding: 2px 6px;
  border-radius: 4px;
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
}

/* Position counter (add/remove cavities / cores / wires) */
.position-counter {
  position: absolute;
  top: -42px;
  left: 50%;
  transform: translateX(-50%);
  display: flex;
  align-items: stretch;
  z-index: 1000;
}

/* Rotated node: the counter moves to the LEFT edge, vertically centred, and turns
   −90° (reads bottom-to-top) so it mirrors the part badge on the right. The
   translateX(-50% - 20px) pushes its rotated (28 px wide) box just clear of the
   node's left edge. */
.position-counter--rotated {
  top: 50%;
  left: 0;
  transform: translateY(-50%) translateX(calc(-50% - 20px)) rotate(-90deg);
}

.position-counter__btn {
  width: 28px;
  height: 28px;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  background: #ffffff;
  border: 1px solid #ced4da;
  color: #000000;
  cursor: pointer;
}

.position-counter__btn:first-child {
  border-radius: 8px 0 0 8px;
}

.position-counter__btn:last-child {
  border-radius: 0 8px 8px 0;
}

.position-counter__btn:hover:not(:disabled) {
  background: #f1f3f5;
}

.position-counter__btn:disabled {
  opacity: 0.45;
  cursor: default;
}

.position-counter__input {
  width: 40px;
  height: 28px;
  box-sizing: border-box;
  padding: 0;
  text-align: center;
  background: #ffffff;
  border: 1px solid #ced4da;
  border-left: none;
  border-right: none;
  color: #000000;
  font: 600 14px Inter, sans-serif;
  outline: none;
}

.position-counter__input:focus {
  border-color: #adb5bd;
}

/* React Flow overrides */
.react-flow__node {
  padding: 0;
}

.react-flow__edge-path {
  fill: none;
}

.react-flow__handle {
  width: 8px;
  height: 8px;
  background: #3f4653;
  border: 2px solid white;
  border-radius: 50%;
}

.react-flow__handle:hover {
  background: #2b8cff;
}

/* Part badges ("Show parts" overlay). Rendered outside the node box as an
   absolutely-positioned slot so the measured node size never changes. */
.part-badge-slot {
  position: absolute;
  top: 100%;
  left: 50%;
  transform: translateX(-50%);
  margin-top: 4px;
  display: flex;
  justify-content: center;
  z-index: 6;
  pointer-events: none;
}

/* Inline components (splice): pull the badge ~30% closer to the node centre. */
.part-badge-slot--tight {
  top: 72%;
}

/* Rotated node: the badge moves to the RIGHT edge, vertically centred, and turns
   −90° so it reads bottom-to-top. The badge is rotated about its top-left corner
   and shifted back by half its own width, which keeps its rotated (18 px wide)
   box flush against the node edge regardless of the label length. */
.part-badge-slot--rotated {
  top: 50%;
  left: 100%;
  transform: none;
  margin: 0 0 0 6px;
  justify-content: flex-start;
}

.part-badge-slot--rotated .part-badge {
  transform-origin: 0 0;
  transform: rotate(-90deg) translateX(-50%);
}

.part-badge {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  height: 18px;
  max-width: 170px;
  box-sizing: border-box;
  padding: 0 6px;
  background: #ffffff;
  border: 1px solid #e9ecef;
  border-radius: 9px;
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.08);
  font: 600 11px/1 Inter, sans-serif;
  color: #212529;
  white-space: nowrap;
}

/* Clickable badge (assigned) / placeholder (unassigned): opens the editor. */
.part-badge--button {
  pointer-events: auto;
  cursor: pointer;
}

.part-badge--button:hover {
  border-color: #ced4da;
  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.16);
}

.part-badge__label {
  overflow: hidden;
  text-overflow: ellipsis;
}

.part-badge--empty {
  color: #adb5bd;
}

/* Contact badges sit inline at the end of a cavity row. */
.part-badge--row {
  flex: 0 0 auto;
  margin-left: 6px;
}

/* Wire ident-label chips (`identLabel`). Mirrors the official layout: a small
   dark chip anchored at each wire end, vertically centred on the run. */
.ident-chip {
  position: absolute;
  left: 0;
  top: 0;
  display: flex;
  gap: 1px;
  pointer-events: auto;
  cursor: text;
  z-index: 6;
  font: 600 7.5px/1 Inter, sans-serif;
  font-variant-numeric: tabular-nums;
}

.ident-chip__label,
.ident-chip__cell {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  height: 9px;
  box-sizing: border-box;
  white-space: nowrap;
}

.ident-chip__label {
  padding: 0 3px;
  border-radius: 1px;
}

.ident-chip__cell {
  width: 7px;
  border-radius: 2px;
}

.ident-chip-editor {
  position: absolute;
  left: 0;
  top: 0;
  pointer-events: auto;
  z-index: 7;
}

.ident-chip__input {
  width: 56px;
  height: 14px;
  box-sizing: border-box;
  padding: 0 2px;
  font: 600 9px/1 Inter, sans-serif;
  background: #ffffff;
  color: #212529;
  border: 1px solid #4dabf7;
  border-radius: 2px;
  outline: none;
}

/* Bundle length label editor (Layout). */
.bundle-length-input {
  height: 16px;
  box-sizing: border-box;
  padding: 0 3px;
  font: 400 12px/1 Inter, sans-serif;
  background: #ffffff;
  color: #212529;
  border: 1px solid #4dabf7;
  border-radius: 2px;
  outline: none;
}

/* Ident field in the wire context menu. */
.wire-ident-input {
  width: 100%;
  box-sizing: border-box;
  height: 26px;
  padding: 0 8px;
  font: 600 13px Inter, sans-serif;
  color: #212529;
  background: #ffffff;
  border: 1px solid #ced4da;
  border-radius: 4px;
  outline: none;
}

.wire-ident-input:focus {
  border-color: #4dabf7;
}

/* Context menu & submenu hover feedback */
.harness-context-menu button:hover:not(:disabled) {
  background-color: #f1f3f5 !important;
}

.harness-context-menu button[aria-pressed="true"]:hover:not(:disabled) {
  background-color: #d0ebff !important;
}

/* Part editor popover (opened from a badge / placeholder). */
.part-editor {
  position: fixed;
  z-index: 3000;
  width: 260px;
  box-sizing: border-box;
  padding: 10px;
  background: #ffffff;
  border: 1px solid #dee2e6;
  border-radius: 8px;
  box-shadow: 0 8px 28px rgba(0, 0, 0, 0.2);
  font-size: 13px;
  color: #212529;
}

.part-editor__header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  margin-bottom: 8px;
  font-weight: 600;
}

.part-editor__field {
  display: flex;
  flex-direction: column;
  gap: 4px;
  margin-bottom: 8px;
}

.part-editor__field input,
.part-editor__field select {
  padding: 6px 8px;
  border: 1px solid #ced4da;
  border-radius: 4px;
  font: inherit;
}

.part-editor__row {
  display: flex;
  gap: 6px;
  margin-top: 4px;
}

.part-editor__btn {
  flex: 1;
  padding: 6px 10px;
  background: #ffffff;
  border: 1px solid #ced4da;
  border-radius: 4px;
  cursor: pointer;
  font: inherit;
  font-weight: 600;
}

.part-editor__btn--primary {
  background: #2b6fd9;
  border-color: #2b6fd9;
  color: #ffffff;
}

.part-editor__btn--danger {
  color: #e03131;
}

.part-editor__list {
  max-height: 150px;
  margin-top: 10px;
  padding-top: 6px;
  border-top: 1px solid #f1f3f5;
  overflow: auto;
}

.part-editor__item {
  display: block;
  width: 100%;
  padding: 5px 6px;
  background: none;
  border: none;
  border-radius: 4px;
  text-align: left;
  cursor: pointer;
  font: inherit;
}

.part-editor__item:hover {
  background: #f1f3f5;
}

.part-editor__hint {
  color: #868e96;
  font-size: 11px;
}

/* Bundle covering type abbreviation badge */
.covering-type-badge {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  transition: all 0.15s ease-in-out;
}

.covering-type-badge:hover {
  background: #e7f5ff !important;
  border-color: #339af0 !important;
  color: #1971c2 !important;
  box-shadow: 0 2px 5px rgba(34, 139, 230, 0.25) !important;
  transform: translateY(-1px);
}

/* "Show destinations" (D): speech-bubble badges next to a connector row /
   terminal, with a searchable picker. Rendered outside the node box so the
   measured node size never changes. */
.destination-list {
  position: absolute;
  top: calc(50% - 15px);
  left: 100%;
  right: auto;
  display: flex;
  flex-direction: row-reverse;
  align-items: center;
  gap: 0;
  width: fit-content;
  padding: 0 10px;
  z-index: 8;
  pointer-events: none;
}

.destination-list--left {
  left: auto;
  right: 100%;
  flex-direction: row;
}

.destination-bubble {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  height: 26px;
  width: max-content;
  min-width: 70px;
  max-width: 260px;
  box-sizing: border-box;
  padding: 0 8px;
  background: #ffffff;
  border: 1px solid #ced4da;
  border-radius: 4px;
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.06);
  pointer-events: auto;
  font: 500 12px/1 Inter, system-ui, sans-serif;
  color: #212529;
}

/* Chevron notch on the node side, matching the official speech bubble. */
.destination-bubble--chevron::before {
  content: '';
  position: absolute;
  top: 50%;
  left: -6px;
  width: 0;
  height: 0;
  border-top: 6px solid transparent;
  border-bottom: 6px solid transparent;
  border-right: 6px solid #ced4da;
  transform: translateY(-50%);
}

.destination-bubble--left.destination-bubble--chevron::before {
  left: auto;
  right: -6px;
  border-right: none;
  border-left: 6px solid #ced4da;
}

.destination-bubble__swatch {
  flex: 0 0 auto;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.15);
}

.destination-bubble__kind {
  display: inline-flex;
  align-items: center;
  color: #868e96;
}

.destination-picker {
  position: relative;
  flex: 1 1 auto;
  min-width: 0;
}

.destination-picker__input {
  width: 100%;
  min-width: 48px;
  height: 24px;
  box-sizing: border-box;
  padding: 0;
  border: none;
  outline: none;
  background: transparent;
  font: inherit;
  color: #212529;
  /* Size the field to its content (the current destination label) so the bubble
     is exactly as wide as the text, never clipping it. */
  field-sizing: content;
}

.destination-picker__input::placeholder {
  color: #adb5bd;
}

.destination-picker__menu {
  position: absolute;
  top: 28px;
  left: 0;
  z-index: 40;
  width: max-content;
  min-width: 180px;
  max-width: 320px;
  max-height: 400px;
  overflow: auto;
  padding: 4px;
  background: #ffffff;
  border: 1px solid #dee2e6;
  border-radius: 8px;
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.16);
}

/* Portaled dropdown: lives on <body>, so it escapes the badge stacking context
   (and any node clipping) and is never covered by a sibling row's badge. */
.destination-picker__menu--portal {
  z-index: 5000;
  max-width: min(360px, 90vw);
}

.destination-picker__option {
  display: block;
  width: 100%;
  padding: 6px 8px;
  background: none;
  border: none;
  border-radius: 4px;
  text-align: left;
  cursor: pointer;
  font: 500 12px/1.2 Inter, system-ui, sans-serif;
  color: #212529;
  white-space: nowrap;
}

.destination-picker__option:hover {
  background: #f1f3f5;
}

.destination-picker__empty {
  padding: 6px 8px;
  font-size: 12px;
  color: #adb5bd;
}

/* Layout "Show destinations" movable floating window. */
.layout-dest-window {
  position: absolute;
  z-index: 30;
  overflow: visible;
  filter: drop-shadow(0 6px 18px rgba(0, 0, 0, 0.18));
}

.layout-dest-window__handle {
  height: 12px;
  border-radius: 8px 8px 0 0;
  background: #e9ecef;
  border: 1px solid #ced4da;
  border-bottom: none;
  cursor: move;
  display: flex;
  align-items: center;
  justify-content: center;
}

.layout-dest-window__grip {
  width: 34px;
  height: 3px;
  border-radius: 2px;
  background: #adb5bd;
}

/* Print / PDF Export Styling */
@media print {
  @page {
    size: landscape;
    margin: 10mm;
  }

  body, html {
    background: #ffffff !important;
    margin: 0 !important;
    padding: 0 !important;
    -webkit-print-color-adjust: exact !important;
    print-color-adjust: exact !important;
  }

  .harness-topbar,
  .harness-split-toolbar,
  .harness-context-menu,
  .harness-modal-backdrop,
  .react-flow__panel,
  .react-flow__controls,
  .react-flow__attribution {
    display: none !important;
  }

  .harness-viewer-container {
    width: 100vw !important;
    height: 100vh !important;
    overflow: visible !important;
  }
}

/* Quotation View Header & Responsive layout */
.harness-quotation-view {
  container-type: inline-size;
}

.quotation-header {
  display: flex;
  align-items: center;
  justify-content: flex-start;
  padding: 8px 16px;
  padding-right: 185px;
  background: #ffffff;
  border-bottom: 1px solid #dee2e6;
  min-height: 46px;
  box-sizing: border-box;
  gap: 12px;
  flex-wrap: wrap;
  row-gap: 8px;
}

.quotation-title-row {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-shrink: 0;
}

.quotation-controls-row {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
}

@container (max-width: 900px) {
  .quotation-header {
    padding-right: 16px;
  }
  .quotation-title-row {
    width: 100%;
    padding-right: 180px;
    box-sizing: border-box;
  }
}

@media (max-width: 1024px) {
  .quotation-header {
    padding-right: 16px;
  }
  .quotation-title-row {
    width: 100%;
    padding-right: 180px;
    box-sizing: border-box;
  }
}


/* Documents pane: page navigation over the canvas (multi-page PDFs). */
.doc-page-edge {
  position: absolute;
  top: 0;
  bottom: 0;
  width: 56px;
  z-index: 5;
  display: flex;
  align-items: center;
  justify-content: center;
  border: none;
  background: transparent;
  color: #ffffff;
  cursor: pointer;
  opacity: 0.35;
  transition: opacity 0.15s ease, background 0.15s ease;
}
.doc-page-edge:not(:disabled):hover {
  opacity: 1;
}
.doc-page-edge:disabled {
  cursor: default;
  opacity: 0.08;
}
.doc-page-edge--prev {
  left: 0;
  background: linear-gradient(to right, rgba(0, 0, 0, 0.4), transparent);
}
.doc-page-edge--next {
  right: 0;
  background: linear-gradient(to left, rgba(0, 0, 0, 0.4), transparent);
}
