/* Library styles for react-networks */

:root {
  /* Presentation corners: panels, cards, labels and device/rack frames.
     Circular indicators/handles and physical connector/cable shapes keep
     their own geometry. */
  --rn-ui-radius: 1px;
}

/* Edge zIndex styles for dynamic prominence */
.edge-prominent {
  z-index: 1000 !important;
  opacity: 1 !important;
}

.edge-dimmed {
  z-index: 500 !important;
  opacity: 0.3 !important;
}

/* Dynamic zIndex classes */
.edge-z-1000 {
  z-index: 1000 !important;
}

.edge-z-500 {
  z-index: 500 !important;
}

/* React Flow theming */
.react-flow-dark,
.react-flow-light {
  --xy-node-border-radius: var(--rn-ui-radius, 1px);
}

.react-flow-dark {
  --rn-flow-background: #1a1a1a;
  --rn-flow-text: #ffffff;
  --rn-flow-border: #404040;
  --rn-flow-controls-bg: #2d2d2d;
  --rn-flow-controls-border: #404040;
  --rn-flow-minimap-bg: #2d2d2d;
  --rn-flow-minimap-border: #404040;

  /* Containable-only bay markers (outline + label). */
  --rn-bay-border: #6b7280;
  --rn-bay-bg: rgba(148, 163, 184, 0.12);
  --rn-bay-text: #e5e7eb;
  --rn-bay-occupied-border: #10b981;
  --rn-bay-failed-border: #ef4444;
  --rn-bay-failed-bg: rgba(239, 68, 68, 0.24);
  --rn-bay-predicted-border: #f59e0b;
  --rn-bay-highlight: #f59e0b;
  --rn-focus-ring: #60a5fa;

  /* --- Design tokens (dark) --------------------------------------------
     Values here reproduce the pre-token dark rendering exactly. Keep this
     list in sync with the light block and with the prefers-color-scheme
     block at the end of this file. */
  --rn-surface: #1f2937;
  --rn-surface-raised: #374151;
  --rn-surface-sunken: #111827;
  --rn-border: #4b5563;
  --rn-border-strong: #6b7280;
  --rn-border-subtle: #374151;
  --rn-text: #e5e7eb;
  --rn-text-muted: #9ca3af;
  --rn-text-strong: #ffffff;
  --rn-text-on-accent: #1a1a1a;
  --rn-accent: #3b82f6;
  --rn-accent-selected: #3b82f6;
  --rn-selection-ring: #3b82f6;
  --rn-status-ok: #10b981;
  --rn-status-ok-border: #059669;
  --rn-status-warn: #f59e0b;
  --rn-status-error: #ef4444;
  --rn-status-unknown: #6b7280;
  --rn-rack-body: #1f2937;
  --rn-rack-rail: #374151;
  --rn-rack-accent: #fbbf24;
  --rn-device-body: #1f2937;
  --rn-device-label: #ffffff;
  --rn-pdu-body: #1a1a1a;
  --rn-pdu-chassis-highlight: #4a5568;
  --rn-pdu-chassis-mid: #2d3748;
  --rn-pdu-chassis-shadow: #1a202c;
  --rn-pdu-outlet: #ffffff;
  --rn-pdu-outlet-border: #6b7280;
  --rn-pdu-header-text: #e2e8f0;
  /* Distribution boards: still a face lighter than a rack body, but slate
     rather than a near-white slab on a dark canvas. */
  --rn-board-face: #475569;
  --rn-board-text: #f1f5f9;
  --rn-board-nameplate: #1e293b;
  --rn-board-nameplate-text: #f1f5f9;
  --rn-board-badge-bg: #e2e8f0;
  --rn-board-badge-text: #1e293b;
  --rn-board-muted: #cbd5e1;
  --rn-board-way-face: #334155;
  --rn-board-way-open-face: #2a3546;
  --rn-board-way-tripped-face: #4c1d24;
  --rn-board-way-border: #64748b;
  --rn-board-way-open-border: #475569;
  --rn-board-lever: #e2e8f0;
}

.react-flow-light {
  --rn-flow-background: #f5f5f5;
  --rn-flow-text: #1a1a1a;
  --rn-flow-border: #e9ecef;
  --rn-flow-controls-bg: #f8f9fa;
  --rn-flow-controls-border: #e9ecef;
  --rn-flow-minimap-bg: #f8f9fa;
  --rn-flow-minimap-border: #e9ecef;

  /* Containable-only bay markers (outline + label). */
  --rn-bay-border: #94a3b8;
  --rn-bay-bg: rgba(100, 116, 139, 0.1);
  --rn-bay-text: #1f2937;
  --rn-bay-occupied-border: #059669;
  --rn-bay-failed-border: #dc2626;
  --rn-bay-failed-bg: rgba(220, 38, 38, 0.16);
  --rn-bay-predicted-border: #d97706;
  --rn-bay-highlight: #d97706;
  --rn-focus-ring: #1d4ed8;

  /* --- Design tokens (light) -------------------------------------------
     Light surfaces so rack/PDU/tray/fibre node bodies stop rendering as
     dark slabs on a light canvas. Keep in sync with the dark block. */
  --rn-surface: #ffffff;
  --rn-surface-raised: #f3f4f6;
  --rn-surface-sunken: #e5e7eb;
  --rn-border: #d1d5db;
  --rn-border-strong: #9ca3af;
  --rn-border-subtle: #e5e7eb;
  --rn-text: #1f2937;
  --rn-text-muted: #6b7280;
  --rn-text-strong: #111827;
  --rn-text-on-accent: #1a1a1a;
  --rn-accent: #2563eb;
  --rn-accent-selected: #2563eb;
  --rn-selection-ring: #2563eb;
  --rn-status-ok: #059669;
  --rn-status-ok-border: #047857;
  --rn-status-warn: #d97706;
  --rn-status-error: #dc2626;
  --rn-status-unknown: #6b7280;
  --rn-rack-body: #e5e7eb;
  --rn-rack-rail: #e5e7eb;
  --rn-rack-accent: #b45309;
  --rn-device-body: #f9fafb;
  --rn-device-label: #1f2937;
  --rn-pdu-body: #e5e7eb;
  --rn-pdu-chassis-highlight: #f3f4f6;
  --rn-pdu-chassis-mid: #e5e7eb;
  --rn-pdu-chassis-shadow: #d1d5db;
  --rn-pdu-outlet: #ffffff;
  --rn-pdu-outlet-border: #9ca3af;
  --rn-pdu-header-text: #1f2937;
  /* Distribution boards: a flat light face, darker nameplate. */
  --rn-board-face: #eef1f5;
  --rn-board-text: #0f172a;
  --rn-board-nameplate: #334155;
  --rn-board-nameplate-text: #f1f5f9;
  --rn-board-badge-bg: #f1f5f9;
  --rn-board-badge-text: #334155;
  --rn-board-muted: #94a3b8;
  --rn-board-way-face: #ffffff;
  --rn-board-way-open-face: #f1f5f9;
  --rn-board-way-tripped-face: #fef2f2;
  --rn-board-way-border: #cbd5e1;
  --rn-board-way-open-border: #d5dce5;
  --rn-board-lever: #334155;
}

/* Keyboard focus ring for the library's custom interactive controls. */
.react-flow__handle[role="button"]:focus-visible,
.device-node__bay--clickable:focus-visible,
.react-flow__node[data-type="splice"]:focus-visible,
.rn-node-button:focus-visible,
.react-networks-attribution-link:focus-visible {
  outline: 2px solid var(--rn-focus-ring, #1d4ed8);
  outline-offset: 1px;
}

/* Apply ReactFlow theming */
.react-flow-dark .react-flow__background {
  background-color: var(--rn-flow-background);
}

.react-flow-light .react-flow__background {
  background-color: var(--rn-flow-background);
}

/* Ensure canvas background is always off-white in light mode */
.react-flow-light .react-flow__viewport {
  background-color: #f5f5f5 !important;
}

.react-flow-light .react-flow {
  background-color: #f5f5f5;
}

.react-flow-dark .react-flow__controls {
  background-color: var(--rn-flow-controls-bg);
  border-color: var(--rn-flow-controls-border);
}

.react-flow-light .react-flow__controls {
  background-color: var(--rn-flow-controls-bg);
  border-color: var(--rn-flow-controls-border);
}

.react-flow-dark .react-flow__minimap {
  background-color: var(--rn-flow-minimap-bg);
  border-color: var(--rn-flow-minimap-border);
}

.react-flow-light .react-flow__minimap {
  background-color: var(--rn-flow-minimap-bg);
  border-color: var(--rn-flow-minimap-border);
}

.react-flow-dark .react-flow__controls-button {
  background-color: var(--rn-flow-controls-bg);
  color: var(--rn-flow-text);
  border-color: var(--rn-flow-controls-border);
}

.react-flow-light .react-flow__controls-button {
  background-color: var(--rn-flow-controls-bg);
  color: var(--rn-flow-text);
  border-color: var(--rn-flow-controls-border);
}

.react-flow-dark .react-flow__controls-button:hover {
  background-color: #4b5563;
}

.react-flow-light .react-flow__controls-button:hover {
  background-color: #e9ecef;
}

/* Mobile-friendly control buttons - larger touch targets */
@media (max-width: 768px) {
  .react-flow__controls-button {
    width: 44px !important;
    height: 44px !important;
    min-width: 44px !important;
    min-height: 44px !important;
  }
}

/* Override React Flow default handle styles for tube fiber handles */
/* Use CSS variables set by inline styles to override React Flow defaults */
.react-flow__handle.tube-fiber-handle {
  border: none !important;
  transform: none !important;
  background-clip: padding-box !important;
  opacity: 1 !important;
  /* Ensure no default React Flow styles interfere */
  box-shadow: none !important;
  /* Don't set background here - let inline styles or specific rules handle it */
}

/* Tube fiber handles - use fiber color */
.react-flow__handle.tube-fiber-handle {
  background: var(--rn-fibre-bg-image, var(--rn-fibre-bg)) !important;
  background-color: var(--rn-fibre-bg) !important;
}

/* Fibre flow map handles */
.react-flow__handle.fibre-flow-handle {
  border: none !important;
  transform: none !important;
  background-clip: padding-box !important;
  opacity: 1 !important;
  box-shadow: none !important;
}

.react-flow__handle.fibre-flow-handle {
  background: var(--rn-fibre-bg-image, var(--rn-fibre-bg)) !important;
  background-color: var(--rn-fibre-bg) !important;
  background-image: var(--rn-fibre-bg-image, none) !important;
}

.react-flow__handle.rn-port-hitbox {
  overflow: visible;
}

.react-flow__handle.connectionindicator.rn-port-hitbox::before {
  content: '';
  position: absolute;
  top: calc(-1 * var(--rn-hit-expand-top, 0px));
  right: calc(-1 * var(--rn-hit-expand-right, 0px));
  bottom: calc(-1 * var(--rn-hit-expand-bottom, 0px));
  left: calc(-1 * var(--rn-hit-expand-left, 0px));
  border-radius: 4px;
  background: transparent;
  pointer-events: auto;
}

.react-flow__handle.rn-port-handle--clickable {
  cursor: pointer;
}

.react-flow__handle.rn-port-handle--highlighted {
  box-shadow: 0 0 0 2px var(--rn-status-warn, #f59e0b), 0 0 8px rgba(245, 158, 11, 0.75);
  z-index: 12;
}

/* Containable-only bay markers. Outlines + labels only — bays never mount a
   React Flow handle. Colours flow through the --rn-bay-* vars (theme-scoped),
   with fallbacks so bays still render outside the flow theme (e.g. isolated
   tests). Highlight/failed treatment mirrors the port highlight above. */
.device-node__bay-layer {
  inset: 0;
  pointer-events: none;
  position: absolute;
  /* MUST stay below the port handles. Port handles carry a positive z-index
     (2, highlighted 12 — see getBaseHandleStyle), so this layer at z-index 0
     paints below them and they win pointer events wherever a clickable bay
     overlaps a port. z-index 0 (not auto) is deliberate: it establishes a
     stacking context that CONFINES the highlighted-bay z-index (below) to this
     layer, so a highlighted bay cannot escape above the handles. The guarantee
     is this z-index ordering, not DOM order. */
  z-index: 0;
}

.device-node__bay {
  align-items: center;
  background: var(--rn-bay-bg, rgba(148, 163, 184, 0.08));
  border: 1.5px solid var(--rn-bay-border, rgba(107, 114, 128, 0.9));
  border-radius: 1px;
  box-sizing: border-box;
  color: var(--rn-bay-text, #e5e7eb);
  display: flex;
  justify-content: center;
  overflow: hidden;
}

.device-node__bay--occupied {
  border-color: var(--rn-bay-occupied-border, #10b981);
  background: var(--rn-bay-occupied-bg, rgba(16, 185, 129, 0.1));
}

.device-node__bay--clickable {
  cursor: pointer;
}

.device-node__bay--predicted {
  border-color: var(--rn-bay-predicted-border, #f59e0b);
  border-style: dashed;
  background: var(--rn-bay-predicted-bg, rgba(245, 158, 11, 0.08));
}

.device-node__bay--failed {
  background: var(--rn-bay-failed-bg, rgba(239, 68, 68, 0.12));
  border-color: var(--rn-bay-failed-border, #ef4444);
}

.device-node__bay--highlighted {
  border-color: var(--rn-bay-highlight, #f59e0b);
  box-shadow: 0 0 0 1px var(--rn-bay-highlight, #f59e0b),
    0 0 6px rgba(245, 158, 11, 0.7);
  z-index: 3;
}

.device-node__bay-label {
  display: block;
  /* Micro tier: raised from 6px, but held below the 9px label floor by the bay
     geometry. A bay rect is clamped to MIN_BAY_SIZE_PX (3px) and defaults to
     DEFAULT_BAY_HEIGHT_PX (12px), and a 1U frame is only U_HEIGHT_PX (20px)
     tall, so a two-row bay layout in 1U leaves ~7px per row. With line-height 1
     the label's line box is exactly its font-size, so 7px is the largest size
     that still fits that row; anything taller is clipped by the bay's own
     `overflow: hidden`. Bays smaller than the line box clip at any size — that
     is pre-existing and unchanged. Hidden entirely below the LOD zoom. */
  font-size: 7px;
  line-height: 1;
  max-width: 100%;
  overflow: hidden;
  padding: 0 1px;
  pointer-events: none;
  text-align: center;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.device-node__bay-slot {
  border: 1px solid var(--rn-bay-border, #6b7280);
  border-radius: 1px;
  box-sizing: border-box;
  opacity: 0.7;
}


.react-flow__handle-right.tube-fiber-handle {
  right: auto !important;
}

/* More specific selector to ensure override - target all possible React Flow handle states */
/* Only apply to non-ribbon handles */
.react-flow__node .react-flow__handle.tube-fiber-handle:not(.ribbon-bundle-handle),
.react-flow__node .react-flow__handle.tube-fiber-handle:not(.ribbon-bundle-handle)[data-handlepos],
.react-flow__handle.tube-fiber-handle:not(.ribbon-bundle-handle)[data-handlepos],
.react-flow__handle.tube-fiber-handle:not(.ribbon-bundle-handle)[data-fiber-idx] {
  background: var(--rn-fibre-bg-image, var(--rn-fibre-bg)) !important;
  background-color: var(--rn-fibre-bg) !important;
  background-image: var(--rn-fibre-bg-image, none) !important;
}

/* Ribbon bundle handles - simple solid color (removed gradient complexity) */

/* Connection animation - pulse effect when edge is first created */
@keyframes edgeConnectPulse {
  0% {
    opacity: 0;
    stroke-width: 1;
  }
  50% {
    opacity: 1;
    stroke-width: 4;
  }
  100% {
    opacity: 1;
    stroke-width: 2;
  }
}

.react-flow__edge.edge-connecting path,
.react-flow__edge.edge-connecting .react-flow__edge-path {
  animation: edgeConnectPulse 1s ease-out;
}

/* Highlighted edge pulse + dash motion (trace paths) */
@keyframes rnEdgeHighlightPulse {
  0%,
  100% {
    opacity: 0.85;
    stroke-width: var(--rn-edge-highlight-from, 2px);
  }
  50% {
    opacity: 1;
    stroke-width: var(--rn-edge-highlight-to, 6px);
  }
}

@keyframes rnEdgeHighlightDash {
  0% {
    stroke-dashoffset: 0;
  }
  100% {
    stroke-dashoffset: -48;
  }
}

.rn-edge-highlight {
  animation: rnEdgeHighlightPulse 2.4s ease-in-out infinite,
    rnEdgeHighlightDash 1.8s linear infinite;
  opacity: 0.9;
  stroke-linecap: round;
}

/* Power energisation overlay (computeEnergization) — marching dashes for live
   feeds, dimmed grey for de-energised ones. Purely visual: the edge set never
   changes with breaker state. */
.rn-power-edge--energized {
  animation: rnEdgeHighlightDash 1.6s linear infinite;
}

.rn-power-edge--energized-reverse {
  animation: rnEdgeHighlightDash 1.6s linear infinite reverse;
}

@media (prefers-reduced-motion: reduce) {
  .rn-power-edge--energized,
  .rn-power-edge--energized-reverse {
    animation: none;
  }
}

/* Splice glow animation - fade in when both handles are connected */
@keyframes spliceGlowFadeIn {
  0% {
    opacity: 0;
    transform: translateX(-50%) scaleY(0.3);
  }
  100% {
    opacity: 1;
    transform: translateX(-50%) scaleY(1);
  }
}

.splice-glow {
  animation: spliceGlowFadeIn 0.5s ease-out;
  transform-origin: center;
}

/* Splice text animation - fade in when both handles are connected */
@keyframes spliceTextFadeIn {
  0% {
    opacity: 0;
    transform: scale(0.8);
  }
  100% {
    opacity: 1;
    transform: scale(1);
  }
}

/* Splice text overlay - blur and opacity for text readability */
.splice-text-overlay {
  backdrop-filter: blur(2px);
  -webkit-backdrop-filter: blur(2px);
}

/* Dark mode overlay */
.react-flow-dark .splice-text-overlay {
  background: rgba(0, 0, 0, 0.6);
}

/* Light mode overlay */
.react-flow-light .splice-text-overlay {
  background: rgba(255, 255, 255, 0.7);
}

/* Splice text label - theme-aware colors */
.splice-text-label {
  color: #fff;
  text-shadow: 0 1px 3px rgba(0, 0, 0, 0.8), 0 0 2px rgba(0, 0, 0, 0.6);
}

.splice-text-label.animate-in {
  animation: spliceTextFadeIn 0.5s ease-out;
  transform-origin: center;
}

/* Light mode text */
.react-flow-light .splice-text-label {
  color: #1a1a1a;
  text-shadow: 0 1px 2px rgba(255, 255, 255, 0.9), 0 0 4px rgba(255, 255, 255, 0.7);
}

/* Remove all borders from splice nodes */
.react-flow__node[data-type="splice"],
.react-flow__node[data-type="splice"] > div {
  border: none !important;
  outline: none !important;
}

.splice-node {
  background: transparent !important;
  border: none !important;
  outline: none !important;
}

/* Only remove box-shadow when not selected */
.react-flow__node[data-type="splice"]:not(.selected) > div,
.splice-node:not(.selected) {
  box-shadow: none !important;
}

/* React Networks Attribution */
.react-networks-attribution {
  padding: 0;
  margin: 0;
  z-index: 1000;
}

.react-networks-attribution-link {
  font-size: 9px;
  color: var(--rn-text-muted, #9ca3af);
  text-decoration: none;
  font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, "Liberation Mono", monospace;
  transition: color 0.2s ease;
  padding: 1px 4px;
  border-radius: var(--rn-ui-radius, 1px);
  display: inline-block;
  background: rgba(0, 0, 0, 0.3);
  backdrop-filter: blur(4px);
}

.react-networks-attribution-link:hover {
  color: #e5e7eb;
  background: rgba(0, 0, 0, 0.4);
}

/* Light mode attribution */
.react-flow-light .react-networks-attribution-link {
  color: #6b7280;
  background: rgba(255, 255, 255, 0.6);
}

.react-flow-light .react-networks-attribution-link:hover {
  color: #1a1a1a;
  background: rgba(255, 255, 255, 0.8);
}

/* Coupler node styles */
.coupler-node {
  transition: box-shadow 0.2s ease;
}

.coupler-node.selected {
  box-shadow: 0 0 0 2px var(--rn-selection-ring, #3b82f6) !important;
}

/* Patch panel node styles */
.patch-panel-node {
  transition: box-shadow 0.2s ease, border-color 0.2s ease;
}

.patch-panel-node.selected {
  box-shadow: 0 0 0 2px var(--rn-selection-ring, #3b82f6) !important;
  border-color: var(--rn-selection-ring, #3b82f6) !important;
}

/* Closure node styles */
.closure-node {
  transition: box-shadow 0.2s ease, border-color 0.2s ease;
}

.closure-node.selected {
  box-shadow: 0 0 0 2px var(--rn-selection-ring, #3b82f6) !important;
  border-color: var(--rn-selection-ring, #3b82f6) !important;
}

/* Device node styles */
.device-node {
  background-color: var(--rn-device-bg-color, var(--rn-device-body, #1f2937));
  color: var(--rn-device-text-color, var(--rn-device-label, white));
  background-image: var(--rn-device-bg-image, none);
  background-position: var(--rn-device-bg-position, center);
  background-repeat: var(--rn-device-bg-repeat, no-repeat);
  background-size: var(--rn-device-bg-size, cover);
  border: 1px solid var(--rn-device-border-color, var(--rn-status-ok, #10b981));
  border-radius: var(--rn-ui-radius, 1px);
  box-shadow: var(--rn-device-box-shadow, 0 1px 2px rgba(0, 0, 0, 0.1));
  box-sizing: border-box;
  color: var(--rn-device-label, white);
  cursor: grab;
  display: flex;
  flex-direction: column;
  font-family: monospace;
  font-size: 8px;
  height: var(--rn-device-height, 20px);
  justify-content: center;
  left: var(--rn-device-left, auto);
  margin: 0;
  padding: 0;
  position: relative;
  transform: translateY(var(--rn-device-translate-y, 0px));
  width: var(--rn-device-width, 100%);
}

.device-node__content {
  display: flex;
  flex: 1;
  flex-direction: column;
  justify-content: center;
  overflow: hidden;
  padding: 2px;
  text-align: center;
}

/* Port geometry supplies exact sizes, including dense ports smaller than
   React Flow's default 5px minimum. Keep their centres and spacing intact. */
.device-node .react-flow__handle {
  min-width: 0;
  min-height: 0;
}

.device-node__image-layer {
  inset: 0;
  overflow: hidden;
  pointer-events: none;
  position: absolute;
  z-index: 0;
}

.device-node__image {
  display: block;
  height: 100%;
  pointer-events: none;
  user-select: none;
  width: 100%;
}

.device-node__content--image-badge {
  overflow: visible;
  text-align: left;
}

.device-node__label {
  font-size: 9px;
  font-weight: bold;
  line-height: 1.1;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.device-node__label--badge {
  background: rgba(15, 23, 42, 0.88);
  border: 1px solid rgba(148, 163, 184, 0.45);
  border-radius: var(--rn-ui-radius, 1px);
  display: inline-flex;
  max-width: 100%;
  padding: 1px 4px;
}

.device-node__manufacturer {
  color: var(--rn-text-muted, #9ca3af);
  font-size: 9px;
  line-height: 1;
}

.device-node__u-indicator {
  background: var(--rn-surface-raised, #374151);
  border-radius: 1px;
  bottom: 1px;
  color: var(--rn-text-muted, #9ca3af);
  font-size: 9px;
  line-height: 1;
  padding: 1px 2px;
  position: absolute;
  right: 1px;
}

.device-node__status-indicator {
  background: var(--rn-device-status-color, var(--rn-status-unknown, #6b7280));
  border-radius: 50%;
  bottom: 1px;
  height: 4px;
  left: 1px;
  position: absolute;
  width: 4px;
}

.device-node__split-face {
  background-color: var(--rn-device-body, #1f2937);
  overflow: hidden;
  position: relative;
}

.device-node__split-face--front {
  border-left: 1px dashed rgba(156, 163, 175, 0.35);
}

.device-node__split-face--rear {
  border-right: 1px dashed rgba(156, 163, 175, 0.35);
}

.device-node__face-bridge {
  position: relative;
}

.device-node__face-bridge-line {
  background: linear-gradient(180deg, transparent 0%, rgba(156, 163, 175, 0.8) 20%, rgba(156, 163, 175, 0.8) 80%, transparent 100%);
  left: 50%;
  position: absolute;
  top: 1px;
  transform: translateX(-50%);
  width: 1px;
  height: calc(100% - 2px);
}

/* Light mode adjustments */
.react-flow-light .coupler-node {
  background: var(--rn-surface, #f9fafb);
  color: var(--rn-text, #1f2937);
  border-color: var(--rn-border, #d1d5db);
}

.react-flow-light .patch-panel-node {
  background: transparent !important;
  color: var(--rn-text, #1f2937);
  border-color: var(--rn-border, #d1d5db);
}

.react-flow-light .closure-node {
  background: var(--rn-surface-raised, #f3f4f6) !important;
  color: var(--rn-text, #1f2937);
  border-color: var(--rn-border, #d1d5db);
}

/* Triangle node styles */
.react-flow__node[data-type="fibre-split"],
.react-flow__node.react-flow__node-fibre-split {
  background: transparent !important;
  border: none !important;
  padding: 0 !important;
}

.react-flow__node[data-type="fibre-split"] > div,
.react-flow__node.react-flow__node-fibre-split > div {
  background: transparent !important;
  border: none !important;
  padding: 0 !important;
  box-shadow: none !important;
  overflow: visible !important;
}

.react-flow__node[data-type="fibre-split"] svg,
.react-flow__node.react-flow__node-fibre-split svg {
  display: block !important;
  visibility: visible !important;
  opacity: 1 !important;
}

.triangle-node {
  position: relative !important;
  display: flex !important;
  align-items: center !important;
  justify-content: center !important;
  background: transparent !important;
  border: none !important;
  padding: 0 !important;
  margin: 0 !important;
  box-shadow: none !important;
  overflow: visible !important;
  box-sizing: border-box !important;
}


.triangle-node-text {
  text-align: center;
  position: relative;
  z-index: 2;
  width: 46px;
  height: 46px;
  display: flex;
  align-items: center;
  justify-content: center;
  margin: 0;
  color: #000000;
  font-weight: bold;
  font-size: 12px;
}

/* Cable node rotation */
.cable-node-rotated {
  transform-origin: center center !important;
}

/* Ensure Fibre Flow edges render with full saturation and aren't affected by node overlays */
.react-flow__edge[data-type="fibre-flow"] path,
.react-flow__edge[data-type="fibre-flow"] .react-flow__edge-path {
  opacity: 1 !important;
  stroke-opacity: 1 !important;
  mix-blend-mode: normal !important;
  filter: none !important;
}

.react-flow__edge[data-type="fibre-flow-link"] path,
.react-flow__edge[data-type="fibre-flow-link"] .react-flow__edge-path {
  opacity: 1 !important;
  stroke-opacity: 1 !important;
  mix-blend-mode: normal !important;
  filter: none !important;
}

/* ---------------------------------------------------------------------------
   Distribution board (generated faceplate — no image dependency).

   Drawn as a WALL-MOUNTED PANELBOARD, and deliberately built from the opposite
   vocabulary to RackNode / VerticalPDU so the two can never be confused at a
   glance on a dark canvas:

     rack / PDU strip          distribution board
     ----------------          ------------------
     dark charcoal frame       flat light steel face
     round status dots         a toggle slot with a lever in it
     U markers / outlet grid   one breaker module per row

   Everything here is flat: no gradients, no drop shadows, no painted-on screws,
   hinges or DIN rails. Those were drawn once and read as clip-art at diagram
   zoom, and none of them carried information. The identity now rests on the
   light face, the square corners, the dark nameplate and the DB chip.

   Colour is spent on exactly one thing: a fault. A closed way is a solid slate
   lever at the top of its slot, an open way a hollow lever at the bottom, and
   a TRIPPED way the only red on the board. Way highlighting still mirrors the
   bay highlight treatment.
   --------------------------------------------------------------------------- */
.distribution-board-node {
  background: var(--rn-board-face, #eef1f5);
  border-radius: var(--rn-ui-radius, 1px);
  box-sizing: border-box;
  color: var(--rn-board-text, #0f172a);
  display: flex;
  flex-direction: column;
  font-family: ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto,
    sans-serif;
  position: relative;
}

/* Nameplate. Dark slate on a light face — the inverse of a rack. */
.distribution-board-node__header {
  align-items: center;
  background: var(--rn-board-nameplate, #334155);
  box-sizing: border-box;
  color: var(--rn-board-nameplate-text, #f1f5f9);
  display: flex;
  gap: 6px;
  padding: 0 8px;
  position: relative;
  z-index: 2;
}

/* "DB" / "RPP" / "PANEL" / "BUSWAY" — the asset-class tag on the nameplate. */
.distribution-board-node__badge {
  background: var(--rn-board-badge-bg, #f1f5f9);
  border-radius: var(--rn-ui-radius, 1px);
  color: var(--rn-board-badge-text, #334155);
  flex: 0 0 auto;
  font-size: 7px;
  font-weight: 700;
  letter-spacing: 0.08em;
  line-height: 1;
  padding: 3px 3px 2px;
}

.distribution-board-node__label {
  font-size: 9px;
  font-weight: 600;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.distribution-board-node__header-meta {
  align-items: center;
  color: var(--rn-board-muted, #94a3b8);
  display: flex;
  flex: 0 0 auto;
  gap: 6px;
  margin-left: auto;
}

.distribution-board-node__incomer-rating,
.distribution-board-node__voltage {
  font-size: 7px;
  line-height: 1;
  white-space: nowrap;
}

.distribution-board-node__body {
  box-sizing: border-box;
  position: relative;
}

/*
 * A way row is one breaker module. The default layout is one way per row, so
 * the modules stack into a single column the way a real board reads. The row
 * rectangle is split by padding: the module face is the top band (::after) and
 * the bottom 4px is the gap to the module below. Keep the 4px in step with
 * BOARD_WAY_GAP_PX.
 */
.distribution-board-node__way {
  align-items: center;
  box-sizing: border-box;
  display: flex;
  gap: 6px;
  overflow: visible;
  /* Right padding keeps the annotation clear of the way's power handle. */
  padding: 0 8px 4px 5px;
}

/* The breaker module face. */
.distribution-board-node__way::after {
  background: var(--rn-board-way-face, #ffffff);
  border: 1px solid var(--rn-way-border, var(--rn-board-way-border, #cbd5e1));
  border-radius: var(--rn-ui-radius, 1px);
  bottom: 4px;
  content: '';
  left: 0;
  position: absolute;
  right: 0;
  top: 0;
  z-index: 0;
}

/* Lift the real content above the module face. */
.distribution-board-node__way > span {
  position: relative;
  z-index: 1;
}

/* Open: the module recedes, and its text with it. */
.distribution-board-node__way--open {
  color: var(--rn-board-muted, #94a3b8);
}

.distribution-board-node__way--open::after {
  background: var(--rn-board-way-open-face, #f1f5f9);
  border-color: var(--rn-way-open-border, var(--rn-board-way-open-border, #d5dce5));
}

.distribution-board-node__way--tripped::after {
  background: var(--rn-board-way-tripped-face, #fef2f2);
  border-color: var(--rn-way-tripped-border, #ef4444);
}

.distribution-board-node__way--failed::after {
  border-color: var(--rn-bay-failed-border, #ef4444);
}

.distribution-board-node__way--predicted::after {
  border-style: dashed;
  border-color: var(--rn-bay-predicted-border, #f59e0b);
}

.distribution-board-node__way--highlighted {
  z-index: 3;
}

.distribution-board-node__way--highlighted::after {
  border-color: var(--rn-bay-highlight, #f59e0b);
  box-shadow: 0 0 0 1px var(--rn-bay-highlight, #f59e0b);
}

/* Way number, printed on the module face as it is on real gear. */
.distribution-board-node__way-label {
  color: inherit;
  flex: 0 0 auto;
  font-size: 8px;
  font-weight: 700;
  line-height: 1;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/*
 * The rating. Tabular figures so a column of ways reads as a column of
 * numbers, and heavy enough to survive being the thing an engineer scans for.
 */
.distribution-board-node__way-rating {
  color: inherit;
  flex: 0 0 auto;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 8px;
  font-weight: 700;
  line-height: 1;
  white-space: nowrap;
}

/* Phase, the one muted token on the row. */
.distribution-board-node__way-detail {
  color: var(--rn-board-muted, #94a3b8);
  flex: 0 0 auto;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 7px;
  line-height: 1;
  margin-left: auto;
  white-space: nowrap;
}

/*
 * The toggle: a slot with a lever in it, two rectangles and nothing else.
 * Nothing else in the library is shaped like this — racks and PDUs use round
 * dots and square outlet blocks.
 */
.distribution-board-node__way-marker {
  border: 1px solid var(--rn-way-slot-border, var(--rn-board-way-border, #cbd5e1));
  border-radius: 1px;
  box-sizing: border-box;
  display: block;
  flex: 0 0 auto;
  /* Anchors the lever's three travel positions. */
  position: relative;
}

.distribution-board-node__way-lever {
  border-radius: 1px;
  box-sizing: border-box;
  display: block;
  height: 5px;
  left: 1px;
  position: absolute;
  right: 1px;
}

/*
 * Lever travel. The slot's inner height is 13px and the lever 5px, so the
 * three stops sit 4px apart — enough separation to tell closed from tripped at
 * diagram zoom, which a centred dot never gave you.
 */

/* Closed = lever up, solid. */
.distribution-board-node__way-marker--closed .distribution-board-node__way-lever {
  background: var(--rn-way-closed, var(--rn-board-lever, #334155));
  top: 0;
}

/* Open = lever down, hollow. */
.distribution-board-node__way-marker--open .distribution-board-node__way-lever {
  background: transparent;
  border: 1px solid var(--rn-way-open-border, var(--rn-board-muted, #94a3b8));
  bottom: 0;
}

/* Tripped = lever stopped between the stops. The only colour on the board. */
.distribution-board-node__way-marker--tripped .distribution-board-node__way-lever {
  background: var(--rn-way-tripped, #ef4444);
  top: 4px;
}

/* Tripped also pulses (same animation pattern as edge highlight). */
@keyframes rnBreakerTrippedPulse {
  0%,
  100% {
    box-shadow: 0 0 0 0 rgba(239, 68, 68, 0.6);
  }
  50% {
    box-shadow: 0 0 0 3px rgba(239, 68, 68, 0);
  }
}

.distribution-board-node__way-marker--tripped {
  animation: rnBreakerTrippedPulse 1.6s ease-in-out infinite;
  border-color: var(--rn-way-tripped-border, #ef4444);
}

@media (prefers-reduced-motion: reduce) {
  .distribution-board-node__way-marker--tripped {
    animation: none;
  }
}

/* ---------------------------------------------------------------------------
   Token fallbacks for un-themed shells.

   `.react-flow-light` / `.react-flow-dark` above are the source of truth. These
   rules only cover a root without either explicit theme class (a pre-hydration
   shell, or a host that never sets a theme): the light values are the base and
   the OS preference swaps in the dark values.
   --------------------------------------------------------------------------- */
:root:not(.react-flow-light):not(.react-flow-dark) {
  --rn-surface: #ffffff;
  --rn-surface-raised: #f3f4f6;
  --rn-surface-sunken: #e5e7eb;
  --rn-border: #d1d5db;
  --rn-border-strong: #9ca3af;
  --rn-border-subtle: #e5e7eb;
  --rn-text: #1f2937;
  --rn-text-muted: #6b7280;
  --rn-text-strong: #111827;
  --rn-text-on-accent: #1a1a1a;
  --rn-accent: #2563eb;
  --rn-accent-selected: #2563eb;
  --rn-selection-ring: #2563eb;
  --rn-status-ok: #059669;
  --rn-status-ok-border: #047857;
  --rn-status-warn: #d97706;
  --rn-status-error: #dc2626;
  --rn-status-unknown: #6b7280;
  --rn-rack-body: #e5e7eb;
  --rn-rack-rail: #e5e7eb;
  --rn-rack-accent: #b45309;
  --rn-device-body: #f9fafb;
  --rn-device-label: #1f2937;
  --rn-pdu-body: #e5e7eb;
  --rn-pdu-chassis-highlight: #f3f4f6;
  --rn-pdu-chassis-mid: #e5e7eb;
  --rn-pdu-chassis-shadow: #d1d5db;
  --rn-pdu-outlet: #ffffff;
  --rn-pdu-outlet-border: #9ca3af;
  --rn-pdu-header-text: #1f2937;
  /* Distribution boards: a flat light face, darker nameplate. */
  --rn-board-face: #eef1f5;
  --rn-board-text: #0f172a;
  --rn-board-nameplate: #334155;
  --rn-board-nameplate-text: #f1f5f9;
  --rn-board-badge-bg: #f1f5f9;
  --rn-board-badge-text: #334155;
  --rn-board-muted: #94a3b8;
  --rn-board-way-face: #ffffff;
  --rn-board-way-open-face: #f1f5f9;
  --rn-board-way-tripped-face: #fef2f2;
  --rn-board-way-border: #cbd5e1;
  --rn-board-way-open-border: #d5dce5;
  --rn-board-lever: #334155;
  --rn-focus-ring: #1d4ed8;
}

@media (prefers-color-scheme: dark) {
  :root:not(.react-flow-light):not(.react-flow-dark) {
    --rn-surface: #1f2937;
    --rn-surface-raised: #374151;
    --rn-surface-sunken: #111827;
    --rn-border: #4b5563;
    --rn-border-strong: #6b7280;
    --rn-border-subtle: #374151;
    --rn-text: #e5e7eb;
    --rn-text-muted: #9ca3af;
    --rn-text-strong: #ffffff;
    --rn-text-on-accent: #1a1a1a;
    --rn-accent: #3b82f6;
    --rn-accent-selected: #3b82f6;
    --rn-selection-ring: #3b82f6;
    --rn-status-ok: #10b981;
    --rn-status-ok-border: #059669;
    --rn-status-warn: #f59e0b;
    --rn-status-error: #ef4444;
    --rn-status-unknown: #6b7280;
    --rn-rack-body: #1f2937;
    --rn-rack-rail: #374151;
    --rn-rack-accent: #fbbf24;
    --rn-device-body: #1f2937;
    --rn-device-label: #ffffff;
    --rn-pdu-body: #1a1a1a;
    --rn-pdu-chassis-highlight: #4a5568;
    --rn-pdu-chassis-mid: #2d3748;
    --rn-pdu-chassis-shadow: #1a202c;
    --rn-pdu-outlet: #ffffff;
    --rn-pdu-outlet-border: #6b7280;
    --rn-pdu-header-text: #e2e8f0;
    /* Distribution boards: still a face lighter than a rack body, but slate
       rather than a near-white slab on a dark canvas. */
    --rn-board-face: #475569;
    --rn-board-text: #f1f5f9;
    --rn-board-nameplate: #1e293b;
    --rn-board-nameplate-text: #f1f5f9;
    --rn-board-badge-bg: #e2e8f0;
    --rn-board-badge-text: #1e293b;
    --rn-board-muted: #cbd5e1;
    --rn-board-way-face: #334155;
    --rn-board-way-open-face: #2a3546;
    --rn-board-way-tripped-face: #4c1d24;
    --rn-board-way-border: #64748b;
    --rn-board-way-open-border: #475569;
    --rn-board-lever: #e2e8f0;
    --rn-focus-ring: #60a5fa;
  }
}

/* ---------------------------------------------------------------------------
   Selection. One visual language for every node type: a 2px ring in the
   accent colour. Node components add `rn-node--selected` instead of inlining
   their own ring, so the width and colour are set in exactly one place.
   --------------------------------------------------------------------------- */
.rn-node--selected {
  box-shadow: 0 0 0 2px var(--rn-selection-ring, #3b82f6) !important;
}

/* ---------------------------------------------------------------------------
 * OtdrTraceStrip
 *
 * The strip has no React Flow dependency, so it carries its own theme classes
 * (`rn-otdr-light` / `rn-otdr-dark`) rather than `react-flow-light/dark` —
 * those also declare `--rn-flow-*` and are the anchor for a pile of
 * `.react-flow__*` descendant rules that mean nothing to a bare SVG. The
 * tokens are additionally declared on the React Flow theme classes so a strip
 * rendered inside an already-themed diagram container inherits them.
 *
 * These hex values are generated from OTDR_COLOR_TOKENS in
 * src/components/otdr-theme.ts and a test asserts the two stay in step.
 * ------------------------------------------------------------------------ */
.rn-otdr-light,
.react-flow-light {
  --rn-otdr-text: #0f172a;
  --rn-otdr-subtext: #64748b;
  --rn-otdr-axis: #cbd5e1;
  --rn-otdr-fibre: #0284c7;
  --rn-otdr-cumulative: #d97706;
  --rn-otdr-event-fill: #0369a1;
  --rn-otdr-end: #16a34a;
  --rn-otdr-fault: #be123c;
}

.rn-otdr-dark,
.react-flow-dark {
  --rn-otdr-text: #e2e8f0;
  --rn-otdr-subtext: #94a3b8;
  --rn-otdr-axis: #475569;
  --rn-otdr-fibre: #38bdf8;
  --rn-otdr-cumulative: #f59e0b;
  --rn-otdr-event-fill: #0ea5e9;
  --rn-otdr-end: #22c55e;
  --rn-otdr-fault: #f43f5e;
}

/* Clickable event affordance — previously injected as an inline <style> block
 * by every strip instance, now a stylesheet rule (import
 * `@mp70/react-networks/index.css`). */
.rn-otdr-event-clickable {
  cursor: pointer;
}

.rn-otdr-event-clickable .rn-otdr-event-ring {
  opacity: 0.35;
  transition: opacity 120ms ease;
}

.rn-otdr-event-clickable:hover .rn-otdr-event-ring,
.rn-otdr-event-clickable:focus-visible .rn-otdr-event-ring {
  opacity: 1;
}

/* Keyboard focus on an event marker: the ring is the focus indicator, so the
   browser's rectangular outline around the <g> bounding box is dropped. */
.rn-otdr-event-clickable:focus {
  outline: none;
}

.rn-otdr-event-clickable:focus-visible .rn-otdr-event-ring {
  stroke: var(--rn-focus-ring, #1d4ed8);
  stroke-width: 2.4px;
}

/* ---------------------------------------------------------------------------
 * Empty / error states
 * ------------------------------------------------------------------------- */

.react-networks-empty-state {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  pointer-events: none;
  z-index: 5;
  padding: 16px;
  text-align: center;
  font-size: 13px;
  line-height: 1.5;
  color: var(--rn-empty-text, #6b7280);
}

.react-networks-capturing .react-networks-diagram-error,
.react-networks-capturing .react-networks-diagram-error-fallback {
  visibility: hidden;
}

.react-networks-diagram-error {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 10px;
  margin: 12px;
  padding: 14px 16px;
  border: 1px solid var(--rn-error-border, #fecaca);
  border-radius: var(--rn-ui-radius, 1px);
  background: var(--rn-error-bg, #fef2f2);
  color: var(--rn-error-text, #b91c1c);
  font-size: 13px;
  line-height: 1.5;
}

.react-networks-diagram-error-message {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 12px;
  overflow-wrap: anywhere;
}

.react-networks-diagram-error-retry {
  padding: 5px 10px;
  border: 1px solid var(--rn-error-border, #fecaca);
  border-radius: var(--rn-ui-radius, 1px);
  background: transparent;
  color: inherit;
  font: inherit;
  font-size: 12px;
  cursor: pointer;
}

.react-networks-diagram-error-retry:hover {
  background: var(--rn-error-button-hover-bg, rgba(185, 28, 28, 0.08));
}

/* ---------------------------------------------------------------------------
   Zoom-aware label level of detail.

   `.rn-zoom-below-detail` is written onto the diagram wrapper by
   DiagramZoomLod whenever the viewport zoom drops below
   DIAGRAM_LABEL_LOD_ZOOM (0.8). Node content lives inside React Flow's
   transform, so an 8-9px label renders at zoom * px: below the threshold the
   micro tier lands under ~7 device px, where it is unreadable noise that
   obscures the geometry it sits on.

   Hiding it here rather than in each node component keeps the switch free —
   one classList write per threshold crossing, no per-node re-render — and
   gives consumers a single hook to extend with their own rules.

   The primary `.device-node__label` deliberately stays visible at every zoom:
   it is the one string that makes an overview readable at all.
   --------------------------------------------------------------------------- */
.rn-zoom-below-detail .device-node__bay-label,
.rn-zoom-below-detail .device-node__manufacturer,
.rn-zoom-below-detail .device-node__u-indicator {
  display: none;
}

/* Reduced motion. */
@media (prefers-reduced-motion: reduce) {
  .rn-edge-highlight,
  .react-flow__edge.animated path,
  .react-flow__edge.animated .react-flow__edge-path {
    animation: none !important;
  }

  .react-flow__edge.edge-connecting path,
  .react-flow__edge.edge-connecting .react-flow__edge-path,
  .splice-glow,
  .splice-text-label.animate-in {
    animation-duration: 1ms !important;
    animation-iteration-count: 1 !important;
  }

  .coupler-node,
  .patch-panel-node,
  .closure-node,
  .react-networks-attribution-link {
    transition: none !important;
  }

  .react-flow__node > div {
    transition-property: box-shadow, transform !important;
    transition-duration: 0s !important;
  }
}
