{
  "version": 3,
  "sources": ["../../../src/rendering-util/createGraph.ts", "../../../src/rendering-util/rendering-elements/lineJump.ts", "../../../src/rendering-util/layout-algorithms/swimlanes/adjustLayout.ts", "../../../src/rendering-util/layout-algorithms/swimlanes/helpers.ts", "../../../src/rendering-util/layout-algorithms/swimlanes/edgeLabelNodes.ts", "../../../src/rendering-util/layout-algorithms/swimlanes/direction/geometry.ts", "../../../src/rendering-util/layout-algorithms/swimlanes/direction/endpointClip.ts", "../../../src/rendering-util/layout-algorithms/swimlanes/direction/lrTransform.ts", "../../../src/rendering-util/layout-algorithms/swimlanes/direction/portSwap.ts", "../../../src/rendering-util/layout-algorithms/swimlanes/direction/terminalStub.ts", "../../../src/rendering-util/layout-algorithms/swimlanes/direction/materializedGeometry.ts", "../../../src/rendering-util/layout-algorithms/swimlanes/direction/detourSimplification.ts", "../../../src/rendering-util/layout-algorithms/swimlanes/direction/labelAnchoring.ts", "../../../src/rendering-util/layout-algorithms/swimlanes/direction/siblingSharedFaceRouting.ts", "../../../src/rendering-util/layout-algorithms/swimlanes/direction/sharedTrackNudging.ts", "../../../src/rendering-util/layout-algorithms/swimlanes/direction/validation.ts", "../../../src/rendering-util/layout-algorithms/swimlanes/postProcessing.ts", "../../../src/rendering-util/layout-algorithms/swimlanes/phase0.helpers.ts", "../../../src/rendering-util/layout-algorithms/swimlanes/phase1.cycles.ts", "../../../src/rendering-util/layout-algorithms/swimlanes/phase2.options.ts", "../../../src/rendering-util/layout-algorithms/swimlanes/config.ts", "../../../src/rendering-util/layout-algorithms/swimlanes/driving-tree.ts", "../../../src/rendering-util/layout-algorithms/swimlanes/phase2.crossCounts.ts", "../../../src/rendering-util/layout-algorithms/swimlanes/phase2.multitree.core.ts", "../../../src/rendering-util/layout-algorithms/swimlanes/phase2.multitree.order.ts", "../../../src/rendering-util/layout-algorithms/swimlanes/phase2.crossOptimization.ts", "../../../src/rendering-util/layout-algorithms/swimlanes/phase2.crossLaneAdjust.ts", "../../../src/rendering-util/layout-algorithms/swimlanes/phase2.longestPath.ts", "../../../src/rendering-util/layout-algorithms/swimlanes/phase2.gravity.ts", "../../../src/rendering-util/layout-algorithms/swimlanes/phase2.laneAwareCompact.ts", "../../../src/rendering-util/layout-algorithms/swimlanes/phase2.dummies.ts", "../../../src/rendering-util/layout-algorithms/swimlanes/phase3.ordering.ts", "../../../src/rendering-util/layout-algorithms/swimlanes/phase4.coordinates.ts", "../../../src/rendering-util/layout-algorithms/swimlanes/laneOrdering.ts", "../../../src/rendering-util/layout-algorithms/swimlanes/pipeline.ts", "../../../src/rendering-util/layout-algorithms/swimlanes/orthogonalRouter/router.ts", "../../../src/rendering-util/layout-algorithms/swimlanes/layoutCore.ts", "../../../src/rendering-util/layout-algorithms/swimlanes/index.ts"],
  "sourcesContent": ["import type { Selection } from 'd3';\nimport * as graphlib from 'dagre-d3-es/src/graphlib/index.js';\nimport type { LayoutData } from './types.js';\nimport { getConfig } from '../diagram-api/diagramAPI.js';\nimport { insertNode } from './rendering-elements/nodes.js';\n\n// Update type:\ntype D3Selection<T extends SVGElement = SVGElement> = Selection<\n  T,\n  unknown,\n  Element | null,\n  unknown\n>;\n\n/**\n * Creates a graph by merging the graph construction and DOM element insertion.\n *\n * This function creates the graph, inserts the SVG groups (clusters, edgePaths, edgeLabels, nodes)\n * into the provided element, and uses `insertNode` to add nodes to the diagram. Node dimensions\n * are computed using each node's bounding box.\n *\n * @param element - The D3 selection in which the SVG groups are inserted.\n * @param data4Layout - The layout data containing nodes and edges.\n * @returns A promise resolving to an object containing the graph and the inserted groups.\n */\nexport async function createGraphWithElements(\n  element: D3Selection,\n  data4Layout: LayoutData\n): Promise<{\n  graph: graphlib.Graph;\n  groups: {\n    clusters: D3Selection<SVGGElement>;\n    edgePaths: D3Selection<SVGGElement>;\n    edgeLabels: D3Selection<SVGGElement>;\n    nodes: D3Selection<SVGGElement>;\n    rootGroups: D3Selection<SVGGElement>;\n  };\n  nodeElements: Map<string, D3Selection<SVGElement | SVGGElement>>;\n}> {\n  // Create a directed, multi graph.\n  const graph = new graphlib.Graph({\n    multigraph: true,\n    compound: true,\n  });\n  const edgesToProcess = [...data4Layout.edges];\n  const config = getConfig();\n  // Create groups for clusters, edge paths, edge labels, and nodes.\n  const rootGroups = element.insert('g').attr('class', 'root');\n  const clusters = rootGroups.insert('g').attr('class', 'clusters');\n  const edgePaths = rootGroups.insert('g').attr('class', 'edges edgePath');\n  const edgeLabels = rootGroups.insert('g').attr('class', 'edgeLabels');\n  const nodesGroup = rootGroups.insert('g').attr('class', 'nodes');\n\n  const nodeElements = new Map<string, D3Selection<SVGElement | SVGGElement>>();\n\n  // When the container element is detached (no real DOM \u2014 e.g. headless unit\n  // tests that exercise the layout engine without rendering), `insertNode`\n  // cannot measure labels and would dereference a null node. The browser\n  // always passes a live container, so render + measure only when one exists;\n  // otherwise still build the graph topology with unmeasured (0) sizes.\n  const hasDom = element.node() != null;\n\n  // Insert nodes into the DOM and add them to the graph.\n  await Promise.all(\n    data4Layout.nodes.map(async (node) => {\n      if (node.isGroup) {\n        graph.setNode(node.id, { ...node });\n      } else {\n        if (hasDom) {\n          const childNodeEl = await insertNode(nodesGroup, node, { config, dir: node.dir });\n          const boundingBox = childNodeEl.node()?.getBBox() ?? { width: 0, height: 0 };\n          nodeElements.set(node.id, childNodeEl as D3Selection<SVGElement | SVGGElement>);\n          node.width = boundingBox.width;\n          node.height = boundingBox.height;\n        }\n        graph.setNode(node.id, { ...node });\n      }\n    })\n  );\n  // Add edges to the graph.\n\n  for (const edge of edgesToProcess) {\n    graph.setEdge(edge.start!, edge.end!, { ...edge }, edge.id);\n    const edgeExists = data4Layout.edges.some((existingEdge) => existingEdge.id === edge.id);\n    if (!edgeExists) {\n      data4Layout.edges.push(edge);\n    }\n  }\n\n  // DDLT size capture (dev / test tooling only). The capture module is loaded\n  // via dynamic import so it is never bundled into the production render path:\n  // in published builds `window.mermaidCaptureSizes` is unset, so this guard is\n  // a single property read and the import resolves to a lazily-loaded chunk that\n  // is only fetched when a developer explicitly enables capture.\n  // See layout-algorithms/ddlt/sizeCapture.ts.\n  if ((globalThis as unknown as { mermaidCaptureSizes?: boolean }).mermaidCaptureSizes) {\n    const { captureNodeSizes } = await import('./layout-algorithms/ddlt/sizeCapture.js');\n    captureNodeSizes(element, data4Layout);\n  }\n\n  return {\n    graph,\n    groups: { clusters, edgePaths, edgeLabels, nodes: nodesGroup, rootGroups },\n    nodeElements,\n  };\n}\n", "/**\n * Line jumps (\"hops\") for edge crossings.\n *\n * Detects true segment crossings between edge polylines and rewrites the SVG\n * path of the later edge so the crossing renders as either a small arc\n * (`jumpStyle: 'arc'`) or a visible break (`jumpStyle: 'gap'`).\n *\n * The pure functions (`findEdgeIntersections`, `processEdgesWithJumps`) are\n * DOM-free. The DOM-side `applyLineJumpsToSvg` helper reads geometry from\n * layout data and leaves curved (non-`M`/`L`) rendered paths untouched.\n */\n\nimport type { D3Selection } from '../../types.js';\nimport { markerOffsets } from '../../utils/lineWithOffset.js';\n\n/** Radius used by edges.js' generateRoundedPath. Kept in sync so rewritten\n * paths look like the originals at bends. */\nconst ROUNDED_CORNER_RADIUS = 5;\n\n/** Skip the jump if its clamped radius falls below this \u2014 avoids invisible\n * zero-length arcs on very crowded paths. */\nconst CORNER_EPSILON = 1e-5;\n\nexport interface Point {\n  x: number;\n  y: number;\n}\n\nexport interface EdgeGeom {\n  id: string;\n  points: Point[];\n  /**\n   * Optional curve hint matching `edge.curve` from the rendering layer.\n   * When set, line jumps are only applied for orthogonal-friendly curves\n   * (`'linear'`, `'rounded'`, `'step'`, `'stepBefore'`, `'stepAfter'`, or\n   * undefined). Other curves (basis, monotoneX, \u2026) are skipped to avoid\n   * corrupting smoothed geometry.\n   */\n  curve?: string;\n  /** Arrow type at the start (first point) \u2014 used to apply marker offset so\n   * the rewritten path's endpoint matches the original rendered geometry and\n   * the arrow marker orients correctly. */\n  arrowTypeStart?: string;\n  /** Arrow type at the end (last point). */\n  arrowTypeEnd?: string;\n}\n\nexport interface LineJumpConfig {\n  enabled: boolean;\n  jumpRadius: number;\n  jumpStyle: 'arc' | 'gap';\n}\n\nexport interface Crossing {\n  jumpEdgeId: string;\n  otherEdgeId: string;\n  /** Index of the segment within the jumping edge's polyline. */\n  segIndex: number;\n  /** Position of the crossing along the jumping edge's segment, 0..1. */\n  t: number;\n  point: Point;\n}\n\nconst ENDPOINT_EPSILON = 1e-6;\n\ninterface Segment {\n  a: Point;\n  b: Point;\n}\n\nfunction buildSegmentList(points: Point[]): Segment[] {\n  const segments: Segment[] = [];\n  for (let i = 0; i < points.length - 1; i++) {\n    segments.push({ a: points[i], b: points[i + 1] });\n  }\n  return segments;\n}\n\ninterface SegmentIntersection {\n  point: Point;\n  tA: number;\n  tB: number;\n}\n\n/**\n * Parametric segment-segment intersection. Returns null if the segments are\n * parallel, do not intersect, or only meet at one of their endpoints (within\n * `ENDPOINT_EPSILON`). Endpoint rejection prevents normal joins, T-junctions,\n * and shared-start edges from being treated as crossings.\n */\nfunction segmentIntersection(\n  a1: Point,\n  a2: Point,\n  b1: Point,\n  b2: Point\n): SegmentIntersection | null {\n  const dxA = a2.x - a1.x;\n  const dyA = a2.y - a1.y;\n  const dxB = b2.x - b1.x;\n  const dyB = b2.y - b1.y;\n\n  const denom = dxA * dyB - dyA * dxB;\n  if (denom === 0) {\n    return null;\n  }\n\n  const dx = b1.x - a1.x;\n  const dy = b1.y - a1.y;\n\n  const tA = (dx * dyB - dy * dxB) / denom;\n  const tB = (dx * dyA - dy * dxA) / denom;\n\n  if (\n    tA <= ENDPOINT_EPSILON ||\n    tA >= 1 - ENDPOINT_EPSILON ||\n    tB <= ENDPOINT_EPSILON ||\n    tB >= 1 - ENDPOINT_EPSILON\n  ) {\n    return null;\n  }\n\n  return {\n    point: { x: a1.x + tA * dxA, y: a1.y + tA * dyA },\n    tA,\n    tB,\n  };\n}\n\n/** True if the segment is horizontally dominant (abs(dx) is at least abs(dy)).\n * Ties go to horizontal to keep pure-diagonal edges grouped with the\n * horizontal bucket \u2014 they don't occur in orthogonal layouts anyway. */\nfunction isHorizontalSeg(seg: Segment): boolean {\n  return Math.abs(seg.b.x - seg.a.x) >= Math.abs(seg.b.y - seg.a.y);\n}\n\nexport function findEdgeIntersections(edges: EdgeGeom[]): Crossing[] {\n  const crossings: Crossing[] = [];\n\n  for (let i = 0; i < edges.length; i++) {\n    const edgeA = edges[i];\n    const segmentsA = buildSegmentList(edgeA.points);\n    for (let j = i + 1; j < edges.length; j++) {\n      const edgeB = edges[j];\n      const segmentsB = buildSegmentList(edgeB.points);\n\n      for (const [si, segA] of segmentsA.entries()) {\n        for (const [sj, segB] of segmentsB.entries()) {\n          const hit = segmentIntersection(segA.a, segA.b, segB.a, segB.b);\n          if (!hit) {\n            continue;\n          }\n\n          // Orthogonal-orientation rule: when one segment is horizontal-\n          // dominant and the other vertical-dominant, the HORIZONTAL one\n          // gets the jump (classic line-hop convention \u2014 arcs arch upward\n          // over the vertical line beneath). Falls back to later-index-wins\n          // when both segments share an orientation.\n          const aHoriz = isHorizontalSeg(segA);\n          const bHoriz = isHorizontalSeg(segB);\n          const orthogonalPair = aHoriz !== bHoriz;\n          const jumpOnA = orthogonalPair ? aHoriz : false;\n\n          if (jumpOnA) {\n            crossings.push({\n              jumpEdgeId: edgeA.id,\n              otherEdgeId: edgeB.id,\n              segIndex: si,\n              t: hit.tA,\n              point: hit.point,\n            });\n          } else {\n            crossings.push({\n              jumpEdgeId: edgeB.id,\n              otherEdgeId: edgeA.id,\n              segIndex: sj,\n              t: hit.tB,\n              point: hit.point,\n            });\n          }\n        }\n      }\n    }\n  }\n\n  return crossings;\n}\n\nfunction fmt(n: number): string {\n  // Strip trailing zeros so \"5.00\" \u2192 \"5\"; keep up to 3 decimals otherwise.\n  const rounded = Math.round(n * 1000) / 1000;\n  return Number.isInteger(rounded) ? `${rounded}` : `${rounded}`;\n}\n\nfunction pointToString(p: Point): string {\n  return `${fmt(p.x)},${fmt(p.y)}`;\n}\n\n/**\n * Determines the SVG arc sweep flag so the jump bumps in the conventional\n * direction: horizontal segments bump up (smaller y in SVG), vertical segments\n * bump right (larger x).\n */\nfunction getArcSweepFlag(seg: Segment): 0 | 1 {\n  const dx = seg.b.x - seg.a.x;\n  const dy = seg.b.y - seg.a.y;\n  if (Math.abs(dx) >= Math.abs(dy)) {\n    // Horizontal-dominant: bump up (smaller y in SVG's y-down frame).\n    // Going +x \u2192 sweep=1 sweeps through increasing angle 180\u00B0\u2192270\u00B0\u21920\u00B0,\n    //   which passes through (mid, y-r) = up.\n    // Going -x \u2192 sweep=0 (reverse direction) also lands the bump above.\n    return dx >= 0 ? 1 : 0;\n  }\n  // Vertical-dominant: bump right (positive x).\n  // Going +y \u2192 sweep=1; going -y \u2192 sweep=0.\n  return dy >= 0 ? 1 : 0;\n}\n\ninterface JumpOnSegment {\n  t: number;\n  point: Point;\n  /** Distance from segment start along the segment direction. */\n  d: number;\n  /** Effective radius after boundary + adjacency clamping. */\n  r: number;\n}\n\nconst MIN_JUMP_RADIUS = 1e-3;\n\n/**\n * Shifts the first/last point inward along the edge direction by the amount\n * required for their arrow markers, matching `applyMarkerOffsetsToPoints` in\n * edges.js so the rewritten path ends exactly where the original did.\n */\nfunction applyMarkerOffsets(points: Point[], edge: EdgeGeom): Point[] {\n  if (points.length < 2) {\n    return points.map((p) => ({ ...p }));\n  }\n  const out = points.map((p) => ({ ...p }));\n  const startOff =\n    edge.arrowTypeStart && markerOffsets[edge.arrowTypeStart as keyof typeof markerOffsets];\n  if (startOff) {\n    const a = points[0];\n    const b = points[1];\n    const ang = Math.atan2(b.y - a.y, b.x - a.x);\n    out[0].x = a.x + startOff * Math.cos(ang);\n    out[0].y = a.y + startOff * Math.sin(ang);\n  }\n  const endOff =\n    edge.arrowTypeEnd && markerOffsets[edge.arrowTypeEnd as keyof typeof markerOffsets];\n  if (endOff) {\n    const n = points.length;\n    const a = points[n - 2];\n    const b = points[n - 1];\n    const ang = Math.atan2(b.y - a.y, b.x - a.x);\n    out[n - 1].x = b.x - endOff * Math.cos(ang);\n    out[n - 1].y = b.y - endOff * Math.sin(ang);\n  }\n  return out;\n}\n\n/**\n * Emits the arc or gap command for a crossing, in the segment's direction.\n * Returns the part strings; caller inserts them in order.\n */\nfunction emitJump(\n  jump: JumpOnSegment,\n  ux: number,\n  uy: number,\n  sweep: 0 | 1,\n  style: 'arc' | 'gap'\n): string[] {\n  const cx = jump.point.x;\n  const cy = jump.point.y;\n  const pre = { x: cx - ux * jump.r, y: cy - uy * jump.r };\n  const post = { x: cx + ux * jump.r, y: cy + uy * jump.r };\n  const out = [`L${pointToString(pre)}`];\n  if (style === 'arc') {\n    out.push(`A${fmt(jump.r)},${fmt(jump.r)} 0 0 ${sweep} ${pointToString(post)}`);\n  } else {\n    out.push(`M${pointToString(post)}`);\n  }\n  return out;\n}\n\n/**\n * Mirrors the corner-rounding logic of `generateRoundedPath` in edges.js:\n * given a bend at `curr` between segments `prev\u2192curr` and `curr\u2192next`,\n * computes (startX, startY) just before curr on the incoming segment and\n * (endX, endY) just after curr on the outgoing segment, plus the Q control\n * point (which is curr itself). Returns `null` if the angle is degenerate\n * and the caller should just emit a straight `L curr`.\n */\ninterface RoundedCorner {\n  startX: number;\n  startY: number;\n  endX: number;\n  endY: number;\n  ctrlX: number;\n  ctrlY: number;\n  /** How much the start of the rounded corner eats into the incoming segment. */\n  cutLen: number;\n}\nfunction computeRoundedCorner(\n  prev: Point,\n  curr: Point,\n  next: Point,\n  radius: number\n): RoundedCorner | null {\n  const dx1 = curr.x - prev.x;\n  const dy1 = curr.y - prev.y;\n  const dx2 = next.x - curr.x;\n  const dy2 = next.y - curr.y;\n  const len1 = Math.hypot(dx1, dy1);\n  const len2 = Math.hypot(dx2, dy2);\n  if (len1 < CORNER_EPSILON || len2 < CORNER_EPSILON) {\n    return null;\n  }\n  const nx1 = dx1 / len1;\n  const ny1 = dy1 / len1;\n  const nx2 = dx2 / len2;\n  const ny2 = dy2 / len2;\n  const dot = nx1 * nx2 + ny1 * ny2;\n  const clamped = Math.max(-1, Math.min(1, dot));\n  const angle = Math.acos(clamped);\n  if (angle < CORNER_EPSILON || Math.abs(Math.PI - angle) < CORNER_EPSILON) {\n    return null;\n  }\n  const cutLen = Math.min(radius / Math.sin(angle / 2), len1 / 2, len2 / 2);\n  return {\n    startX: curr.x - nx1 * cutLen,\n    startY: curr.y - ny1 * cutLen,\n    endX: curr.x + nx2 * cutLen,\n    endY: curr.y + ny2 * cutLen,\n    ctrlX: curr.x,\n    ctrlY: curr.y,\n    cutLen,\n  };\n}\n\nfunction rewriteEdgePath(edge: EdgeGeom, jumps: Crossing[], config: LineJumpConfig): string {\n  const rawPoints = edge.points;\n  if (rawPoints.length < 2) {\n    return '';\n  }\n\n  // Match edges.js: shift the first/last point inward so arrow markers line up.\n  const points = applyMarkerOffsets(rawPoints, edge);\n  const rounded = edge.curve === 'rounded';\n\n  // Jumps are indexed into the ORIGINAL (un-offset) segment list. For mid-\n  // segments (i > 0 and i < n-2) the offsets don't change anything, and for\n  // the first/last segment the shift is tiny compared to jump radius so\n  // reusing the same (segIndex, t) is fine.\n  const segments = buildSegmentList(points);\n  const bySeg = new Map<number, JumpOnSegment[]>();\n  for (const j of jumps) {\n    const seg = segments[j.segIndex];\n    if (!seg) {\n      continue;\n    }\n    const segLen = Math.hypot(seg.b.x - seg.a.x, seg.b.y - seg.a.y);\n    const list = bySeg.get(j.segIndex) ?? [];\n    list.push({\n      t: j.t,\n      point: j.point,\n      d: j.t * segLen,\n      r: config.jumpRadius,\n    });\n    bySeg.set(j.segIndex, list);\n  }\n\n  const parts: string[] = [`M${pointToString(points[0])}`];\n  // Running cursor along the current segment measured from seg.a.\n  // Consumed at the front by the previous corner's cutLen (for rounded) and\n  // after that by mid-segment jumps.\n  for (let i = 0; i < segments.length; i++) {\n    const seg = segments[i];\n    const segLen = Math.hypot(seg.b.x - seg.a.x, seg.b.y - seg.a.y);\n    const ux = segLen === 0 ? 0 : (seg.b.x - seg.a.x) / segLen;\n    const uy = segLen === 0 ? 0 : (seg.b.y - seg.a.y) / segLen;\n    const sweep = getArcSweepFlag(seg);\n\n    // How much of the front of this segment was consumed by the previous\n    // corner's Q end-point (endX,endY). Default 0.\n    let segStartConsumed = 0;\n    if (rounded && i > 0) {\n      const corner = computeRoundedCorner(\n        points[i - 1],\n        points[i],\n        points[i + 1] ?? points[i],\n        ROUNDED_CORNER_RADIUS\n      );\n      if (corner) {\n        segStartConsumed = corner.cutLen;\n      }\n    }\n\n    // Rounded: if there's a next corner ahead, we stop short of it by cutLen.\n    let segEndStop = segLen;\n    let upcomingCorner: RoundedCorner | null = null;\n    if (rounded && i < segments.length - 1) {\n      upcomingCorner = computeRoundedCorner(\n        points[i],\n        points[i + 1],\n        points[i + 2] ?? points[i + 1],\n        ROUNDED_CORNER_RADIUS\n      );\n      if (upcomingCorner) {\n        segEndStop = segLen - upcomingCorner.cutLen;\n      }\n    }\n\n    // Jumps clamped so they don't overlap corners at either end of the\n    // segment or each other.\n    const segJumps = [...(bySeg.get(i) ?? [])].sort((a, b) => a.t - b.t);\n    for (const j of segJumps) {\n      j.r = Math.min(j.r, j.d - segStartConsumed, segEndStop - j.d);\n    }\n    for (let k = 0; k < segJumps.length - 1; k++) {\n      const gap = segJumps[k + 1].d - segJumps[k].d;\n      if (segJumps[k].r + segJumps[k + 1].r > gap) {\n        const half = gap / 2;\n        segJumps[k].r = Math.min(segJumps[k].r, half);\n        segJumps[k + 1].r = Math.min(segJumps[k + 1].r, half);\n      }\n    }\n\n    for (const j of segJumps) {\n      if (j.r < MIN_JUMP_RADIUS) {\n        continue;\n      }\n      parts.push(...emitJump(j, ux, uy, sweep, config.jumpStyle));\n    }\n\n    // End of segment: either a straight L to seg.b (last segment or linear),\n    // or a Q-corner into seg.b's neighborhood (rounded, middle).\n    if (rounded && upcomingCorner) {\n      parts.push(`L${fmt(upcomingCorner.startX)},${fmt(upcomingCorner.startY)}`);\n      parts.push(\n        `Q${fmt(upcomingCorner.ctrlX)},${fmt(upcomingCorner.ctrlY)} ${fmt(upcomingCorner.endX)},${fmt(upcomingCorner.endY)}`\n      );\n    } else {\n      parts.push(`L${pointToString(seg.b)}`);\n    }\n  }\n\n  return parts.join(' ');\n}\n\nfunction plainPath(points: Point[]): string {\n  if (points.length === 0) {\n    return '';\n  }\n  const parts = [`M${pointToString(points[0])}`];\n  for (let i = 1; i < points.length; i++) {\n    parts.push(`L${pointToString(points[i])}`);\n  }\n  return parts.join(' ');\n}\n\nexport function processEdgesWithJumps(\n  edges: EdgeGeom[],\n  config: LineJumpConfig\n): Map<string, string> {\n  const result = new Map<string, string>();\n\n  if (!config.enabled) {\n    for (const edge of edges) {\n      result.set(edge.id, plainPath(edge.points));\n    }\n    return result;\n  }\n\n  const crossings = findEdgeIntersections(edges);\n  const jumpsByEdge = new Map<string, Crossing[]>();\n  for (const c of crossings) {\n    const list = jumpsByEdge.get(c.jumpEdgeId) ?? [];\n    list.push(c);\n    jumpsByEdge.set(c.jumpEdgeId, list);\n  }\n\n  for (const edge of edges) {\n    const jumps = jumpsByEdge.get(edge.id);\n    if (!jumps || jumps.length === 0) {\n      result.set(edge.id, plainPath(edge.points));\n    } else {\n      result.set(edge.id, rewriteEdgePath(edge, jumps, config));\n    }\n  }\n\n  return result;\n}\n\n/**\n * Returns true iff the SVG path `d` is a straight-line path \u2014 only `M`/`L`/`m`/`l`\n * move/line commands plus their numeric coordinates (digits, sign, decimal point,\n * scientific-notation `e`, and `,`/space separators). Curved paths are skipped by\n * the caller.\n */\nexport function isStraightPath(d: string): boolean {\n  return /^[\\d\\s+,.LMelm-]*$/.test(d);\n}\n\n/**\n * Returns true iff the named curve produces orthogonal-friendly segments that\n * can be safely re-emitted with line jumps. Includes `'rounded'` even though\n * its rendered `d` contains `Q` corner-rounding commands \u2014 when an edge with\n * a jump is rewritten the corner rounding is dropped in exchange for visible\n * arc hops at crossings, which is the desired trade-off.\n */\nexport function curveSupportsLineHops(curve: string | undefined): boolean {\n  if (!curve) {\n    return true;\n  }\n  return (\n    curve === 'linear' ||\n    curve === 'rounded' ||\n    curve === 'step' ||\n    curve === 'stepBefore' ||\n    curve === 'stepAfter'\n  );\n}\n\n/**\n * Decodes the `data-points` attribute set by edges.js at render time. This\n * gives us the exact point list edges.js used to emit the rendered path \u2014\n * i.e. after node-boundary `intersect()` clipping and any orthogonalization,\n * but BEFORE `applyMarkerOffsetsToPoints`. Using these points guarantees the\n * rewrite's endpoints match the original rendered endpoints.\n */\nfunction decodeDataPoints(raw: string | null): Point[] | null {\n  if (!raw) {\n    return null;\n  }\n  try {\n    const json = typeof atob === 'function' ? atob(raw) : Buffer.from(raw, 'base64').toString();\n    const parsed = JSON.parse(json);\n    if (!Array.isArray(parsed)) {\n      return null;\n    }\n    const pts: Point[] = [];\n    for (const p of parsed) {\n      if (p && typeof p.x === 'number' && typeof p.y === 'number') {\n        pts.push({ x: p.x, y: p.y });\n      }\n    }\n    return pts.length >= 2 ? pts : null;\n  } catch {\n    return null;\n  }\n}\n\n/**\n * Patches the rendered SVG paths in `edgePathsGroup` for any edges that\n * cross. The true geometry is read from each path's `data-points` attribute\n * (written by edges.js at render time) so the rewrite's endpoints match\n * exactly what was originally rendered. Edges whose curve is a true\n * smoothing curve (`basis`, `monotoneX`, \u2026) are skipped.\n */\nexport function applyLineJumpsToSvg(\n  edgePathsGroup: D3Selection<SVGGElement>,\n  edges: EdgeGeom[],\n  config: LineJumpConfig\n): void {\n  if (!config.enabled) {\n    return;\n  }\n\n  const groupNode = edgePathsGroup.node();\n  if (!groupNode) {\n    return;\n  }\n\n  // Build a metadata lookup so per-edge properties (curve, arrow types)\n  // survive the DOM round-trip.\n  const edgeMeta = new Map<string, EdgeGeom>();\n  for (const e of edges) {\n    edgeMeta.set(e.id, e);\n  }\n\n  // Collect geometry from each path's data-points, preferring that over the\n  // incoming `edges[].points` which came from pre-render layout state.\n  const renderedEdges: EdgeGeom[] = [];\n  const pathById = new Map<string, Element>();\n  for (const e of edges) {\n    const escapedId = typeof CSS !== 'undefined' && CSS.escape ? CSS.escape(e.id) : e.id;\n    const pathEl = groupNode.querySelector(`path[data-id=\"${escapedId}\"]`);\n    if (!pathEl) {\n      continue;\n    }\n    pathById.set(e.id, pathEl);\n    const decoded = decodeDataPoints(pathEl.getAttribute('data-points'));\n    const points = decoded ?? e.points;\n    renderedEdges.push({ ...e, points });\n  }\n\n  const crossings = findEdgeIntersections(renderedEdges);\n  if (crossings.length === 0) {\n    return;\n  }\n\n  const jumpsByEdge = new Map<string, Crossing[]>();\n  for (const c of crossings) {\n    const list = jumpsByEdge.get(c.jumpEdgeId) ?? [];\n    list.push(c);\n    jumpsByEdge.set(c.jumpEdgeId, list);\n  }\n\n  for (const renderedEdge of renderedEdges) {\n    const jumps = jumpsByEdge.get(renderedEdge.id);\n    if (!jumps || jumps.length === 0) {\n      continue;\n    }\n    const meta = edgeMeta.get(renderedEdge.id);\n    const curveHint = meta?.curve;\n    if (curveHint !== undefined && !curveSupportsLineHops(curveHint)) {\n      continue;\n    }\n\n    const pathEl = pathById.get(renderedEdge.id);\n    if (!pathEl) {\n      continue;\n    }\n\n    if (curveHint === undefined) {\n      const currentD = pathEl.getAttribute('d') ?? '';\n      if (!isStraightPath(currentD)) {\n        continue;\n      }\n    }\n\n    // Read the ORIGINAL stroke-dasharray before rewriting so we can\n    // recompute it against the new total length. The `neo` look emits:\n    //   stroke-dasharray: 0 <oValueS> <len - oValueS - oValueE> <oValueE>;\n    // which hides the first oValueS and last oValueE pixels of the stroke\n    // \u2014 this is what actually prevents the stroke from poking into the arrow\n    // marker body. Our rewritten path has a different length, so without\n    // updating the \"on\" portion the hidden tail ends up in the wrong place.\n    const originalStyle = pathEl.getAttribute('style') ?? '';\n    const dasharrayMatch = /stroke-dasharray\\s*:\\s*0\\s+([\\d.]+)\\s+[\\d.]+\\s+([\\d.]+)/.exec(\n      originalStyle\n    );\n    const preservedOValueS = dasharrayMatch ? Number.parseFloat(dasharrayMatch[1]) : null;\n    const preservedOValueE = dasharrayMatch ? Number.parseFloat(dasharrayMatch[2]) : null;\n\n    const newD = rewriteEdgePath(renderedEdge, jumps, config);\n    pathEl.setAttribute('d', newD);\n\n    if (\n      preservedOValueS !== null &&\n      preservedOValueE !== null &&\n      typeof (pathEl as SVGPathElement).getTotalLength === 'function'\n    ) {\n      const newLen = (pathEl as SVGPathElement).getTotalLength();\n      const onLen = Math.max(0, newLen - preservedOValueS - preservedOValueE);\n      const newDasharray = `0 ${preservedOValueS} ${onLen} ${preservedOValueE}`;\n      const cleaned = originalStyle\n        .replace(/stroke-dasharray\\s*:[^;]*;?/g, `stroke-dasharray: ${newDasharray};`)\n        .replace(/;\\s*;+/g, ';');\n      pathEl.setAttribute('style', cleaned);\n    }\n  }\n}\n", "import type { LayoutData } from '../../types.js';\nimport { positionNode } from '../../rendering-elements/nodes.js';\nimport type { D3Selection } from '../../../types.js';\nimport { insertCluster } from '../../rendering-elements/clusters.js';\nimport {\n  edgeLabels,\n  insertEdge,\n  insertEdgeLabel,\n  terminalLabels,\n} from '../../rendering-elements/edges.js';\nimport { applyLineJumpsToSvg } from '../../rendering-elements/lineJump.js';\nimport { log } from '../../../logger.js';\nimport { getSubGraphTitleMargins } from '../../../utils/subGraphTitleMargins.js';\nimport { getConfig } from '../../../config.js';\nimport utils from '../../../utils.js';\n\nexport async function adjustLayout(\n  data4Layout: LayoutData,\n  groups: {\n    edgePaths: D3Selection<SVGGElement>;\n    rootGroups: D3Selection<SVGGElement>;\n    [key: string]: D3Selection<SVGGElement>;\n    edgeLabels: D3Selection<SVGGElement>;\n  }\n): Promise<void> {\n  // Render clusters and position nodes; this also populates node.intersect on shapes.\n  for (const node of data4Layout.nodes) {\n    if (node.isGroup) {\n      await insertCluster(groups.clusters, node);\n    } else {\n      positionNode(node);\n    }\n  }\n\n  // Build a lookup so we can pass full node objects (with intersect) to insertEdge,\n  // matching the behavior of the dagre-based pipeline.\n  const nodeById = new Map<string, any>();\n  for (const node of data4Layout.nodes) {\n    if (node?.id) {\n      nodeById.set(node.id, node);\n    }\n  }\n\n  for (const edge of data4Layout.edges) {\n    const startNode = edge.start ? (nodeById.get(edge.start) ?? {}) : {};\n    const endNode = edge.end ? (nodeById.get(edge.end) ?? {}) : {};\n\n    const paths = insertEdge(\n      groups.edgePaths,\n      { ...edge },\n      {},\n      data4Layout.type,\n      startNode,\n      endNode,\n      data4Layout.diagramId\n    );\n    if (edge.label) {\n      await insertEdgeLabel(groups.rootGroups, edge);\n    }\n\n    if (edge.label) {\n      positionEdgeLabel(edge, paths);\n    }\n  }\n\n  // Render-time post-processing: replace edge crossings with line hops.\n  // Default: 'arc'. Set swimlane.lineHops = false to opt out.\n  const lineHopsConfig = data4Layout.config?.swimlane?.lineHops;\n  if (lineHopsConfig !== false) {\n    const jumpStyle: 'arc' | 'gap' = lineHopsConfig === 'gap' ? 'gap' : 'arc';\n    const edgeGeometries = data4Layout.edges\n      .filter((e: any) => Array.isArray(e.points) && e.points.length >= 2)\n      .map((e: any) => ({\n        id: e.id,\n        points: e.points,\n        curve: e.curve,\n        arrowTypeStart: e.arrowTypeStart,\n        arrowTypeEnd: e.arrowTypeEnd,\n      }));\n    applyLineJumpsToSvg(groups.edgePaths, edgeGeometries, {\n      enabled: true,\n      jumpRadius: 6,\n      jumpStyle,\n    });\n  }\n}\n\nfunction positionEdgeLabel(edge: any, paths: any) {\n  const path = paths?.updatedPath ?? paths?.originalPath;\n  const siteConfig = getConfig();\n  const { subGraphTitleTotalMargin } = getSubGraphTitleMargins({\n    flowchart: siteConfig.flowchart ?? {},\n  });\n  if (edge.label) {\n    const el = edgeLabels.get(edge.id);\n    let x = edge.x;\n    let y = edge.y;\n    if (path) {\n      const pos = utils.calcLabelPosition(path);\n      log.debug(\n        'Moving label ' + edge.label + ' from (',\n        x,\n        ',',\n        y,\n        ') to (',\n        pos.x,\n        ',',\n        pos.y,\n        ') abc88'\n      );\n      if (paths) {\n        x = pos.x;\n        y = pos.y;\n      }\n    }\n    el.attr('transform', `translate(${x}, ${y + subGraphTitleTotalMargin / 2})`);\n  }\n\n  if (edge?.startLabelLeft) {\n    const el = terminalLabels.get(edge.id).startLeft;\n    let x = edge?.x;\n    let y = edge?.y;\n    if (path) {\n      const pos = utils.calcTerminalLabelPosition(edge.arrowTypeStart ? 10 : 0, 'start_left', path);\n      x = pos.x;\n      y = pos.y;\n    }\n    el.attr('transform', `translate(${x}, ${y})`);\n  }\n  if (edge.startLabelRight) {\n    const el = terminalLabels.get(edge.id).startRight;\n    let x = edge.x;\n    let y = edge.y;\n    if (path) {\n      const pos = utils.calcTerminalLabelPosition(\n        edge.arrowTypeStart ? 10 : 0,\n        'start_right',\n        path\n      );\n      x = pos.x;\n      y = pos.y;\n    }\n    el.attr('transform', `translate(${x}, ${y})`);\n  }\n  if (edge.endLabelLeft) {\n    const el = terminalLabels.get(edge.id).endLeft;\n    let x = edge.x;\n    let y = edge.y;\n    if (path) {\n      const pos = utils.calcTerminalLabelPosition(edge.arrowTypeEnd ? 10 : 0, 'end_left', path);\n      x = pos.x;\n      y = pos.y;\n    }\n    el.attr('transform', `translate(${x}, ${y})`);\n  }\n  if (edge.endLabelRight) {\n    const el = terminalLabels.get(edge.id).endRight;\n    let x = edge.x;\n    let y = edge.y;\n    if (path) {\n      const pos = utils.calcTerminalLabelPosition(edge.arrowTypeEnd ? 10 : 0, 'end_right', path);\n      x = pos.x;\n      y = pos.y;\n    }\n    el.attr('transform', `translate(${x}, ${y})`);\n  }\n}\n", "import type {\n  LayoutData,\n  Node as MermaidNode,\n  Edge as MermaidEdge,\n  ClusterNode,\n} from '../../types.js';\n\nexport type Layout = LayoutData;\nexport type Node = MermaidNode;\nexport type NodeId = Node['id'];\nexport type EdgeId = MermaidEdge['id'];\n\nexport interface EdgeRef {\n  id: EdgeId;\n  src: NodeId;\n  dst: NodeId;\n  weight?: number;\n  ref: MermaidEdge;\n}\n\nexport interface Graph {\n  nodes: NodeId[];\n  edges: EdgeRef[];\n  layout: Layout;\n  nodeById: Map<NodeId, Node>;\n}\n\nexport interface Layering {\n  layers: NodeId[][];\n  rankOf: Record<NodeId, number>;\n  dummy?: Set<NodeId>;\n}\n\nexport interface OrderedLayers {\n  layers: NodeId[][];\n}\n\nexport interface Coordinates {\n  x: Record<NodeId, number>;\n  y: Record<NodeId, number>;\n}\n\nexport type Edge = EdgeRef;\n\nexport const DEFAULT_SWIMLANE_ID = '__swimlane_default__';\n\nexport interface WriteBackOptions {\n  layerGap?: number;\n  nodeGap?: number;\n}\n\n// Captured swimlane fixtures use 21px as the stable single-line label height.\nconst TOP_LANE_TITLE_BAND_HEIGHT = 21;\nconst MIN_TOP_LANE_HORIZONTAL_PADDING = 20;\n\nfunction topLaneHorizontalPadding(lane: Node): number {\n  return Math.max(lane.padding ?? MIN_TOP_LANE_HORIZONTAL_PADDING, MIN_TOP_LANE_HORIZONTAL_PADDING);\n}\n\nfunction assignTopLaneTitleRect(lane: Node): void {\n  const { x, y, width, height } = lane;\n  const contentTop = (lane as { swimlaneContentTop?: unknown }).swimlaneContentTop;\n  if (\n    typeof x !== 'number' ||\n    typeof y !== 'number' ||\n    typeof width !== 'number' ||\n    typeof height !== 'number' ||\n    typeof contentTop !== 'number' ||\n    !Number.isFinite(x) ||\n    !Number.isFinite(y) ||\n    !Number.isFinite(width) ||\n    !Number.isFinite(height) ||\n    !Number.isFinite(contentTop) ||\n    width <= 0 ||\n    height <= 0\n  ) {\n    delete lane.groupTitleRect;\n    return;\n  }\n\n  const top = y - height / 2;\n  const headerBottom = Math.min(contentTop, y + height / 2);\n  const titleHeight = Math.min(TOP_LANE_TITLE_BAND_HEIGHT, Math.max(0, headerBottom - top));\n  const bottom = top + titleHeight;\n  if (bottom <= top) {\n    delete lane.groupTitleRect;\n    return;\n  }\n\n  lane.groupTitleRect = {\n    left: x - width / 2,\n    right: x + width / 2,\n    top,\n    bottom,\n  };\n}\n\nexport function prepareLayoutForSwimlanes(layout: LayoutData): void {\n  const direction = (layout as any).direction;\n  const nodes = (layout.nodes ??= []);\n  for (const node of layout.nodes ?? []) {\n    if (node.isGroup && !node.parentId) {\n      node.shape = 'swimlane';\n      if (direction) {\n        (node as any).direction = direction;\n      }\n    }\n  }\n\n  const looseNodes = nodes.filter((node) => !node.isGroup && !node.parentId);\n  if (looseNodes.length === 0) {\n    return;\n  }\n\n  let defaultLane = nodes.find((node) => node.id === DEFAULT_SWIMLANE_ID);\n  if (!defaultLane) {\n    defaultLane = {\n      id: DEFAULT_SWIMLANE_ID,\n      label: '',\n      isGroup: true,\n      shape: 'swimlane',\n      padding: 20,\n      ...(direction ? { direction } : {}),\n    } as ClusterNode;\n    nodes.push(defaultLane);\n  } else if (defaultLane.isGroup) {\n    defaultLane.shape = 'swimlane';\n    if (direction) {\n      (defaultLane as any).direction = direction;\n    }\n  }\n\n  for (const node of looseNodes) {\n    node.parentId = DEFAULT_SWIMLANE_ID;\n  }\n}\n\nexport function toGraphView(layout: LayoutData): Graph {\n  const nodeById = new Map<NodeId, Node>();\n  for (const n of layout.nodes ?? []) {\n    nodeById.set(n.id, n);\n  }\n\n  const edges: EdgeRef[] = [];\n  for (const e of layout.edges ?? []) {\n    const src = typeof e.start === 'string' ? e.start : undefined;\n    const dst = typeof e.end === 'string' ? e.end : undefined;\n    if (!src || !dst) {\n      continue;\n    }\n    // Exclude labelled originals from Sugiyama: their routing is carried by\n    // the two layout-only virtual edges A\u2192label and label\u2192B, which create the\n    // correct layer/ordering constraints. Including the original as well would\n    // double-count rank pressure and inflate crossing penalties.\n    if ((e as MermaidEdge & { labelNodeId?: string }).labelNodeId) {\n      continue;\n    }\n    edges.push({ id: e.id, src, dst, ref: e });\n  }\n\n  const allNodes = layout.nodes ?? [];\n  const groupNodes = allNodes.filter((n) => n.isGroup);\n  const nonGroupNodes = allNodes.filter((n) => !n.isGroup);\n\n  const nodesInGroupOrder = [...groupNodes].reverse();\n  const nodes: NodeId[] = [...nodesInGroupOrder, ...nonGroupNodes].map((n) => n.id);\n  return { nodes, edges, layout, nodeById };\n}\n\nexport function writeBackToLayoutData(\n  g: Graph,\n  ordered: OrderedLayers,\n  coords: Coordinates,\n  opts?: WriteBackOptions\n): void {\n  const { layout } = g;\n  const nodeMap = g.nodeById;\n  const layerGap = opts?.layerGap ?? 100;\n  const nodeGap = opts?.nodeGap ?? 40;\n\n  let layerIndex = 0;\n  for (const layer of ordered.layers) {\n    let orderIndex = 0;\n    for (const id of layer) {\n      const node = nodeMap.get(id);\n      if (!node) {\n        orderIndex++;\n        continue;\n      }\n      node.layer = layerIndex;\n      node.order = orderIndex;\n      const x = coords.x[id] ?? orderIndex * nodeGap;\n      const y = coords.y[id] ?? layerIndex * layerGap;\n      node.x = x;\n      node.y = y;\n      orderIndex++;\n    }\n    layerIndex++;\n  }\n\n  const allNodes = layout.nodes ?? [];\n  const groupBounds = new Map<NodeId, { minX: number; maxX: number; minY: number; maxY: number }>();\n  const topLevelGroups: Node[] = [];\n  for (const group of allNodes) {\n    if (!group?.isGroup) {\n      continue;\n    }\n    if (!group.parentId) {\n      topLevelGroups.push(group);\n    }\n    const children = allNodes.filter((n) => n.parentId === group.id);\n    let minX = Infinity;\n    let maxX = -Infinity;\n    let minY = Infinity;\n    let maxY = -Infinity;\n    for (const child of children) {\n      const cx = child.x ?? coords.x[child.id];\n      const cy = child.y ?? coords.y[child.id];\n      const cw = child.width ?? 0;\n      const ch = child.height ?? 0;\n      if (cx != null && cy != null) {\n        minX = Math.min(minX, cx - cw / 2);\n        maxX = Math.max(maxX, cx + cw / 2);\n        minY = Math.min(minY, cy - ch / 2);\n        maxY = Math.max(maxY, cy + ch / 2);\n      }\n    }\n    if (minX === Infinity || minY === Infinity) {\n      group.x = group.x ?? 0;\n      group.y = group.y ?? 0;\n      group.width = group.width ?? 0;\n      group.height = group.height ?? 0;\n    } else {\n      const pad = group.padding ?? 20;\n      const horizontalPad = group.parentId ? pad : 2 * topLaneHorizontalPadding(group);\n      const verticalPad = pad;\n      const w = Math.max(0, maxX - minX) + horizontalPad;\n      const h = Math.max(0, maxY - minY) + verticalPad;\n      const cx = (minX + maxX) / 2;\n      const cy = (minY + maxY) / 2;\n      group.x = cx;\n      group.y = cy;\n      group.width = w;\n      group.height = h;\n      groupBounds.set(group.id, { minX, maxX, minY, maxY });\n    }\n  }\n\n  if (topLevelGroups.length > 0 && groupBounds.size > 0) {\n    let globalMinY = Infinity;\n    let globalMaxY = -Infinity;\n    let maxPad = 0;\n    for (const lane of topLevelGroups) {\n      const pad = lane.padding ?? 20;\n      if (pad > maxPad) {\n        maxPad = pad;\n      }\n      const b = groupBounds.get(lane.id);\n      if (!b) {\n        continue;\n      }\n      globalMinY = Math.min(globalMinY, b.minY);\n      globalMaxY = Math.max(globalMaxY, b.maxY);\n    }\n    if (globalMinY !== Infinity && globalMaxY !== -Infinity) {\n      const contentHeight = Math.max(0, globalMaxY - globalMinY);\n      const minHeaderMargin = 36;\n      const verticalMargin = Math.max(maxPad, minHeaderMargin);\n      const laneHeight = contentHeight + 2 * verticalMargin;\n      const centerY = (globalMinY + globalMaxY) / 2;\n      for (const lane of topLevelGroups) {\n        lane.y = centerY;\n        lane.height = laneHeight;\n        (lane as any).swimlaneContentTop = globalMinY;\n      }\n\n      const sortedLanes = [...topLevelGroups].sort((a, b) => {\n        const ax = a.x ?? 0;\n        const bx = b.x ?? 0;\n        return ax - bx;\n      });\n\n      const laneIds: NodeId[] = [];\n      const centers: number[] = [];\n      const baseWidths: number[] = [];\n\n      for (const lane of sortedLanes) {\n        const b = groupBounds.get(lane.id);\n        if (!b) {\n          continue;\n        }\n        const contentWidth = Math.max(0, b.maxX - b.minX) + 2 * topLaneHorizontalPadding(lane);\n        const cx = (b.minX + b.maxX) / 2;\n        laneIds.push(lane.id);\n        centers.push(cx);\n        baseWidths.push(contentWidth);\n      }\n\n      const count = laneIds.length;\n      if (count > 0) {\n        const laneWidths = new Map<NodeId, number>();\n\n        if (count === 1) {\n          laneWidths.set(laneIds[0], baseWidths[0]);\n        } else {\n          const d: number[] = [];\n          for (let i = 0; i < count - 1; i++) {\n            d.push(centers[i + 1] - centers[i]);\n          }\n\n          const u: number[] = new Array(count);\n          u[0] = 0;\n          for (let i = 0; i < count - 1; i++) {\n            u[i + 1] = 2 * d[i] - u[i];\n          }\n\n          let lowerBound = 0;\n          let upperBound = Number.POSITIVE_INFINITY;\n          for (let i = 0; i < count; i++) {\n            const baseW = baseWidths[i];\n            if (i % 2 === 0) {\n              lowerBound = Math.max(lowerBound, baseW - u[i]);\n            } else {\n              upperBound = Math.min(upperBound, u[i] - baseW);\n            }\n          }\n\n          let x = lowerBound;\n          if (lowerBound <= upperBound) {\n            x = (lowerBound + upperBound) / 2;\n          } else {\n            x = lowerBound;\n          }\n\n          for (let i = 0; i < count; i++) {\n            const w = u[i] + (i % 2 === 0 ? x : -x);\n            const finalWidth = Math.max(baseWidths[i], w);\n            laneWidths.set(laneIds[i], finalWidth);\n          }\n        }\n\n        for (const lane of topLevelGroups) {\n          const w = laneWidths.get(lane.id);\n          if (w != null) {\n            lane.width = w;\n          }\n          assignTopLaneTitleRect(lane);\n        }\n      }\n    }\n  }\n}\n", "/**\n * Edge Label Nodes Transformation (label-as-waypoint variant)\n *\n * For each labelled edge, this transform creates an `edge-label-*` node that\n * participates in the Sugiyama layout (so the label text gets a deterministic\n * position in a lane). Unlike the older split-edge model, it leaves the\n * original labelled edge in place and stamps `labelNodeId` on it \u2014 the router\n * uses that stamp to thread the original edge's single polyline through the\n * label node's center.\n *\n * Two `isLayoutOnly` virtual edges (A\u2192label, label\u2192B) are appended to the\n * layout so that Sugiyama's layering and ordering honour the label's position\n * between source and target. They are never routed or rendered: the router and\n * renderer skip any edge flagged with `isLayoutOnly`.\n */\n\nimport type { LayoutData, Node, Edge, NonClusterNode } from '../../types.js';\nimport { log } from '../../../logger.js';\n\nconst EDGE_LABEL_LOG_PREFIX = '[EdgeLabelNodes]';\n\n/**\n * Transforms edges with labels into label nodes + layout-only virtual edges.\n *\n * For each edge with a label:\n * 1. Creates a label node with the label text.\n * 2. Assigns the label node to the source or target lane (cross-lane edges\n *    prefer the target lane for tighter routing).\n * 3. Stamps `labelNodeId` on the original edge.\n * 4. Appends two `isLayoutOnly: true` virtual edges (A\u2192label, label\u2192B) so\n *    Sugiyama places the label between source and target. The router skips\n *    these; only the original edge is routed (threading through the label\n *    node's center).\n *\n * @param data - The layout data to transform\n * @returns The transformed layout data with label nodes and virtual edges\n */\nexport function createEdgeLabelNodes(data: LayoutData): LayoutData {\n  const nodesToAdd: NonClusterNode[] = [];\n  const layoutOnlyEdges: Edge[] = [];\n\n  const nodeById = new Map<string, Node>();\n  for (const node of data.nodes) {\n    nodeById.set(node.id, node);\n  }\n\n  for (const edge of data.edges) {\n    if (!edge.label || edge.label.length === 0) {\n      continue;\n    }\n    if ((edge as Edge & { isLayoutOnly?: boolean }).isLayoutOnly) {\n      continue;\n    }\n    // Guard against double-processing if the caller invokes us twice.\n    if ((edge as Edge & { labelNodeId?: string }).labelNodeId) {\n      continue;\n    }\n\n    const sourceNode = edge.start ? nodeById.get(edge.start) : undefined;\n    const targetNode = edge.end ? nodeById.get(edge.end) : undefined;\n\n    if (!sourceNode || !targetNode) {\n      log.warn(EDGE_LABEL_LOG_PREFIX, `Edge ${edge.id} has missing source or target node`);\n      continue;\n    }\n\n    const labelNodeId = `edge-label-${edge.start}-${edge.end}-${edge.id}`;\n\n    // For cross-lane edges, assign to the target lane for better routing:\n    // it keeps the label closer to where the edge is heading and avoids long\n    // detours back to the source lane.\n    const isCrossLane = sourceNode.parentId !== targetNode.parentId;\n    const labelLane = isCrossLane ? targetNode.parentId : sourceNode.parentId;\n\n    const labelNode: NonClusterNode = {\n      id: labelNodeId,\n      label: edge.label,\n      edgeStart: edge.start ?? '',\n      edgeEnd: edge.end ?? '',\n      shape: 'labelRect',\n      width: 0, // populated when rendered / applied from fixture\n      height: 0,\n      isEdgeLabel: true,\n      isDummy: true,\n      parentId: labelLane,\n      isGroup: false,\n      labelStyle: Array.isArray(edge.labelStyle) ? edge.labelStyle[0] : (edge.labelStyle ?? ''),\n      ...(sourceNode.dir ? { dir: sourceNode.dir } : {}),\n    };\n\n    nodesToAdd.push(labelNode);\n\n    // Stamp the original edge so the router can decompose routing through the\n    // label's center when producing a single polyline.\n    (edge as Edge & { labelNodeId?: string }).labelNodeId = labelNodeId;\n\n    // Ownership of the label text moves to the label node. Clear the label\n    // off the original edge so the edge renderer does not draw it a second\n    // time alongside the label node's own text.\n    edge.label = undefined;\n    (edge as Edge & { text?: unknown }).text = undefined;\n\n    // Layout-only virtual edges: Sugiyama uses these to place the label node\n    // between source and target. They are not routed or rendered \u2014 consumers\n    // must skip any edge with `isLayoutOnly: true`.\n    const toLabelVirtual: Edge = {\n      id: `${edge.id}-to-label`,\n      start: edge.start,\n      end: labelNodeId,\n      type: 'normal',\n      isLayoutOnly: true,\n    } as unknown as Edge;\n    const fromLabelVirtual: Edge = {\n      id: `${edge.id}-from-label`,\n      start: labelNodeId,\n      end: edge.end,\n      type: 'normal',\n      isLayoutOnly: true,\n    } as unknown as Edge;\n\n    layoutOnlyEdges.push(toLabelVirtual, fromLabelVirtual);\n  }\n\n  const newNodes = [...data.nodes, ...nodesToAdd];\n  const newEdges = [...data.edges, ...layoutOnlyEdges];\n\n  return {\n    ...data,\n    nodes: newNodes,\n    edges: newEdges,\n  };\n}\n", "const EPS = 1e-3;\n\nexport interface Point {\n  x: number;\n  y: number;\n}\n\nexport type RectSide = 'top' | 'bottom' | 'left' | 'right';\n\nexport interface RectBounds {\n  left: number;\n  right: number;\n  top: number;\n  bottom: number;\n}\n\nexport interface RectEntry {\n  id: string;\n  rect: RectBounds;\n}\n\nexport interface NodeBoundsInfo extends RectEntry {\n  cx: number;\n  cy: number;\n}\n\nexport interface NodePairGeometry {\n  srcId: string;\n  dstId: string;\n  srcInfo: NodeBoundsInfo;\n  dstInfo: NodeBoundsInfo;\n  collinearX: boolean;\n  collinearY: boolean;\n}\n\nexport interface LayoutNodeRect extends RectBounds {\n  nodeId: string;\n}\n\nexport interface ThreeSegmentRoute {\n  kind: 'HVH' | 'VHV';\n  p0: Point;\n  p1: Point;\n  p2: Point;\n  p3: Point;\n}\n\nexport interface OrthogonalSegment {\n  index: number;\n  a: Point;\n  b: Point;\n  horizontal: boolean;\n  vertical: boolean;\n}\n\ninterface EdgeSegmentInput {\n  points?: Point[];\n  isLayoutOnly?: boolean;\n}\n\ninterface NodeBoundsInput {\n  id?: string;\n  x?: number;\n  y?: number;\n  width?: number;\n  height?: number;\n  isGroup?: boolean;\n  isEdgeLabel?: boolean;\n}\n\ninterface RectNodeInput {\n  x?: number;\n  y?: number;\n  width?: number;\n  height?: number;\n}\n\ninterface EdgeEndpointInput {\n  start?: string;\n  end?: string;\n}\n\ninterface SimplifyPassResult {\n  points: Point[];\n  changed: boolean;\n}\n\nfunction measuredNodeRect(node: RectNodeInput) {\n  const cx = node.x ?? 0;\n  const cy = node.y ?? 0;\n  const width = node.width ?? 0;\n  const height = node.height ?? 0;\n  return width > 0 && height > 0\n    ? { cx, cy, rect: rectFromCenterSize(cx, cy, width, height) }\n    : undefined;\n}\n\nfunction nodeBoundsInfoFor(node: NodeBoundsInput): NodeBoundsInfo | undefined {\n  if (node.isGroup) {\n    return undefined;\n  }\n  const measured = measuredNodeRect(node);\n  if (!measured) {\n    return undefined;\n  }\n  const id = String(node.id ?? '');\n  return {\n    id,\n    cx: measured.cx,\n    cy: measured.cy,\n    rect: measured.rect,\n  };\n}\n\nexport function samePoint(a: Point, b: Point, epsilon = EPS): boolean {\n  return Math.abs(a.x - b.x) < epsilon && Math.abs(a.y - b.y) < epsilon;\n}\n\nexport function sameX(a: Point, b: Point, epsilon = EPS): boolean {\n  return Math.abs(a.x - b.x) < epsilon;\n}\n\nexport function sameY(a: Point, b: Point, epsilon = EPS): boolean {\n  return Math.abs(a.y - b.y) < epsilon;\n}\n\nexport function isHorizontalSegment(a: Point, b: Point, epsilon = EPS): boolean {\n  return sameY(a, b, epsilon) && Math.abs(a.x - b.x) > epsilon;\n}\n\nexport function isVerticalSegment(a: Point, b: Point, epsilon = EPS): boolean {\n  return sameX(a, b, epsilon) && Math.abs(a.y - b.y) > epsilon;\n}\n\nexport function overlapLength(a1: number, a2: number, b1: number, b2: number): number {\n  return Math.max(\n    0,\n    Math.min(Math.max(a1, a2), Math.max(b1, b2)) - Math.max(Math.min(a1, a2), Math.min(b1, b2))\n  );\n}\n\nexport function sameAxisSegmentOverlapLength(\n  a: OrthogonalSegment,\n  b: OrthogonalSegment,\n  epsilon = EPS\n): number {\n  if (a.horizontal && b.horizontal && sameY(a.a, b.a, epsilon)) {\n    return overlapLength(a.a.x, a.b.x, b.a.x, b.b.x);\n  }\n  if (a.vertical && b.vertical && sameX(a.a, b.a, epsilon)) {\n    return overlapLength(a.a.y, a.b.y, b.a.y, b.b.y);\n  }\n  return 0;\n}\n\nexport function orthogonalSegmentsForPoints(points: Point[], epsilon = EPS): OrthogonalSegment[] {\n  const result: OrthogonalSegment[] = [];\n  for (let i = 0; i < points.length - 1; i++) {\n    const a = points[i];\n    const b = points[i + 1];\n    const horizontal = isHorizontalSegment(a, b, epsilon);\n    const vertical = isVerticalSegment(a, b, epsilon);\n    if (horizontal || vertical) {\n      result.push({ index: i, a, b, horizontal, vertical });\n    }\n  }\n  return result;\n}\n\nexport function countOrthogonalBends(points: Point[], epsilon = EPS): number {\n  const segments = orthogonalSegmentsForPoints(points, epsilon);\n  let bends = 0;\n  for (let i = 1; i < segments.length; i++) {\n    if (segments[i - 1].horizontal !== segments[i].horizontal) {\n      bends++;\n    }\n  }\n  return bends;\n}\n\nexport function dedupeConsecutivePoints(points: Point[], epsilon = EPS): Point[] {\n  const result: Point[] = [];\n  for (const point of points) {\n    const last = result.length > 0 ? result[result.length - 1] : undefined;\n    if (!last || !samePoint(last, point, epsilon)) {\n      result.push({ x: point.x, y: point.y });\n    }\n  }\n  return result;\n}\n\nexport function classifyThreeSegmentRoute(\n  points: Point[] | undefined,\n  epsilon = EPS\n): ThreeSegmentRoute | undefined {\n  if (!points || points.length !== 4) {\n    return undefined;\n  }\n  const [p0, p1, p2, p3] = points;\n  const isHVH =\n    isHorizontalSegment(p0, p1, epsilon) &&\n    isVerticalSegment(p1, p2, epsilon) &&\n    isHorizontalSegment(p2, p3, epsilon);\n  if (isHVH) {\n    return { kind: 'HVH', p0, p1, p2, p3 };\n  }\n  const isVHV =\n    isVerticalSegment(p0, p1, epsilon) &&\n    isHorizontalSegment(p1, p2, epsilon) &&\n    isVerticalSegment(p2, p3, epsilon);\n  return isVHV ? { kind: 'VHV', p0, p1, p2, p3 } : undefined;\n}\n\nexport function segmentBoundsOverlapRect(\n  a: Point,\n  b: Point,\n  rect: RectBounds,\n  buffer = 0\n): boolean {\n  const segMinX = Math.min(a.x, b.x);\n  const segMaxX = Math.max(a.x, b.x);\n  const segMinY = Math.min(a.y, b.y);\n  const segMaxY = Math.max(a.y, b.y);\n  return (\n    segMaxX > rect.left - buffer &&\n    segMinX < rect.right + buffer &&\n    segMaxY > rect.top - buffer &&\n    segMinY < rect.bottom + buffer\n  );\n}\n\nexport function pointInsideRect(point: Point, rect: RectBounds, buffer = 0): boolean {\n  return (\n    point.x > rect.left + buffer &&\n    point.x < rect.right - buffer &&\n    point.y > rect.top + buffer &&\n    point.y < rect.bottom - buffer\n  );\n}\n\nexport function rectContainsRect(outer: RectBounds, inner: RectBounds): boolean {\n  return (\n    outer.left <= inner.left &&\n    outer.right >= inner.right &&\n    outer.top <= inner.top &&\n    outer.bottom >= inner.bottom\n  );\n}\n\nexport function rectsOverlap(a: RectBounds, b: RectBounds): boolean {\n  return a.left < b.right && a.right > b.left && a.top < b.bottom && a.bottom > b.top;\n}\n\nexport function inflateRect(rect: RectBounds, margin: number): RectBounds {\n  return {\n    left: rect.left - margin,\n    right: rect.right + margin,\n    top: rect.top - margin,\n    bottom: rect.bottom + margin,\n  };\n}\n\nexport function rectFromCenterSize(\n  cx: number,\n  cy: number,\n  width: number,\n  height: number\n): RectBounds {\n  return {\n    left: cx - width / 2,\n    right: cx + width / 2,\n    top: cy - height / 2,\n    bottom: cy + height / 2,\n  };\n}\n\nexport function rectOfNodeBounds(node: RectNodeInput): RectBounds | undefined {\n  return measuredNodeRect(node)?.rect;\n}\n\nexport function portForRectSide(\n  node: { cx: number; cy: number; rect: RectBounds },\n  side: RectSide\n): Point {\n  switch (side) {\n    case 'top':\n      return { x: node.cx, y: node.rect.top };\n    case 'bottom':\n      return { x: node.cx, y: node.rect.bottom };\n    case 'left':\n      return { x: node.rect.left, y: node.cy };\n    case 'right':\n      return { x: node.rect.right, y: node.cy };\n  }\n}\n\nexport function buildOrthogonalPortPath(\n  src: Point,\n  srcSide: RectSide,\n  dst: Point,\n  dstSide: RectSide,\n  anchor: number,\n  epsilon = EPS\n): Point[] | undefined {\n  const srcH = srcSide === 'left' || srcSide === 'right';\n  const dstH = dstSide === 'left' || dstSide === 'right';\n\n  if (srcH && dstH) {\n    const opposingDir =\n      (srcSide === 'right' && dstSide === 'left' && src.x < dst.x) ||\n      (srcSide === 'left' && dstSide === 'right' && src.x > dst.x);\n    if (opposingDir) {\n      if (sameY(src, dst, epsilon)) {\n        return [src, dst];\n      }\n      const midX = (src.x + dst.x) / 2;\n      return [src, { x: midX, y: src.y }, { x: midX, y: dst.y }, dst];\n    }\n    if (srcSide === dstSide) {\n      if (sameY(src, dst, epsilon)) {\n        return undefined;\n      }\n      const intX =\n        srcSide === 'left' ? Math.min(src.x, dst.x) - anchor : Math.max(src.x, dst.x) + anchor;\n      return [src, { x: intX, y: src.y }, { x: intX, y: dst.y }, dst];\n    }\n    return undefined;\n  }\n\n  if (!srcH && !dstH) {\n    if (srcSide === dstSide) {\n      if (sameX(src, dst, epsilon)) {\n        return undefined;\n      }\n      const intY =\n        srcSide === 'top' ? Math.min(src.y, dst.y) - anchor : Math.max(src.y, dst.y) + anchor;\n      return [src, { x: src.x, y: intY }, { x: dst.x, y: intY }, dst];\n    }\n    const sameDir =\n      (srcSide === 'bottom' && dstSide === 'top' && src.y < dst.y) ||\n      (srcSide === 'top' && dstSide === 'bottom' && src.y > dst.y);\n    if (!sameDir) {\n      return undefined;\n    }\n    if (sameX(src, dst, epsilon)) {\n      return [src, dst];\n    }\n    const midY = (src.y + dst.y) / 2;\n    return [src, { x: src.x, y: midY }, { x: dst.x, y: midY }, dst];\n  }\n\n  if (srcH && !dstH) {\n    const sameDirSrc =\n      (srcSide === 'right' && dst.x > src.x) || (srcSide === 'left' && dst.x < src.x);\n    const sameDirDst =\n      (dstSide === 'top' && src.y < dst.y) || (dstSide === 'bottom' && src.y > dst.y);\n    return sameDirSrc && sameDirDst ? [src, { x: dst.x, y: src.y }, dst] : undefined;\n  }\n\n  const sameDirSrc =\n    (srcSide === 'bottom' && dst.y > src.y) || (srcSide === 'top' && dst.y < src.y);\n  const sameDirDst =\n    (dstSide === 'left' && src.x < dst.x) || (dstSide === 'right' && src.x > dst.x);\n  return sameDirSrc && sameDirDst ? [src, { x: src.x, y: dst.y }, dst] : undefined;\n}\n\nexport function buildSameSideTrackPath(\n  src: Point,\n  side: RectSide,\n  dst: Point,\n  track: number\n): Point[] {\n  return side === 'left' || side === 'right'\n    ? [src, { x: track, y: src.y }, { x: track, y: dst.y }, dst]\n    : [src, { x: src.x, y: track }, { x: dst.x, y: track }, dst];\n}\n\nexport function collectRealNodeBounds(nodes: Iterable<NodeBoundsInput>): {\n  nodeInfoById: Map<string, NodeBoundsInfo>;\n  realNodeRects: RectEntry[];\n} {\n  const nodeInfoById = new Map<string, NodeBoundsInfo>();\n  const realNodeRects: RectEntry[] = [];\n  for (const node of nodes) {\n    if (node.isEdgeLabel) {\n      continue;\n    }\n    const info = nodeBoundsInfoFor(node);\n    if (!info) {\n      continue;\n    }\n    nodeInfoById.set(info.id, info);\n    realNodeRects.push({ id: info.id, rect: info.rect });\n  }\n  return { nodeInfoById, realNodeRects };\n}\n\nexport function collectNodeRectEntries(nodes: Iterable<NodeBoundsInput>): {\n  realNodeRects: RectEntry[];\n  labelNodeRects: RectEntry[];\n} {\n  const realNodeRects: RectEntry[] = [];\n  const labelNodeRects: RectEntry[] = [];\n  for (const node of nodes) {\n    const info = nodeBoundsInfoFor(node);\n    if (!info) {\n      continue;\n    }\n    const entry = { id: info.id, rect: info.rect };\n    if (node.isEdgeLabel) {\n      labelNodeRects.push(entry);\n    } else {\n      realNodeRects.push(entry);\n    }\n  }\n  return { realNodeRects, labelNodeRects };\n}\n\nexport function collectLayoutNodeRects(\n  nodes: Iterable<NodeBoundsInput>,\n  { includeEdgeLabels = true }: { includeEdgeLabels?: boolean } = {}\n): LayoutNodeRect[] {\n  const result: LayoutNodeRect[] = [];\n  for (const node of nodes) {\n    if (node.isGroup || (!includeEdgeLabels && node.isEdgeLabel)) {\n      continue;\n    }\n    const cx = node.x ?? 0;\n    const cy = node.y ?? 0;\n    const width = node.width ?? 0;\n    const height = node.height ?? 0;\n    result.push({\n      nodeId: node.id!,\n      ...rectFromCenterSize(cx, cy, width, height),\n    });\n  }\n  return result;\n}\n\nexport function getNodePairGeometry(\n  edge: EdgeEndpointInput,\n  nodeInfoById: Map<string, NodeBoundsInfo>,\n  epsilon = EPS\n): NodePairGeometry | undefined {\n  const srcId = edge.start;\n  const dstId = edge.end;\n  if (!srcId || !dstId) {\n    return undefined;\n  }\n  const srcInfo = nodeInfoById.get(srcId);\n  const dstInfo = nodeInfoById.get(dstId);\n  if (!srcInfo || !dstInfo) {\n    return undefined;\n  }\n  return {\n    srcId,\n    dstId,\n    srcInfo,\n    dstInfo,\n    collinearX: Math.abs(srcInfo.cx - dstInfo.cx) < epsilon,\n    collinearY: Math.abs(srcInfo.cy - dstInfo.cy) < epsilon,\n  };\n}\n\nexport function segmentHitsAnyRect(\n  a: Point,\n  b: Point,\n  rects: RectEntry[],\n  excludeIds: string[] = [],\n  shrink = 0\n): boolean {\n  for (const entry of rects) {\n    if (excludeIds.includes(entry.id)) {\n      continue;\n    }\n    if (segmentBoundsOverlapRect(a, b, entry.rect, -shrink)) {\n      return true;\n    }\n  }\n  return false;\n}\n\nexport function orthogonalSegmentsCross(\n  a1: Point,\n  b1: Point,\n  a2: Point,\n  b2: Point,\n  epsilon = EPS,\n  endpointTolerance = 1e-6\n): boolean {\n  const s1H = sameY(a1, b1, epsilon);\n  const s1V = sameX(a1, b1, epsilon);\n  const s2H = sameY(a2, b2, epsilon);\n  const s2V = sameX(a2, b2, epsilon);\n  if ((s1H && s2H) || (s1V && s2V)) {\n    return false;\n  }\n  if (!(s1H || s1V) || !(s2H || s2V)) {\n    return false;\n  }\n\n  const horiz = s1H ? { a: a1, b: b1 } : { a: a2, b: b2 };\n  const vert = s1V ? { a: a1, b: b1 } : { a: a2, b: b2 };\n  const hY = horiz.a.y;\n  const hX1 = Math.min(horiz.a.x, horiz.b.x);\n  const hX2 = Math.max(horiz.a.x, horiz.b.x);\n  const vX = vert.a.x;\n  const vY1 = Math.min(vert.a.y, vert.b.y);\n  const vY2 = Math.max(vert.a.y, vert.b.y);\n  if (vX < hX1 || vX > hX2 || hY < vY1 || hY > vY2) {\n    return false;\n  }\n\n  const matchesHorizEndpoint =\n    (Math.abs(vX - horiz.a.x) < endpointTolerance &&\n      Math.abs(hY - horiz.a.y) < endpointTolerance) ||\n    (Math.abs(vX - horiz.b.x) < endpointTolerance && Math.abs(hY - horiz.b.y) < endpointTolerance);\n  const matchesVertEndpoint =\n    (Math.abs(vX - vert.a.x) < endpointTolerance && Math.abs(hY - vert.a.y) < endpointTolerance) ||\n    (Math.abs(vX - vert.b.x) < endpointTolerance && Math.abs(hY - vert.b.y) < endpointTolerance);\n  return !(matchesHorizEndpoint && matchesVertEndpoint);\n}\n\nexport function sameAxisSegmentsOverlap(\n  a1: Point,\n  b1: Point,\n  a2: Point,\n  b2: Point,\n  epsilon = EPS\n): boolean {\n  const s1H = sameY(a1, b1, epsilon);\n  const s1V = sameX(a1, b1, epsilon);\n  const s2H = sameY(a2, b2, epsilon);\n  const s2V = sameX(a2, b2, epsilon);\n  if (s1V && s2V && sameX(a1, a2, epsilon)) {\n    return overlapLength(a1.y, b1.y, a2.y, b2.y) > epsilon;\n  }\n  if (s1H && s2H && sameY(a1, a2, epsilon)) {\n    return overlapLength(a1.x, b1.x, a2.x, b2.x) > epsilon;\n  }\n  return false;\n}\n\nexport function segmentConflictsWithAnyEdge(\n  a: Point,\n  b: Point,\n  edges: Iterable<EdgeSegmentInput>,\n  excludeEdge?: EdgeSegmentInput,\n  {\n    epsilon = EPS,\n    skipDegenerateOther = false,\n  }: { epsilon?: number; skipDegenerateOther?: boolean } = {}\n): boolean {\n  for (const other of edges) {\n    if (other === excludeEdge || other.isLayoutOnly) {\n      continue;\n    }\n    const points = other.points;\n    if (!points || points.length < 2) {\n      continue;\n    }\n    for (let i = 0; i < points.length - 1; i++) {\n      const oa = points[i];\n      const ob = points[i + 1];\n      if (skipDegenerateOther && samePoint(oa, ob, epsilon)) {\n        continue;\n      }\n      if (\n        orthogonalSegmentsCross(a, b, oa, ob, epsilon) ||\n        sameAxisSegmentsOverlap(a, b, oa, ob, epsilon)\n      ) {\n        return true;\n      }\n    }\n  }\n  return false;\n}\n\nexport function orthogonalSegmentsStrictlyCross(\n  a1: Point,\n  b1: Point,\n  a2: Point,\n  b2: Point,\n  epsilon = EPS\n): boolean {\n  const aHoriz = sameY(a1, b1, epsilon);\n  const aVert = sameX(a1, b1, epsilon);\n  const bHoriz = sameY(a2, b2, epsilon);\n  const bVert = sameX(a2, b2, epsilon);\n  if (!((aHoriz && bVert) || (aVert && bHoriz))) {\n    return false;\n  }\n\n  const horiz = aHoriz ? { a: a1, b: b1 } : { a: a2, b: b2 };\n  const vert = aHoriz ? { a: a2, b: b2 } : { a: a1, b: b1 };\n  const hY = horiz.a.y;\n  const hXmin = Math.min(horiz.a.x, horiz.b.x);\n  const hXmax = Math.max(horiz.a.x, horiz.b.x);\n  const vX = vert.a.x;\n  const vYmin = Math.min(vert.a.y, vert.b.y);\n  const vYmax = Math.max(vert.a.y, vert.b.y);\n  return (\n    vX > hXmin + epsilon && vX < hXmax - epsilon && hY > vYmin + epsilon && hY < vYmax - epsilon\n  );\n}\n\nfunction strictlyBetween(value: number, a: number, b: number): boolean {\n  const lo = Math.min(a, b);\n  const hi = Math.max(a, b);\n  return value > lo + EPS && value < hi - EPS;\n}\n\nfunction isCollinearIntermediate(prev: Point, cur: Point, next: Point): boolean {\n  if (sameX(prev, cur) && sameX(cur, next)) {\n    return strictlyBetween(cur.y, prev.y, next.y);\n  }\n\n  if (sameY(prev, cur) && sameY(cur, next)) {\n    return strictlyBetween(cur.x, prev.x, next.x);\n  }\n\n  return false;\n}\n\nfunction simplifyPolylineOnce(points: Point[]): SimplifyPassResult {\n  let changed = false;\n  const out: Point[] = [];\n\n  for (let i = 0; i < points.length; i++) {\n    const prev = out[out.length - 1];\n    const cur = points[i];\n    const next = i + 1 < points.length ? points[i + 1] : undefined;\n    if (prev && next) {\n      if (samePoint(prev, next)) {\n        i++;\n        changed = true;\n        continue;\n      }\n\n      if (isCollinearIntermediate(prev, cur, next)) {\n        changed = true;\n        continue;\n      }\n    }\n    out.push(cur);\n  }\n\n  return { points: out, changed };\n}\n\n// Inserts orthogonal L-bends and removes consecutive duplicate points.\nexport function orthogonalizePolyline(pts: Point[]): Point[] {\n  const cleaned: Point[] = [pts[0]];\n  for (let i = 1; i < pts.length; i++) {\n    const prev = cleaned[cleaned.length - 1];\n    const curr = pts[i];\n    if (!sameX(prev, curr) && !sameY(prev, curr)) {\n      const prevPrev = cleaned.length >= 2 ? cleaned[cleaned.length - 2] : undefined;\n      const incomingVertical = prevPrev ? sameX(prevPrev, prev) : false;\n      const corner = incomingVertical ? { x: prev.x, y: curr.y } : { x: curr.x, y: prev.y };\n      cleaned.push(corner);\n    }\n    cleaned.push(curr);\n  }\n  const deduped: Point[] = [];\n  for (const p of cleaned) {\n    const last = deduped[deduped.length - 1];\n    if (!last || !samePoint(last, p)) {\n      deduped.push(p);\n    }\n  }\n  return deduped;\n}\n\nexport function simplifyPolyline(pts: Point[]): Point[] {\n  if (pts.length < 3) {\n    return pts;\n  }\n  let work = [...pts];\n  for (let guard = 0; guard < 32; guard++) {\n    const result = simplifyPolylineOnce(work);\n    work = result.points;\n    if (!result.changed) {\n      break;\n    }\n  }\n  return work;\n}\n", "import {\n  dedupeConsecutivePoints,\n  orthogonalizePolyline,\n  pointInsideRect,\n  rectOfNodeBounds,\n  samePoint,\n  sameX,\n  sameY,\n  simplifyPolyline,\n} from './geometry.js';\nimport type { Point, RectBounds } from './geometry.js';\n\nconst EPS = 1e-3;\nconst INSIDE_EPS = 0.5;\nconst CORNER_CLEARANCE = 4;\n\ntype NodeRect = RectBounds;\n\ntype BorderSide = 'top' | 'bottom' | 'left' | 'right';\n\ninterface EndpointEdge {\n  isLayoutOnly?: boolean;\n  points?: Point[];\n  start?: string;\n  end?: string;\n}\n\nfunction endpointContextFor(edge: unknown, nodeByIdMap: Map<string, any>, minPoints: number) {\n  const candidate = edge as EndpointEdge;\n  if (candidate.isLayoutOnly || !candidate.points || candidate.points.length < minPoints) {\n    return undefined;\n  }\n  const src = candidate.start ? nodeByIdMap.get(candidate.start) : undefined;\n  const dst = candidate.end ? nodeByIdMap.get(candidate.end) : undefined;\n  return {\n    edge: candidate,\n    points: candidate.points,\n    srcRect: src ? rectOfNodeBounds(src) : undefined,\n    dstRect: dst ? rectOfNodeBounds(dst) : undefined,\n  };\n}\n\n// Given an axis-aligned segment from outside a rect to inside it, return the\n// point where the segment enters the rect boundary.\nfunction segmentEnterPoint(outside: Point, inside: Point, r: NodeRect): Point {\n  if (sameY(outside, inside, EPS)) {\n    const x = outside.x < r.left ? r.left : r.right;\n    return { x, y: outside.y };\n  }\n  if (sameX(outside, inside, EPS)) {\n    const y = outside.y < r.top ? r.top : r.bottom;\n    return { x: outside.x, y };\n  }\n  return {\n    x: Math.min(r.right, Math.max(r.left, outside.x)),\n    y: Math.min(r.bottom, Math.max(r.top, outside.y)),\n  };\n}\n\nfunction clipEndpoint(points: Point[], rect: NodeRect, atStart: boolean): Point[] {\n  const step = atStart ? 1 : -1;\n  let outsideIndex = atStart ? 0 : points.length - 1;\n  while (\n    outsideIndex >= 0 &&\n    outsideIndex < points.length &&\n    pointInsideRect(points[outsideIndex], rect, INSIDE_EPS)\n  ) {\n    outsideIndex += step;\n  }\n  if (outsideIndex < 0 || outsideIndex >= points.length) {\n    return points;\n  }\n\n  const insideIndex = outsideIndex - step;\n  if (insideIndex < 0 || insideIndex >= points.length) {\n    return points;\n  }\n\n  const entry = segmentEnterPoint(points[outsideIndex], points[insideIndex], rect);\n  return atStart\n    ? [entry, ...points.slice(outsideIndex)]\n    : [...points.slice(0, outsideIndex + 1), entry];\n}\n\nexport function clipEdgeEndpointsToNodeBoundaries(edges: unknown[], nodeByIdMap: Map<string, any>) {\n  for (const edge of edges) {\n    const context = endpointContextFor(edge, nodeByIdMap, 2);\n    if (!context) {\n      continue;\n    }\n\n    let next = [...context.points];\n    if (context.srcRect) {\n      next = clipEndpoint(next, context.srcRect, true);\n    }\n    if (context.dstRect) {\n      next = clipEndpoint(next, context.dstRect, false);\n    }\n    next = simplifyPolyline(orthogonalizePolyline(next));\n    next = clearStraightEndpointCornerConnections(next, context.srcRect, context.dstRect);\n    context.edge.points = simplifyPolyline(orthogonalizePolyline(next));\n  }\n}\n\nfunction snapEndpointToBoundary(\n  inner: Point,\n  endpoint: Point,\n  r: NodeRect,\n  useApproachSide = false\n): Point {\n  if (sameY(inner, endpoint, EPS)) {\n    if (endpoint.y < r.top - EPS || endpoint.y > r.bottom + EPS) {\n      return endpoint;\n    }\n    if (useApproachSide) {\n      if (inner.x < r.left - EPS) {\n        return { x: r.left, y: inner.y };\n      }\n      if (inner.x > r.right + EPS) {\n        return { x: r.right, y: inner.y };\n      }\n    }\n    const toLeft = Math.abs(endpoint.x - r.left) <= Math.abs(endpoint.x - r.right);\n    return { x: toLeft ? r.left : r.right, y: inner.y };\n  }\n  if (sameX(inner, endpoint, EPS)) {\n    if (endpoint.x < r.left - EPS || endpoint.x > r.right + EPS) {\n      return endpoint;\n    }\n    if (useApproachSide) {\n      if (inner.y < r.top - EPS) {\n        return { x: inner.x, y: r.top };\n      }\n      if (inner.y > r.bottom + EPS) {\n        return { x: inner.x, y: r.bottom };\n      }\n    }\n    const toTop = Math.abs(endpoint.y - r.top) <= Math.abs(endpoint.y - r.bottom);\n    return { x: inner.x, y: toTop ? r.top : r.bottom };\n  }\n  return endpoint;\n}\n\nfunction firstDistinctAdjacent(\n  points: Point[],\n  endpointIndex: number,\n  step: 1 | -1\n): Point | undefined {\n  const endpoint = points[endpointIndex];\n  for (let index = endpointIndex + step; index >= 0 && index < points.length; index += step) {\n    const candidate = points[index];\n    if (!samePoint(candidate, endpoint, EPS)) {\n      return candidate;\n    }\n  }\n  return points[endpointIndex + step];\n}\n\nfunction cornerClearanceRange(min: number, max: number): { lo: number; hi: number } {\n  const lo = min + CORNER_CLEARANCE;\n  const hi = max - CORNER_CLEARANCE;\n  return lo <= hi ? { lo, hi } : { lo: (min + max) / 2, hi: (min + max) / 2 };\n}\n\nfunction clampToCornerClearance(value: number, min: number, max: number): number {\n  const { lo, hi } = cornerClearanceRange(min, max);\n  return Math.min(hi, Math.max(lo, value));\n}\n\nfunction intersectRanges(\n  ranges: { lo: number; hi: number }[]\n): { lo: number; hi: number } | undefined {\n  const lo = Math.max(...ranges.map((range) => range.lo));\n  const hi = Math.min(...ranges.map((range) => range.hi));\n  if (lo > hi) {\n    return undefined;\n  }\n  return { lo, hi };\n}\n\nfunction clearanceRangeForSide(r: NodeRect, side: BorderSide): { lo: number; hi: number } {\n  return side === 'left' || side === 'right'\n    ? cornerClearanceRange(r.top, r.bottom)\n    : cornerClearanceRange(r.left, r.right);\n}\n\nfunction terminalSideForSegment(\n  endpoint: Point,\n  adjacent: Point,\n  r: NodeRect\n): BorderSide | undefined {\n  const yWithin = endpoint.y >= r.top - EPS && endpoint.y <= r.bottom + EPS;\n  const xWithin = endpoint.x >= r.left - EPS && endpoint.x <= r.right + EPS;\n  if (sameY(endpoint, adjacent, EPS) && yWithin) {\n    if (Math.abs(endpoint.x - r.left) < EPS) {\n      return 'left';\n    }\n    if (Math.abs(endpoint.x - r.right) < EPS) {\n      return 'right';\n    }\n  }\n  if (sameX(endpoint, adjacent, EPS) && xWithin) {\n    if (Math.abs(endpoint.y - r.top) < EPS) {\n      return 'top';\n    }\n    if (Math.abs(endpoint.y - r.bottom) < EPS) {\n      return 'bottom';\n    }\n  }\n  return undefined;\n}\n\nfunction isHorizontalSide(side: BorderSide): boolean {\n  return side === 'left' || side === 'right';\n}\n\nfunction straightClearanceRange(\n  start: Point,\n  end: Point,\n  srcRect: NodeRect | undefined,\n  dstRect: NodeRect | undefined,\n  horizontal: boolean\n): { lo: number; hi: number } | undefined {\n  const ranges: { lo: number; hi: number }[] = [];\n  const srcSide = srcRect ? terminalSideForSegment(start, end, srcRect) : undefined;\n  const dstSide = dstRect ? terminalSideForSegment(end, start, dstRect) : undefined;\n\n  if (srcRect && srcSide && isHorizontalSide(srcSide) === horizontal) {\n    ranges.push(clearanceRangeForSide(srcRect, srcSide));\n  }\n  if (dstRect && dstSide && isHorizontalSide(dstSide) === horizontal) {\n    ranges.push(clearanceRangeForSide(dstRect, dstSide));\n  }\n\n  return ranges.length > 0 ? intersectRanges(ranges) : undefined;\n}\n\nfunction clearStraightEndpointCornerAxis(\n  start: Point,\n  end: Point,\n  srcRect: NodeRect | undefined,\n  dstRect: NodeRect | undefined,\n  horizontal: boolean\n): Point[] | undefined {\n  const range = straightClearanceRange(start, end, srcRect, dstRect, horizontal);\n  if (!range) {\n    return undefined;\n  }\n\n  const current = horizontal ? start.y : start.x;\n  const next = Math.min(range.hi, Math.max(range.lo, current));\n  if (Math.abs(next - current) < EPS) {\n    return undefined;\n  }\n\n  return horizontal\n    ? [\n        { x: start.x, y: next },\n        { x: end.x, y: next },\n      ]\n    : [\n        { x: next, y: start.y },\n        { x: next, y: end.y },\n      ];\n}\n\nfunction clearStraightEndpointCornerConnections(\n  points: Point[],\n  srcRect?: NodeRect,\n  dstRect?: NodeRect\n): Point[] {\n  if (points.length !== 2) {\n    return points;\n  }\n\n  const [start, end] = points;\n  if (sameY(start, end, EPS)) {\n    return clearStraightEndpointCornerAxis(start, end, srcRect, dstRect, true) ?? points;\n  }\n\n  if (sameX(start, end, EPS)) {\n    return clearStraightEndpointCornerAxis(start, end, srcRect, dstRect, false) ?? points;\n  }\n\n  return points;\n}\n\nfunction cornerClearedEndpoint(endpoint: Point, r: NodeRect, side: BorderSide): Point {\n  return isHorizontalSide(side)\n    ? { x: endpoint.x, y: clampToCornerClearance(endpoint.y, r.top, r.bottom) }\n    : { x: clampToCornerClearance(endpoint.x, r.left, r.right), y: endpoint.y };\n}\n\nfunction moveCollinearEndpointRun(\n  points: Point[],\n  endpointIndex: number,\n  step: 1 | -1,\n  endpoint: Point,\n  adjusted: Point,\n  horizontalTerminal: boolean\n): Point[] {\n  const next = points.map((point) => ({ ...point }));\n  for (let index = endpointIndex; index >= 0 && index < points.length; index += step) {\n    const point = points[index];\n    if (horizontalTerminal && !sameY(point, endpoint, EPS)) {\n      break;\n    }\n    if (!horizontalTerminal && !sameX(point, endpoint, EPS)) {\n      break;\n    }\n    if (horizontalTerminal) {\n      next[index].y = adjusted.y;\n    } else {\n      next[index].x = adjusted.x;\n    }\n  }\n  return next;\n}\n\nfunction clearEndpointCornerConnection(points: Point[], r: NodeRect, atStart: boolean): Point[] {\n  if (points.length < 2) {\n    return points;\n  }\n\n  const endpointIndex = atStart ? 0 : points.length - 1;\n  const step = atStart ? 1 : -1;\n  const endpoint = points[endpointIndex];\n  const adjacent = firstDistinctAdjacent(points, endpointIndex, step);\n  if (!adjacent) {\n    return points;\n  }\n\n  const side = terminalSideForSegment(endpoint, adjacent, r);\n  if (!side) {\n    return points;\n  }\n\n  const horizontalTerminal = isHorizontalSide(side);\n  const adjusted = cornerClearedEndpoint(endpoint, r, side);\n  if (samePoint(endpoint, adjusted, EPS)) {\n    return points;\n  }\n\n  return moveCollinearEndpointRun(\n    points,\n    endpointIndex,\n    step,\n    endpoint,\n    adjusted,\n    horizontalTerminal\n  );\n}\n\nfunction borderSideForSegment(a: Point, b: Point, r: NodeRect): BorderSide | undefined {\n  const xWithin = Math.min(a.x, b.x) >= r.left - EPS && Math.max(a.x, b.x) <= r.right + EPS;\n  const yWithin = Math.min(a.y, b.y) >= r.top - EPS && Math.max(a.y, b.y) <= r.bottom + EPS;\n  if (Math.abs(a.y - r.top) < EPS && Math.abs(b.y - r.top) < EPS && xWithin) {\n    return 'top';\n  }\n  if (Math.abs(a.y - r.bottom) < EPS && Math.abs(b.y - r.bottom) < EPS && xWithin) {\n    return 'bottom';\n  }\n  if (Math.abs(a.x - r.left) < EPS && Math.abs(b.x - r.left) < EPS && yWithin) {\n    return 'left';\n  }\n  if (Math.abs(a.x - r.right) < EPS && Math.abs(b.x - r.right) < EPS && yWithin) {\n    return 'right';\n  }\n  return undefined;\n}\n\nfunction leavesOutward(side: BorderSide, from: Point, to: Point, r: NodeRect): boolean {\n  switch (side) {\n    case 'top':\n      return sameX(from, to, EPS) && to.y < r.top - EPS;\n    case 'bottom':\n      return sameX(from, to, EPS) && to.y > r.bottom + EPS;\n    case 'left':\n      return sameY(from, to, EPS) && to.x < r.left - EPS;\n    case 'right':\n      return sameY(from, to, EPS) && to.x > r.right + EPS;\n  }\n}\n\nfunction collapseOwnBorderStub(points: Point[], r: NodeRect, atStart: boolean): Point[] {\n  if (points.length < 3) {\n    return points;\n  }\n  if (atStart) {\n    const side = borderSideForSegment(points[0], points[1], r);\n    if (side && leavesOutward(side, points[1], points[2], r)) {\n      return points.slice(1);\n    }\n    return points;\n  }\n\n  const last = points.length - 1;\n  const side = borderSideForSegment(points[last - 1], points[last], r);\n  if (side && leavesOutward(side, points[last - 1], points[last - 2], r)) {\n    return points.slice(0, last);\n  }\n  return points;\n}\n\nfunction snapAndCollapseEndpoints(\n  points: Point[],\n  srcRect?: NodeRect,\n  dstRect?: NodeRect\n): Point[] {\n  let next = points;\n  if (srcRect) {\n    const adjacent = firstDistinctAdjacent(next, 0, 1);\n    if (adjacent) {\n      const snapped = snapEndpointToBoundary(adjacent, next[0], srcRect);\n      if (snapped !== next[0]) {\n        next = [snapped, ...next.slice(1)];\n      }\n    }\n    next = collapseOwnBorderStub(next, srcRect, true);\n  }\n  if (dstRect) {\n    const last = next.length - 1;\n    const adjacent = firstDistinctAdjacent(next, last, -1);\n    if (adjacent) {\n      const snapped = snapEndpointToBoundary(adjacent, next[last], dstRect, true);\n      if (snapped !== next[last]) {\n        next = [...next.slice(0, last), snapped];\n      }\n    }\n    next = collapseOwnBorderStub(next, dstRect, false);\n  }\n\n  const straightCleared = clearStraightEndpointCornerConnections(next, srcRect, dstRect);\n  if (straightCleared !== next || next.length === 2) {\n    return straightCleared;\n  }\n\n  if (srcRect) {\n    next = clearEndpointCornerConnection(next, srcRect, true);\n  }\n  if (dstRect) {\n    next = clearEndpointCornerConnection(next, dstRect, false);\n  }\n  return next;\n}\n\nexport function prepareEdgeEndpointsForRenderer(edges: unknown[], nodeByIdMap: Map<string, any>) {\n  for (const edge of edges) {\n    const context = endpointContextFor(edge, nodeByIdMap, 2);\n    if (!context) {\n      continue;\n    }\n\n    const input = dedupeConsecutivePoints(context.points, EPS);\n    const newPts = snapAndCollapseEndpoints(input, context.srcRect, context.dstRect);\n    if (newPts.length < 3) {\n      context.edge.points = newPts;\n      continue;\n    }\n    const duplicated = [\n      newPts[0],\n      { ...newPts[0] },\n      ...newPts.slice(1, -1),\n      newPts[newPts.length - 1],\n      { ...newPts[newPts.length - 1] },\n    ];\n    context.edge.points = duplicated;\n  }\n}\n", "import type { LayoutData } from '../../../types.js';\n\ntype LayoutNode = NonNullable<LayoutData['nodes']>[number] & { swimlaneContentTop?: number };\ntype Direction = 'LR' | 'RL';\ntype Axis = 'x' | 'y';\n\nfunction buildNodeMap(nodes: LayoutNode[]): Map<string, LayoutNode> {\n  return new Map(nodes.map((node) => [node.id, node]));\n}\n\nfunction resolveTopLevelGroupId(\n  node: LayoutNode,\n  nodeById: Map<string, LayoutNode>\n): string | null {\n  let parentId = node.parentId;\n  let topLevelGroupId: string | null = null;\n  while (parentId) {\n    const parent = nodeById.get(parentId);\n    if (!parent?.isGroup) {\n      break;\n    }\n    topLevelGroupId = parent.id;\n    parentId = parent.parentId;\n  }\n  return topLevelGroupId;\n}\n\nfunction groupDepth(group: LayoutNode, nodeById: Map<string, LayoutNode>): number {\n  let depth = 0;\n  let parentId = group.parentId;\n  while (parentId) {\n    const parent = nodeById.get(parentId);\n    if (!parent?.isGroup) {\n      break;\n    }\n    depth++;\n    parentId = parent.parentId;\n  }\n  return depth;\n}\n\nfunction boundsForChildren(\n  children: LayoutNode[]\n): { minX: number; maxX: number; minY: number; maxY: number } | null {\n  let minX = Infinity;\n  let maxX = -Infinity;\n  let minY = Infinity;\n  let maxY = -Infinity;\n  for (const child of children) {\n    const cx = child.x;\n    const cy = child.y;\n    if (typeof cx !== 'number' || typeof cy !== 'number') {\n      continue;\n    }\n    const w = child.width ?? 0;\n    const h = child.height ?? 0;\n    minX = Math.min(minX, cx - w / 2);\n    maxX = Math.max(maxX, cx + w / 2);\n    minY = Math.min(minY, cy - h / 2);\n    maxY = Math.max(maxY, cy + h / 2);\n  }\n  if (minX === Infinity || minY === Infinity) {\n    return null;\n  }\n  return { minX, maxX, minY, maxY };\n}\n\nfunction applyGroupBounds(\n  group: LayoutNode,\n  bounds: NonNullable<ReturnType<typeof boundsForChildren>>\n) {\n  const pad = group.padding ?? 20;\n  group.x = (bounds.minX + bounds.maxX) / 2;\n  group.y = (bounds.minY + bounds.maxY) / 2;\n  group.width = Math.max(0, bounds.maxX - bounds.minX) + pad;\n  group.height = Math.max(0, bounds.maxY - bounds.minY) + pad;\n}\n\nfunction recomputeNestedGroupBounds(nodes: LayoutNode[]): void {\n  const nodeById = buildNodeMap(nodes);\n  const groupsByDepth = nodes\n    .filter((node) => node.isGroup && node.parentId)\n    .sort((a, b) => groupDepth(b, nodeById) - groupDepth(a, nodeById));\n\n  for (const group of groupsByDepth) {\n    const children = nodes.filter((node) => node.parentId === group.id);\n    const bounds = boundsForChildren(children);\n    if (bounds) {\n      applyGroupBounds(group, bounds);\n    }\n  }\n}\n\nfunction mirrorAxis(layout: LayoutData, axis: Axis): boolean {\n  const nodes = (layout.nodes ?? []) as LayoutNode[];\n  const edges = layout.edges ?? [];\n  const contentNodes = nodes.filter((node) => !node.isGroup);\n  let min = Infinity;\n  let max = -Infinity;\n  for (const node of contentNodes) {\n    const value = node[axis];\n    if (typeof value !== 'number') {\n      continue;\n    }\n    min = Math.min(min, value);\n    max = Math.max(max, value);\n  }\n  if (!Number.isFinite(min) || !Number.isFinite(max)) {\n    return false;\n  }\n  const mirror = (value: number) => min + max - value;\n  for (const node of nodes) {\n    const value = node[axis];\n    if (typeof value === 'number') {\n      node[axis] = mirror(value);\n    }\n    const titleRect = node.groupTitleRect;\n    if (titleRect) {\n      node.groupTitleRect =\n        axis === 'x'\n          ? {\n              ...titleRect,\n              left: mirror(titleRect.right),\n              right: mirror(titleRect.left),\n            }\n          : {\n              ...titleRect,\n              top: mirror(titleRect.bottom),\n              bottom: mirror(titleRect.top),\n            };\n    }\n  }\n  for (const edge of edges) {\n    for (const point of edge.points ?? []) {\n      point[axis] = mirror(point[axis]);\n    }\n  }\n  return true;\n}\n\nexport function applyBtDirectionTransform(layout: LayoutData): boolean {\n  const nodes = (layout.nodes ?? []) as LayoutNode[];\n  if (!nodes.some((node) => !node.isGroup)) {\n    return true;\n  }\n\n  return mirrorAxis(layout, 'y');\n}\n\nexport function applyLrDirectionTransform(\n  layout: LayoutData,\n  direction: Direction = 'LR'\n): boolean {\n  const nodes = (layout.nodes ?? []) as LayoutNode[];\n  const edges = layout.edges ?? [];\n  const contentNodes = nodes.filter((n) => !n.isGroup);\n\n  let minX = Infinity;\n  let minY = Infinity;\n  for (const n of contentNodes) {\n    const x0 = n.x ?? 0;\n    const y0 = n.y ?? 0;\n    if (x0 < minX) {\n      minX = x0;\n    }\n    if (y0 < minY) {\n      minY = y0;\n    }\n  }\n\n  if (!Number.isFinite(minX) || !Number.isFinite(minY)) {\n    return false;\n  }\n\n  const titleBandSize = 36;\n\n  let totalWidth = 0;\n  let totalHeight = 0;\n  for (const n of contentNodes) {\n    totalWidth += n.width ?? 0;\n    totalHeight += n.height ?? 0;\n  }\n  const avgWidth = totalWidth / contentNodes.length;\n  const avgHeight = totalHeight / contentNodes.length;\n  const horizontalScaleFactor = avgHeight > 0 ? Math.max(1, avgWidth / avgHeight) : 1;\n\n  for (const n of contentNodes) {\n    const x0 = n.x ?? 0;\n    const y0 = n.y ?? 0;\n    const newX = (y0 - minY) * horizontalScaleFactor + titleBandSize;\n    const newY = x0 - minX;\n\n    n.x = newX;\n    n.y = newY;\n  }\n\n  for (const e of edges) {\n    if (!e.points) {\n      continue;\n    }\n    for (const p of e.points) {\n      const x0 = p.x;\n      const y0 = p.y;\n      const newX = (y0 - minY) * horizontalScaleFactor + titleBandSize;\n      const newY = x0 - minX;\n      p.x = newX;\n      p.y = newY;\n    }\n  }\n\n  recomputeNestedGroupBounds(nodes);\n\n  const laneNodes = nodes.filter((n) => n.isGroup && !n.parentId);\n  if (laneNodes.length === 0) {\n    if (direction === 'RL') {\n      mirrorAxis(layout, 'x');\n    }\n    return true;\n  }\n\n  const nodeById = buildNodeMap(nodes);\n  const childrenByLane = new Map<string, LayoutNode[]>();\n\n  for (const n of nodes) {\n    if (n.isGroup) {\n      continue;\n    }\n    const laneId = resolveTopLevelGroupId(n, nodeById);\n    if (!laneId) {\n      continue;\n    }\n    const bucket = childrenByLane.get(laneId) ?? [];\n    bucket.push(n);\n    childrenByLane.set(laneId, bucket);\n  }\n\n  let maxPad = 0;\n  for (const lane of laneNodes) {\n    const pad = lane.padding ?? 0;\n    if (pad > maxPad) {\n      maxPad = pad;\n    }\n  }\n\n  const laneBounds: {\n    lane: LayoutNode;\n    contentTop: number;\n    contentBottom: number;\n    centerY: number;\n  }[] = [];\n  let globalMinXChild = Infinity;\n  let globalMaxXChild = -Infinity;\n\n  for (const lane of laneNodes) {\n    const children = childrenByLane.get(lane.id) ?? [];\n    const bounds = boundsForChildren(children);\n    if (!bounds) {\n      continue;\n    }\n    globalMinXChild = Math.min(globalMinXChild, bounds.minX);\n    globalMaxXChild = Math.max(globalMaxXChild, bounds.maxX);\n\n    laneBounds.push({\n      lane,\n      contentTop: bounds.minY,\n      contentBottom: bounds.maxY,\n      centerY: (bounds.minY + bounds.maxY) / 2,\n    });\n  }\n\n  if (globalMinXChild === Infinity || globalMaxXChild === -Infinity) {\n    return true;\n  }\n\n  const fullContentWidth = Math.max(0, globalMaxXChild - globalMinXChild);\n  const horizontalMargin = Math.max(maxPad, 10);\n  const bodyWidth = fullContentWidth + 2 * horizontalMargin;\n  const laneWidth = titleBandSize + bodyWidth;\n  const bodyCenter = (globalMinXChild + globalMaxXChild) / 2;\n  const bodyLeft = bodyCenter - bodyWidth / 2;\n  const laneLeft = bodyLeft - titleBandSize;\n  const centerX = laneLeft + laneWidth / 2;\n  const verticalMargin = Math.max(maxPad, titleBandSize);\n\n  laneBounds.sort((a, b) => a.centerY - b.centerY);\n\n  for (let i = 0; i < laneBounds.length; i++) {\n    const curr = laneBounds[i];\n    let laneTop: number;\n    let laneBottom: number;\n\n    if (i === 0) {\n      laneTop = curr.contentTop - verticalMargin;\n    } else {\n      const prev = laneBounds[i - 1];\n      laneTop = (prev.contentBottom + curr.contentTop) / 2;\n    }\n\n    if (i === laneBounds.length - 1) {\n      laneBottom = curr.contentBottom + verticalMargin;\n    } else {\n      const next = laneBounds[i + 1];\n      laneBottom = (curr.contentBottom + next.contentTop) / 2;\n    }\n\n    const laneHeight = Math.max(0, laneBottom - laneTop);\n    const centerY = (laneTop + laneBottom) / 2;\n\n    curr.lane.x = centerX;\n    curr.lane.y = centerY;\n    curr.lane.width = laneWidth;\n    curr.lane.height = laneHeight;\n    curr.lane.swimlaneContentTop = curr.contentTop;\n    curr.lane.groupTitleRect = {\n      left: laneLeft,\n      right: laneLeft + titleBandSize,\n      top: laneTop,\n      bottom: laneBottom,\n    };\n  }\n\n  if (direction === 'RL') {\n    mirrorAxis(layout, 'x');\n  }\n\n  return true;\n}\n", "// cspell:ignore Battista Eades Eiglsperger Hegemann Kandinsky segs Siebenhaller Tamassia Tollis F\u00F6\u00DFmeier\nimport type { Edge, Node } from '../../../types.js';\nimport {\n  classifyThreeSegmentRoute,\n  collectRealNodeBounds,\n  dedupeConsecutivePoints,\n  getNodePairGeometry,\n  samePoint,\n  segmentConflictsWithAnyEdge,\n  segmentHitsAnyRect,\n} from './geometry.js';\n\nconst EPS = 1e-6;\n// \u03B4_s \u2014 the Kandinsky port-spacing constant (F\u00F6\u00DFmeier\u2013Kaufmann 1995;\n// Siebenhaller dissertation \u00A76.1.2.2). When this pass places a second\n// edge on a face already occupied by a sibling centered at delta=0,\n// the canonical pairing is (0, \u00B1\u03B4_s) \u2014 full \u03B4_s separation between\n// port centers, not \u03B4_s/2. `straightenCollinearSiblingDetours` uses \u03B4_s/2\n// because that pass shifts BOTH members of a collinear pair\n// symmetrically (to \u00B1\u03B4_s/2, separation \u03B4_s); this pass shifts only\n// the single edge being swapped, so it must move the full \u03B4_s to\n// preserve the same canonical spacing.\nconst MIN_PORT_SPACING = 8;\nconst PORT_SHIFT = MIN_PORT_SPACING;\nconst TRY_DELTAS = [0, PORT_SHIFT, -PORT_SHIFT, 2 * PORT_SHIFT, -2 * PORT_SHIFT];\n\ninterface PointLite {\n  x: number;\n  y: number;\n}\n\n/**\n * Iter 17 \u2014 port-swap a 4-point H-V-H / V-H-V edge to a 3-point L-shape\n * when the current src port is \"straight-through\" (parallel to the\n * incoming edge) but a perpendicular src face permits a one-bend reach\n * to the existing dst port.\n *\n * Motivating case (user report 2026-04-16, 8-query-process-2.mmd):\n *   L_A2_E_0 currently:\n *     (A2.east=355.2, 0) \u2192 (gutter=402.3, 0)\n *       \u2192 (402.3, 213.4) \u2192 (E.west=844.1, 213.4)\n *   i.e. exits A2 on the east face (parallel to incoming A\u2192A2), bends\n *   south, bends east \u2014 2 interior bends. The south face of A2 points\n *   directly toward E's lane, so exiting south gives a 1-bend L-shape:\n *     (A2.south=cx\u00B1\u03B4, 69.3) \u2192 (cx\u00B1\u03B4, 213.4) \u2192 (E.west=844.1, 213.4)\n *   Saves one bend.\n *\n * Paper backing:\n *   - Tamassia's bend-minimization flow (1987, and\n *     Di Battista\u2013Eades\u2013Tamassia\u2013Tollis \u00A75): port/face assignment is a\n *     free variable and the optimum switches faces whenever it saves a\n *     bend.\n *   - Kandinsky port distribution (F\u00F6\u00DFmeier\u2013Kaufmann 1995;\n *     Siebenhaller dissertation \u00A72.3\u2013\u00A72.5): decision-diamond outgoing\n *     edges favor distinct perpendicular faces.\n *   - Siebenhaller \u00A73.3 \"Port Assignment\" + \u00A74.1 \"Bend optimization\":\n *     local port-swap accepted iff (a) bends strictly decrease, (b) no\n *     new crossings, (c) Kandinsky face-capacity preserved.\n *   - Hegemann\u2013Wolff \u00A74.2 joint-feasibility (paper src `b65b3d45`):\n *     the formal crossings + capacity guard set.\n *\n * Shape handled (src, dst NOT collinear):\n *   H-V-H:  p0 \u2192 p1 (horiz) \u2192 p2 (vert) \u2192 p3 (horiz);\n *           src face E/W (parallel to seg01); swap to N/S.\n *   V-H-V:  p0 \u2192 p1 (vert)  \u2192 p2 (horiz) \u2192 p3 (vert);\n *           src face N/S (parallel to seg01); swap to E/W.\n *\n * Rewrite (H-V-H):\n *   new_src_port = (src.cx + \u03B4, dst-below ? src.bottom : src.top)\n *   new_polyline = [ new_src_port, (src.cx + \u03B4, p3.y), p3 ]\n * (V-H-V symmetric across axes.)\n *\n * Safety (the six guards from the iter-17 plan):\n *   1. Strict bend-count decrease   \u2014 enforced by the 4-point \u2192 3-point\n *                                     rewrite.\n *   2. No new edge-edge crossings    \u2014 orthogonalSegmentsCross vs every other\n *                                     non-self segment.\n *   3. No new edge-node collisions   \u2014 segment-vs-node guard (both new segs,\n *                                     excluding src for seg-1 and dst\n *                                     for seg-2).\n *   4. Kandinsky face capacity       \u2014 port-offset delta chosen from\n *                                     0, \u00B1PORT_SHIFT, \u00B12\u00B7PORT_SHIFT;\n *                                     each candidate must lie strictly\n *                                     within the src face span; the\n *                                     collinear-axis overlap check\n *                                     (shared axis + overlapping range)\n *                                     rejects \u03B4 values that collide\n *                                     with an existing sibling port.\n *   5. No label-rect overlap on new  \u2014 re-done by anchorLabelsToPolyline\n *      segments                        which runs after this pass.\n *   6. Monotonic on fixture suite    \u2014 enforced externally by the DDLT\n *                                     contract (no spec's totalBends or\n *                                     crossings may increase).\n *\n * Distinct from `straightenCollinearSiblingDetours` (iter 12) which handles\n * the COLLINEAR case (4-point \u2192 2-point straight). This pass handles\n * the non-collinear case (4-point \u2192 3-point L). The two are disjoint\n * by the collinearX === collinearY guard: coRoute runs first and\n * converts collinear edges to 2-point straights which this pass then\n * skips by shape filter.\n *\n * Distinct from Eiglsperger bend-stretching (cited in iter 16\n * collapseShortTerminalStub): that pass requires the first and last\n * direction to be preserved; this pass explicitly CHANGES the first\n * direction \u2014 the whole point.\n */\nexport function portSwapToLShape(edges: Edge[], nodes: Node[]): void {\n  const { nodeInfoById, realNodeRects } = collectRealNodeBounds(nodes);\n\n  for (const edge of edges) {\n    if (edge.isLayoutOnly) {\n      continue;\n    }\n    const pts = edge.points;\n    if (!pts || pts.length < 4) {\n      continue;\n    }\n\n    // Dedupe consecutive identical points (raykov / endpoint-clip can\n    // produce duplicates). We operate on the DEDUPED polyline but write\n    // back without duplicates too \u2014 the rendering-handoff pass later\n    // re-duplicates endpoints for the intersect-rect guard.\n    const route = classifyThreeSegmentRoute(dedupeConsecutivePoints(pts, EPS), EPS);\n    if (!route) {\n      continue;\n    }\n\n    const { p3 } = route;\n    const isHVH = route.kind === 'HVH';\n\n    const nodePair = getNodePairGeometry(edge, nodeInfoById, EPS);\n    if (!nodePair) {\n      continue;\n    }\n    const { srcId, dstId, srcInfo, dstInfo, collinearX, collinearY } = nodePair;\n\n    // Skip collinear src/dst \u2014 straightenCollinearSiblingDetours handles those.\n    if (collinearX || collinearY) {\n      continue;\n    }\n\n    // Build candidate new polyline.\n    // H-V-H: swap src E/W face \u2192 N/S face. Preserve dst port (p3).\n    //   new p0 = (src.cx + \u03B4, dst-below ? src.bottom : src.top)\n    //   new p1 = (src.cx + \u03B4, p3.y)\n    //   new p2 = p3\n    // V-H-V symmetric.\n    let newPts: PointLite[] | undefined;\n    const srcRect = srcInfo.rect;\n\n    for (const delta of TRY_DELTAS) {\n      let np0: PointLite;\n      let np1: PointLite;\n      let np2: PointLite;\n\n      if (isHVH) {\n        const dstBelow = dstInfo.cy > srcInfo.cy;\n        const newSrcY = dstBelow ? srcRect.bottom : srcRect.top;\n        const newSrcX = srcInfo.cx + delta;\n        // Must lie strictly within src face span (exclusive of corners).\n        if (newSrcX <= srcRect.left + EPS || newSrcX >= srcRect.right - EPS) {\n          continue;\n        }\n        np0 = { x: newSrcX, y: newSrcY };\n        np1 = { x: newSrcX, y: p3.y };\n        np2 = { x: p3.x, y: p3.y };\n      } else {\n        // isVHV\n        const dstEast = dstInfo.cx > srcInfo.cx;\n        const newSrcX = dstEast ? srcRect.right : srcRect.left;\n        const newSrcY = srcInfo.cy + delta;\n        if (newSrcY <= srcRect.top + EPS || newSrcY >= srcRect.bottom - EPS) {\n          continue;\n        }\n        np0 = { x: newSrcX, y: newSrcY };\n        np1 = { x: p3.x, y: newSrcY };\n        np2 = { x: p3.x, y: p3.y };\n      }\n\n      // Degenerate: if np1 === np2, the \"L\" collapses to a straight line.\n      // Accept it (even better than a 1-bend L), but keep it as 2 pts.\n      const firstSegDegenerate = samePoint(np0, np1, EPS);\n      const secondSegDegenerate = samePoint(np1, np2, EPS);\n      if (firstSegDegenerate && secondSegDegenerate) {\n        continue;\n      }\n\n      // Guard 3: no edge-node collisions. Seg 1 may touch src; seg 2 may\n      // touch dst. Excluding those ids from the hit check.\n      if (!firstSegDegenerate && segmentHitsAnyRect(np0, np1, realNodeRects, [srcId], 1)) {\n        continue;\n      }\n      if (!secondSegDegenerate && segmentHitsAnyRect(np1, np2, realNodeRects, [dstId], 1)) {\n        continue;\n      }\n\n      // Guard 5: label overlap is checked by anchorLabelsToPolyline which\n      // runs AFTER this pass and re-anchors each label onto its owning\n      // edge's polyline (with along-segment parametric retry from iter\n      // 14). At this pipeline stage labels still sit at stale Sugiyama\n      // positions so a label-rect check here would reject against\n      // positions that will imminently be moved. If anchorLabelsToPolyline\n      // cannot find any legal anchor on the rewritten polyline,\n      // validateLayout's label-on-edge-segment invariant will flag it at\n      // DDLT level 1. Deliberately not checked here.\n\n      // Guards 2 + 4: check every other edge's every segment for a\n      // perpendicular crossing or a collinear-axis overlap with EITHER\n      // of the new segments.\n      const firstSegConflicts =\n        !firstSegDegenerate &&\n        segmentConflictsWithAnyEdge(np0, np1, edges, edge, {\n          epsilon: EPS,\n          skipDegenerateOther: true,\n        });\n      const secondSegConflicts =\n        !secondSegDegenerate &&\n        segmentConflictsWithAnyEdge(np1, np2, edges, edge, {\n          epsilon: EPS,\n          skipDegenerateOther: true,\n        });\n      if (firstSegConflicts || secondSegConflicts) {\n        continue;\n      }\n\n      // All guards pass. Build the final polyline.\n      if (firstSegDegenerate) {\n        newPts = [np1, np2];\n      } else if (secondSegDegenerate) {\n        newPts = [np0, np1];\n      } else {\n        newPts = [np0, np1, np2];\n      }\n      break;\n    }\n\n    if (newPts) {\n      edge.points = newPts;\n    }\n  }\n}\n", "// cspell:ignore Hegemann Wybrow penult\nimport {\n  collectNodeRectEntries,\n  dedupeConsecutivePoints,\n  isHorizontalSegment,\n  isVerticalSegment,\n  orthogonalSegmentsStrictlyCross as segmentsCross,\n  pointInsideRect,\n  rectOfNodeBounds,\n  sameX,\n  sameY,\n  segmentHitsAnyRect,\n} from './geometry.js';\nimport type { Point } from './geometry.js';\n\n/**\n * Iter 16 \u2014 collapse a short terminal stub at an edge's destination by\n * retargeting the destination face and dropping the corner. See the call-\n * site comment in `applySwimlaneDirectionTransform` for the user report and\n * paper backing (Siebenhaller `21f7ca55`; precedent in the retired\n * stale-port-offset straightener, Hegemann-Wolff `b65b3d45`).\n *\n * Shape handled:\n *   ... \u2192 prev \u2192 penult \u2192 end\n *                ~~~~~~~~~~~~~\n *                penult perpendicular to last; `|end - penult| < MIN_STUB`.\n *\n * Rewrite:\n *   ... \u2192 prev' \u2192 end'\n *   where prev' keeps prev's \"far\" coordinate and adopts the destination's\n *   face-center on the other axis, and end' is the destination face-center\n *   on the approach axis (i.e. bottom/top when penult is vertical;\n *   left/right when penult is horizontal \u2014 face chosen opposite to the\n *   approach direction).\n *\n * Safety:\n *   - Reject when the new prev'\u2192end' segment would enter any real-node\n *     rect (excluding the dst itself), any label rect, or cross an\n *     existing segment of a different edge (excluding its own segments).\n *   - Reject when the new prev' lies inside the src node's rect.\n *   - Only applied to the dst end; applying symmetrically on src\n *     would need identical safety accounting and is out of scope here.\n */\nexport function collapseShortTerminalStub(edges: any[], nodeByIdMap: Map<string, any>): void {\n  const MIN_STUB = 10;\n  const EPS_LOCAL = 1e-3;\n  const BUFFER = 2;\n\n  type PointLite = Point;\n\n  const { realNodeRects, labelNodeRects: labelRects } = collectNodeRectEntries(\n    nodeByIdMap.values()\n  );\n\n  for (const edge of edges) {\n    if ((edge as { isLayoutOnly?: boolean }).isLayoutOnly) {\n      continue;\n    }\n    const rawPts = (edge as { points?: PointLite[] }).points;\n    if (!rawPts || rawPts.length < 4) {\n      continue;\n    }\n\n    // Dedupe consecutive equal points so we measure the real last segment.\n    const pts = dedupeConsecutivePoints(rawPts, EPS_LOCAL);\n    if (pts.length < 4) {\n      continue;\n    }\n\n    const nLast = pts.length - 1;\n    const endPt = pts[nLast];\n    const penultPt = pts[nLast - 1];\n    const prevPt = pts[nLast - 2];\n\n    // Last segment (penult \u2192 end): must be short.\n    const lastDx = endPt.x - penultPt.x;\n    const lastDy = endPt.y - penultPt.y;\n    const lastLen = Math.hypot(lastDx, lastDy);\n    if (lastLen >= MIN_STUB || lastLen < EPS_LOCAL) {\n      continue;\n    }\n\n    // Penult segment (prev \u2192 penult): must be non-degenerate and\n    // perpendicular to last.\n    const penultDx = penultPt.x - prevPt.x;\n    const penultDy = penultPt.y - prevPt.y;\n    const penultLen = Math.hypot(penultDx, penultDy);\n    if (penultLen < EPS_LOCAL) {\n      continue;\n    }\n\n    const lastIsHoriz = isHorizontalSegment(penultPt, endPt, EPS_LOCAL);\n    const lastIsVert = isVerticalSegment(penultPt, endPt, EPS_LOCAL);\n    const penultIsHoriz = isHorizontalSegment(prevPt, penultPt, EPS_LOCAL);\n    const penultIsVert = isVerticalSegment(prevPt, penultPt, EPS_LOCAL);\n    if (!((lastIsHoriz && penultIsVert) || (lastIsVert && penultIsHoriz))) {\n      continue;\n    }\n\n    const dstId = (edge as { end?: string }).end;\n    const srcId = (edge as { start?: string }).start;\n    const dst = dstId ? nodeByIdMap.get(dstId) : undefined;\n    if (!dst) {\n      continue;\n    }\n    const dstCx = (dst as { x?: number }).x ?? 0;\n    const dstCy = (dst as { y?: number }).y ?? 0;\n    const dstRect = rectOfNodeBounds(dst);\n    if (!dstRect) {\n      continue;\n    }\n\n    // Compute the new prev' and end'. The axis of approach is the\n    // penult segment's axis; the new face is on the perpendicular to\n    // the approach, opposite to the approach direction.\n    let newPrev: { x: number; y: number };\n    let newEnd: { x: number; y: number };\n    if (penultIsVert) {\n      // Vertical approach: penult goes up (penultDy<0) or down (penultDy>0).\n      const approachFromBelow = penultDy < 0;\n      newPrev = { x: dstCx, y: prevPt.y };\n      newEnd = { x: dstCx, y: approachFromBelow ? dstRect.bottom : dstRect.top };\n    } else {\n      // Horizontal approach: penult goes right (penultDx>0) or left.\n      const approachFromLeft = penultDx > 0;\n      newPrev = { x: prevPt.x, y: dstCy };\n      newEnd = { x: approachFromLeft ? dstRect.right : dstRect.left, y: dstCy };\n    }\n\n    // Reject if the new prev'\u2192end' vertical/horizontal segment would cross\n    // any real-node rect (other than dst itself).\n    if (segmentHitsAnyRect(newPrev, newEnd, realNodeRects, dstId ? [dstId] : [], -BUFFER)) {\n      continue;\n    }\n\n    // Reject if the new approach segment would run through any label rect.\n    if (segmentHitsAnyRect(newPrev, newEnd, labelRects, [], -BUFFER)) {\n      continue;\n    }\n\n    // Reject if new prev' lies inside the src node's rect (pathological).\n    if (srcId) {\n      const src = nodeByIdMap.get(srcId);\n      const srcRect = src ? rectOfNodeBounds(src) : undefined;\n      if (srcRect && pointInsideRect(newPrev, srcRect, BUFFER)) {\n        continue;\n      }\n    }\n\n    // Also reject if the new prev'\u2192end' segment crosses any other edge's\n    // existing segment (excluding our own segments we're about to replace).\n    const ownSegmentKey = (a: PointLite, b: PointLite) =>\n      `${a.x.toFixed(3)},${a.y.toFixed(3)}|${b.x.toFixed(3)},${b.y.toFixed(3)}`;\n    const selfSegments = new Set<string>();\n    for (let i = 0; i < pts.length - 1; i++) {\n      selfSegments.add(ownSegmentKey(pts[i], pts[i + 1]));\n    }\n\n    const segmentCrossesOtherEdge = (from: PointLite, to: PointLite): boolean => {\n      for (const other of edges) {\n        if (other === edge) {\n          continue;\n        }\n        if ((other as { isLayoutOnly?: boolean }).isLayoutOnly) {\n          continue;\n        }\n        const oPts = (other as { points?: PointLite[] }).points;\n        if (!oPts || oPts.length < 2) {\n          continue;\n        }\n        for (let i = 0; i < oPts.length - 1; i++) {\n          const a = oPts[i];\n          const b = oPts[i + 1];\n          if (selfSegments.has(ownSegmentKey(a, b))) {\n            continue;\n          }\n          if (segmentsCross(from, to, a, b, EPS_LOCAL)) {\n            return true;\n          }\n        }\n      }\n      return false;\n    };\n\n    if (segmentCrossesOtherEdge(newPrev, newEnd)) {\n      continue;\n    }\n\n    // Also: if the new prev' segment (from prev-before-prev to newPrev) is\n    // degenerate or crosses anything, reject. The segment before the\n    // original prev (pts[nLast-3] \u2192 prev) becomes (pts[nLast-3] \u2192 newPrev)\n    // when we shift prev's axis.\n    if (nLast - 3 >= 0) {\n      const beforePrev = pts[nLast - 3];\n      // The pre-existing segment was beforePrev \u2192 prev on the axis perpendicular\n      // to penult. Shifting prev to newPrev preserves that axis alignment\n      // (only the axis we're shifting changes). Re-check for obstacles on\n      // the NEW extended segment.\n      const endpointIds = [srcId, dstId].filter((id): id is string => Boolean(id));\n      if (segmentHitsAnyRect(beforePrev, newPrev, realNodeRects, endpointIds, -BUFFER)) {\n        continue;\n      }\n      if (segmentCrossesOtherEdge(beforePrev, newPrev)) {\n        continue;\n      }\n    }\n\n    // Build rewritten polyline: pts[0..nLast-3] + newPrev + newEnd.\n    // This drops the original prev, penult, and end; replaces with newPrev\n    // and newEnd (one fewer bend).\n    const head = pts.slice(0, nLast - 2);\n    const newPts = [...head, newPrev, newEnd];\n    (edge as { points: PointLite[] }).points = newPts;\n\n    // Re-anchor the edge's label (if any) onto the new polyline. The\n    // original anchorLabelsToPolyline pass ran earlier in the pipeline\n    // and placed the label against the old geometry; validateLayout\n    // requires the polyline to pass through its label node. Place the\n    // label at the midpoint of the longest segment of the new polyline\n    // whose orientation matches the label's aspect.\n    const labelId = (edge as { labelNodeId?: string }).labelNodeId;\n    if (labelId) {\n      const labelNode = nodeByIdMap.get(labelId);\n      if (labelNode) {\n        const lw = (labelNode as { width?: number }).width ?? 0;\n        const lh = (labelNode as { height?: number }).height ?? 0;\n        if (lw > 0 && lh > 0) {\n          // Find longest segment \u2014 use its midpoint. Prefer axis-aligned\n          // segments whose length >= the label's corresponding dim so\n          // the label fits inside the segment's bounding run.\n          let bestMidX: number | undefined;\n          let bestMidY: number | undefined;\n          let bestLen = -1;\n          for (let i = 0; i < newPts.length - 1; i++) {\n            const a = newPts[i];\n            const b = newPts[i + 1];\n            const segLen = Math.hypot(b.x - a.x, b.y - a.y);\n            const isHoriz = sameY(a, b, EPS_LOCAL);\n            const isVert = sameX(a, b, EPS_LOCAL);\n            // Require axis-aligned and long enough to hold the label.\n            const fits = (isHoriz && segLen >= lw + 2) || (isVert && segLen >= lh + 2);\n            if (!fits) {\n              continue;\n            }\n            if (segLen > bestLen) {\n              bestLen = segLen;\n              bestMidX = (a.x + b.x) / 2;\n              bestMidY = (a.y + b.y) / 2;\n            }\n          }\n          if (bestMidX !== undefined && bestMidY !== undefined) {\n            (labelNode as { x: number }).x = bestMidX;\n            (labelNode as { y: number }).y = bestMidY;\n          }\n        }\n      }\n    }\n  }\n}\n", "// cspell:ignore Wybrow\n\nimport {\n  collectNodeRectEntries,\n  countOrthogonalBends,\n  dedupeConsecutivePoints,\n  isHorizontalSegment,\n  isVerticalSegment,\n  samePoint,\n  sameX,\n  sameY,\n  buildOrthogonalPortPath,\n  buildSameSideTrackPath,\n  overlapLength,\n  orthogonalSegmentsForPoints,\n  orthogonalSegmentsStrictlyCross,\n  portForRectSide,\n  rectOfNodeBounds,\n  sameAxisSegmentOverlapLength,\n  segmentHitsAnyRect,\n  simplifyPolyline,\n} from './geometry.js';\nimport type { OrthogonalSegment, Point, RectBounds, RectSide } from './geometry.js';\nimport type { Edge, Node } from '../../../types.js';\n\nconst EPS_LOCAL = 1e-3;\nconst MIN_SHARED = 8;\n\ntype PointLite = Point;\ntype RectLite = RectBounds;\ntype MaterializedEdge = Edge & { points?: PointLite[] };\ntype MaterializedNode = Node & { direction?: string };\ntype EdgeReplacementMap = Map<MaterializedEdge, PointLite[]>;\n\ntype SegmentLite = OrthogonalSegment;\n\nconst segmentsFor = orthogonalSegmentsForPoints;\n\nconst orthogonallyAligned = (a: PointLite, b: PointLite): boolean =>\n  sameX(a, b, EPS_LOCAL) || sameY(a, b, EPS_LOCAL);\n\nexport function separateSharedRenderedTerminalLanes(\n  edges: MaterializedEdge[],\n  nodeByIdMap: Map<string, MaterializedNode>\n): void {\n  const MIN_FACE_CLEARANCE = 16;\n  const TRACK_SHIFT = 7;\n\n  interface TerminalLane {\n    edge: MaterializedEdge;\n    edgeId: string;\n    nodeId: string;\n    atStart: boolean;\n    orientation: 'H' | 'V';\n    coord: number;\n    min: number;\n    max: number;\n    boundary: PointLite;\n    railEnd: PointLite;\n    rect: RectLite;\n  }\n\n  const rectIntersect = (node: MaterializedNode, point: PointLite): PointLite => {\n    const x = (node as { x?: number }).x ?? 0;\n    const y = (node as { y?: number }).y ?? 0;\n    const dx = point.x - x;\n    const dy = point.y - y;\n    let w = ((node as { width?: number }).width ?? 0) / 2;\n    let h = ((node as { height?: number }).height ?? 0) / 2;\n\n    if (Math.abs(dy) * w > Math.abs(dx) * h) {\n      if (dy < 0) {\n        h = -h;\n      }\n      return { x: x + (dy === 0 ? 0 : (h * dx) / dy), y: y + h };\n    }\n\n    if (dx < 0) {\n      w = -w;\n    }\n    return { x: x + w, y: y + (dx === 0 ? 0 : (w * dy) / dx) };\n  };\n\n  const terminalLaneFor = (edge: MaterializedEdge, atStart: boolean): TerminalLane | undefined => {\n    const points = dedupeConsecutivePoints((edge as { points?: PointLite[] }).points ?? []);\n    if (points.length < 2) {\n      return undefined;\n    }\n\n    const nodeId = atStart ? (edge as { start?: string }).start : (edge as { end?: string }).end;\n    const node = nodeId ? nodeByIdMap.get(nodeId) : undefined;\n    const rect = node ? rectOfNodeBounds(node) : undefined;\n    if (!node || !nodeId || !rect) {\n      return undefined;\n    }\n\n    const endpoint = atStart ? points[0] : points[points.length - 1];\n    const adjacent = atStart ? points[1] : points[points.length - 2];\n    const boundary = rectIntersect(node, endpoint);\n    let railEnd = endpoint;\n    if (orthogonallyAligned(adjacent, boundary)) {\n      railEnd = adjacent;\n    }\n\n    if (sameX(boundary, railEnd, EPS_LOCAL)) {\n      return {\n        edge,\n        edgeId: String((edge as { id?: string }).id ?? ''),\n        nodeId,\n        atStart,\n        orientation: 'V',\n        coord: boundary.x,\n        min: Math.min(boundary.y, railEnd.y),\n        max: Math.max(boundary.y, railEnd.y),\n        boundary,\n        railEnd,\n        rect,\n      };\n    }\n    if (sameY(boundary, railEnd, EPS_LOCAL)) {\n      return {\n        edge,\n        edgeId: String((edge as { id?: string }).id ?? ''),\n        nodeId,\n        atStart,\n        orientation: 'H',\n        coord: boundary.y,\n        min: Math.min(boundary.x, railEnd.x),\n        max: Math.max(boundary.x, railEnd.x),\n        boundary,\n        railEnd,\n        rect,\n      };\n    }\n    return undefined;\n  };\n\n  const projectedOverlapLength = (a: TerminalLane, b: TerminalLane): number =>\n    Math.max(0, Math.min(a.max, b.max) - Math.max(a.min, b.min));\n\n  const sameTerminalFace = (a: TerminalLane, b: TerminalLane): boolean => {\n    if (a.nodeId !== b.nodeId || a.orientation !== b.orientation) {\n      return false;\n    }\n\n    if (a.orientation === 'H') {\n      const aOnHorizontalFace =\n        Math.abs(a.boundary.x - a.rect.left) < 1 || Math.abs(a.boundary.x - a.rect.right) < 1;\n      return aOnHorizontalFace && sameX(a.boundary, b.boundary, 1);\n    }\n\n    const aOnVerticalFace =\n      Math.abs(a.boundary.y - a.rect.top) < 1 || Math.abs(a.boundary.y - a.rect.bottom) < 1;\n    return aOnVerticalFace && sameY(a.boundary, b.boundary, 1);\n  };\n\n  const exactTerminalLaneConflict = (a: TerminalLane, b: TerminalLane): boolean => {\n    if (a.nodeId !== b.nodeId || a.orientation !== b.orientation) {\n      return false;\n    }\n\n    const shared = projectedOverlapLength(a, b);\n    return shared >= MIN_SHARED && Math.abs(a.coord - b.coord) < 0.5;\n  };\n\n  const nearTerminalLaneConflict = (a: TerminalLane, b: TerminalLane): boolean => {\n    if (\n      a.nodeId !== b.nodeId ||\n      a.orientation !== b.orientation ||\n      a.orientation !== 'H' ||\n      a.atStart === b.atStart\n    ) {\n      return false;\n    }\n\n    const shared = projectedOverlapLength(a, b);\n    if (shared < MIN_SHARED) {\n      return false;\n    }\n    const faceSpan = a.rect.bottom - a.rect.top;\n    if (shared < faceSpan || shared > 2 * faceSpan) {\n      return false;\n    }\n\n    // Wybrow-style nudging keeps connector topology fixed while preserving\n    // ordering constraints; rendered terminal tracks on the same object face\n    // need the same treatment before endpoint duplication pins them in place.\n    return sameTerminalFace(a, b) && Math.abs(a.coord - b.coord) < MIN_FACE_CLEARANCE;\n  };\n\n  const shiftedCandidate = (lane: TerminalLane, shift: number): PointLite[] | undefined => {\n    const points = dedupeConsecutivePoints((lane.edge as { points?: PointLite[] }).points ?? []);\n    if (points.length < 2) {\n      return undefined;\n    }\n\n    const shiftedBoundary =\n      lane.orientation === 'V'\n        ? { x: lane.boundary.x + shift, y: lane.boundary.y }\n        : { x: lane.boundary.x, y: lane.boundary.y + shift };\n    const shiftedRailEnd =\n      lane.orientation === 'V'\n        ? { x: lane.railEnd.x + shift, y: lane.railEnd.y }\n        : { x: lane.railEnd.x, y: lane.railEnd.y + shift };\n\n    const boundaryStaysOnSameFace = (): boolean => {\n      if (\n        Math.abs(lane.boundary.y - lane.rect.top) < 1 ||\n        Math.abs(lane.boundary.y - lane.rect.bottom) < 1\n      ) {\n        return (\n          sameY(shiftedBoundary, lane.boundary, EPS_LOCAL) &&\n          shiftedBoundary.x >= lane.rect.left + 1 &&\n          shiftedBoundary.x <= lane.rect.right - 1\n        );\n      }\n\n      if (\n        Math.abs(lane.boundary.x - lane.rect.left) < 1 ||\n        Math.abs(lane.boundary.x - lane.rect.right) < 1\n      ) {\n        return (\n          sameX(shiftedBoundary, lane.boundary, EPS_LOCAL) &&\n          shiftedBoundary.y >= lane.rect.top + 1 &&\n          shiftedBoundary.y <= lane.rect.bottom - 1\n        );\n      }\n\n      return false;\n    };\n\n    if (!boundaryStaysOnSameFace()) {\n      return undefined;\n    }\n\n    if (lane.atStart) {\n      const railEndIsAdjacent = points.length > 1 && samePoint(points[1], lane.railEnd, EPS_LOCAL);\n      const rest = points.slice(railEndIsAdjacent ? 2 : 1);\n      const next = rest[0];\n      if (next && !orthogonallyAligned(next, shiftedRailEnd)) {\n        return undefined;\n      }\n      return [shiftedBoundary, shiftedRailEnd, ...rest];\n    }\n\n    const railEndIsAdjacent =\n      points.length > 1 && samePoint(points[points.length - 2], lane.railEnd, EPS_LOCAL);\n    const before = points.slice(0, railEndIsAdjacent ? -2 : -1);\n    const previous = before[before.length - 1];\n    if (previous && !orthogonallyAligned(previous, shiftedRailEnd)) {\n      return undefined;\n    }\n    return [...before, shiftedRailEnd, shiftedBoundary];\n  };\n\n  const laneIsStraightCollinearConnector = (lane: TerminalLane): boolean => {\n    const edge = lane.edge as { points?: PointLite[]; start?: string; end?: string };\n    const points = dedupeConsecutivePoints(edge.points ?? []);\n    if (points.length !== 2) {\n      return false;\n    }\n    const startId = edge.start;\n    const endId = edge.end;\n    const start = startId ? nodeByIdMap.get(startId) : undefined;\n    const end = endId ? nodeByIdMap.get(endId) : undefined;\n    if (!start || !end) {\n      return false;\n    }\n\n    const startX = (start as { x?: number }).x ?? 0;\n    const startY = (start as { y?: number }).y ?? 0;\n    const endX = (end as { x?: number }).x ?? 0;\n    const endY = (end as { y?: number }).y ?? 0;\n    const [a, b] = points;\n\n    return (\n      (sameY(a, b, EPS_LOCAL) && Math.abs(startY - endY) < 1 && Math.abs(startX - endX) > 1) ||\n      (sameX(a, b, EPS_LOCAL) && Math.abs(startX - endX) < 1 && Math.abs(startY - endY) > 1)\n    );\n  };\n\n  const shifts = [\n    -TRACK_SHIFT,\n    TRACK_SHIFT,\n    -2 * TRACK_SHIFT,\n    2 * TRACK_SHIFT,\n    -3 * TRACK_SHIFT,\n    3 * TRACK_SHIFT,\n  ];\n\n  for (let iteration = 0; iteration < 8; iteration++) {\n    const lanes = edges\n      .filter((edge) => !(edge as { isLayoutOnly?: boolean }).isLayoutOnly)\n      .flatMap((edge) => [terminalLaneFor(edge, true), terminalLaneFor(edge, false)])\n      .filter((lane): lane is TerminalLane => Boolean(lane));\n\n    let fixed = false;\n    for (let i = 0; i < lanes.length && !fixed; i++) {\n      for (let j = i + 1; j < lanes.length && !fixed; j++) {\n        const first = lanes[i];\n        const second = lanes[j];\n        if (\n          first.edge === second.edge ||\n          !(exactTerminalLaneConflict(first, second) || nearTerminalLaneConflict(first, second))\n        ) {\n          continue;\n        }\n\n        const fixingNearConflict = !exactTerminalLaneConflict(first, second);\n        const candidates = [first, second].sort((a, b) => {\n          const aPreservesStraight = laneIsStraightCollinearConnector(a);\n          const bPreservesStraight = laneIsStraightCollinearConnector(b);\n          if (aPreservesStraight !== bPreservesStraight) {\n            return Number(aPreservesStraight) - Number(bPreservesStraight);\n          }\n          return Number(!b.atStart) - Number(!a.atStart);\n        });\n        for (const lane of candidates) {\n          for (const shift of shifts) {\n            const candidate = shiftedCandidate(lane, shift);\n            if (!candidate) {\n              continue;\n            }\n            const nextLane = terminalLaneFor({ ...lane.edge, points: candidate }, lane.atStart);\n            if (\n              !nextLane ||\n              lanes.some(\n                (other) =>\n                  other.edge !== lane.edge &&\n                  (exactTerminalLaneConflict(nextLane, other) ||\n                    (fixingNearConflict && nearTerminalLaneConflict(nextLane, other)))\n              )\n            ) {\n              continue;\n            }\n\n            (lane.edge as { points: PointLite[] }).points = candidate;\n            fixed = true;\n            break;\n          }\n          if (fixed) {\n            break;\n          }\n        }\n      }\n    }\n\n    if (!fixed) {\n      return;\n    }\n  }\n}\n\nexport function collapseRedundantRectangularDoglegs(\n  edges: MaterializedEdge[],\n  nodeByIdMap: Map<string, MaterializedNode>\n): void {\n  const BUFFER = 2;\n  const MAX_ITERATIONS = 8;\n\n  const { realNodeRects, labelNodeRects: labelRects } = collectNodeRectEntries(\n    nodeByIdMap.values()\n  );\n\n  const candidateIsSafe = (edge: MaterializedEdge, candidate: PointLite[]): boolean => {\n    const sourceId = (edge as { start?: string }).start;\n    const targetId = (edge as { end?: string }).end;\n    const candidateSegments = segmentsFor(candidate);\n    if (candidateSegments.length !== candidate.length - 1) {\n      return false;\n    }\n\n    const endpointIds = [sourceId, targetId].filter((id): id is string => Boolean(id));\n    for (const segment of candidateSegments) {\n      if (segmentHitsAnyRect(segment.a, segment.b, realNodeRects, endpointIds, -BUFFER)) {\n        return false;\n      }\n      if (segmentHitsAnyRect(segment.a, segment.b, labelRects, [], -BUFFER)) {\n        return false;\n      }\n    }\n\n    for (const other of edges) {\n      if (other === edge || (other as { isLayoutOnly?: boolean }).isLayoutOnly) {\n        continue;\n      }\n      const otherPoints = (other as { points?: PointLite[] }).points;\n      if (!otherPoints || otherPoints.length < 2) {\n        continue;\n      }\n      for (const candidateSegment of candidateSegments) {\n        for (const otherSegment of segmentsFor(dedupeConsecutivePoints(otherPoints))) {\n          if (sameAxisSegmentOverlapLength(candidateSegment, otherSegment, 0.5) >= MIN_SHARED) {\n            return false;\n          }\n          if (\n            orthogonalSegmentsStrictlyCross(\n              candidateSegment.a,\n              candidateSegment.b,\n              otherSegment.a,\n              otherSegment.b,\n              EPS_LOCAL\n            )\n          ) {\n            return false;\n          }\n        }\n      }\n    }\n\n    return true;\n  };\n\n  const withoutDogleg = (points: PointLite[], i: number): PointLite[] | undefined => {\n    if (i + 4 >= points.length) {\n      return undefined;\n    }\n    const p0 = points[i];\n    const p1 = points[i + 1];\n    const p2 = points[i + 2];\n    const p3 = points[i + 3];\n    const p4 = points[i + 4];\n\n    const terminalVerticalDogleg =\n      isHorizontalSegment(p0, p1) &&\n      isVerticalSegment(p1, p2) &&\n      isHorizontalSegment(p2, p3) &&\n      isVerticalSegment(p3, p4) &&\n      sameX(p0, p3, EPS_LOCAL) &&\n      sameX(p0, p4, EPS_LOCAL) &&\n      sameX(p1, p2, EPS_LOCAL) &&\n      (p1.x - p0.x) * (p3.x - p2.x) < 0;\n\n    const terminalHorizontalDogleg =\n      isVerticalSegment(p0, p1) &&\n      isHorizontalSegment(p1, p2) &&\n      isVerticalSegment(p2, p3) &&\n      isHorizontalSegment(p3, p4) &&\n      sameY(p0, p3, EPS_LOCAL) &&\n      sameY(p0, p4, EPS_LOCAL) &&\n      sameY(p1, p2, EPS_LOCAL) &&\n      (p1.y - p0.y) * (p3.y - p2.y) < 0;\n\n    if (terminalVerticalDogleg || terminalHorizontalDogleg) {\n      return dedupeConsecutivePoints([...points.slice(0, i + 1), p4, ...points.slice(i + 5)]);\n    }\n\n    if (i + 5 >= points.length) {\n      return undefined;\n    }\n    const p5 = points[i + 5];\n\n    const verticalDogleg =\n      isVerticalSegment(p0, p1) &&\n      isHorizontalSegment(p1, p2) &&\n      isVerticalSegment(p2, p3) &&\n      isHorizontalSegment(p3, p4) &&\n      isVerticalSegment(p4, p5) &&\n      sameX(p0, p4, EPS_LOCAL) &&\n      sameX(p0, p5, EPS_LOCAL) &&\n      sameX(p2, p3, EPS_LOCAL) &&\n      (p2.x - p1.x) * (p4.x - p3.x) < 0;\n\n    const horizontalDogleg =\n      isHorizontalSegment(p0, p1) &&\n      isVerticalSegment(p1, p2) &&\n      isHorizontalSegment(p2, p3) &&\n      isVerticalSegment(p3, p4) &&\n      isHorizontalSegment(p4, p5) &&\n      sameY(p0, p4, EPS_LOCAL) &&\n      sameY(p0, p5, EPS_LOCAL) &&\n      sameY(p2, p3, EPS_LOCAL) &&\n      (p2.y - p1.y) * (p4.y - p3.y) < 0;\n\n    if (!verticalDogleg && !horizontalDogleg) {\n      return undefined;\n    }\n\n    return dedupeConsecutivePoints([...points.slice(0, i + 1), p5, ...points.slice(i + 6)]);\n  };\n\n  for (let iteration = 0; iteration < MAX_ITERATIONS; iteration++) {\n    let fixed = false;\n    for (const edge of edges) {\n      if ((edge as { isLayoutOnly?: boolean }).isLayoutOnly) {\n        continue;\n      }\n      const points = dedupeConsecutivePoints((edge as { points?: PointLite[] }).points ?? []);\n      for (let i = 0; i <= points.length - 5; i++) {\n        const candidate = withoutDogleg(points, i);\n        if (!candidate || !candidateIsSafe(edge, candidate)) {\n          continue;\n        }\n        (edge as { points: PointLite[] }).points = candidate;\n        fixed = true;\n        break;\n      }\n      if (fixed) {\n        break;\n      }\n    }\n    if (!fixed) {\n      return;\n    }\n  }\n}\n\nexport function liftObstacleHuggingSameSideRails(\n  edges: MaterializedEdge[],\n  nodeByIdMap: Map<string, MaterializedNode>\n): void {\n  const BUFFER = 2;\n  const CLEARANCE = 20;\n  const MAX_ITERATIONS = 8;\n\n  const { realNodeRects, labelNodeRects: labelRects } = collectNodeRectEntries(\n    nodeByIdMap.values()\n  );\n  const visibleEdges = edges.filter((edge) => !(edge as { isLayoutOnly?: boolean }).isLayoutOnly);\n\n  const pointsFor = (\n    edge: MaterializedEdge,\n    replacementEdge?: MaterializedEdge,\n    replacement?: PointLite[]\n  ): PointLite[] =>\n    dedupeConsecutivePoints(\n      edge === replacementEdge\n        ? (replacement ?? [])\n        : ((edge as { points?: PointLite[] }).points ?? [])\n    );\n\n  const strictCrossingCount = (\n    replacementEdge?: MaterializedEdge,\n    replacement?: PointLite[]\n  ): number => {\n    let count = 0;\n    for (let i = 0; i < visibleEdges.length; i++) {\n      const firstSegments = segmentsFor(pointsFor(visibleEdges[i], replacementEdge, replacement));\n      for (let j = i + 1; j < visibleEdges.length; j++) {\n        const secondSegments = segmentsFor(\n          pointsFor(visibleEdges[j], replacementEdge, replacement)\n        );\n        for (const firstSegment of firstSegments) {\n          for (const secondSegment of secondSegments) {\n            if (\n              orthogonalSegmentsStrictlyCross(\n                firstSegment.a,\n                firstSegment.b,\n                secondSegment.a,\n                secondSegment.b,\n                EPS_LOCAL\n              )\n            ) {\n              count++;\n            }\n          }\n        }\n      }\n    }\n    return count;\n  };\n\n  const middleRail = (\n    points: PointLite[]\n  ):\n    | { index: number; horizontal: boolean; vertical: boolean; segment: SegmentLite }\n    | undefined => {\n    const segments = segmentsFor(points);\n    if (segments.length !== 3) {\n      return undefined;\n    }\n    const middle = segments[1];\n    if (\n      segments[0].horizontal === middle.horizontal ||\n      segments[2].horizontal === middle.horizontal\n    ) {\n      return undefined;\n    }\n    return {\n      index: middle.index,\n      horizontal: middle.horizontal,\n      vertical: middle.vertical,\n      segment: middle,\n    };\n  };\n\n  const blockingRectsFor = (edge: MaterializedEdge, rail: SegmentLite) => {\n    const endpointIds = [(edge as { start?: string }).start, (edge as { end?: string }).end].filter(\n      (id): id is string => Boolean(id)\n    );\n    return realNodeRects.filter((entry) => {\n      if (endpointIds.includes(entry.id)) {\n        return false;\n      }\n      const rect = entry.rect;\n      if (rail.horizontal) {\n        const xOverlap = overlapLength(rail.a.x, rail.b.x, rect.left, rect.right);\n        return (\n          xOverlap >= MIN_SHARED &&\n          rail.a.y >= rect.top - BUFFER &&\n          rail.a.y <= rect.bottom + BUFFER\n        );\n      }\n      const yOverlap = overlapLength(rail.a.y, rail.b.y, rect.top, rect.bottom);\n      return (\n        yOverlap >= MIN_SHARED && rail.a.x >= rect.left - BUFFER && rail.a.x <= rect.right + BUFFER\n      );\n    });\n  };\n\n  const candidateByMovingRail = (\n    points: PointLite[],\n    rail: SegmentLite,\n    coord: number\n  ): PointLite[] | undefined => {\n    const candidate = points.map((point) => ({ ...point }));\n    if (rail.horizontal) {\n      candidate[rail.index].y = coord;\n      candidate[rail.index + 1].y = coord;\n    } else if (rail.vertical) {\n      candidate[rail.index].x = coord;\n      candidate[rail.index + 1].x = coord;\n    } else {\n      return undefined;\n    }\n    const simplified = simplifyPolyline(dedupeConsecutivePoints(candidate));\n    return segmentsFor(simplified).length === simplified.length - 1 ? simplified : undefined;\n  };\n\n  const candidateIsSafe = (\n    edge: MaterializedEdge,\n    candidate: PointLite[],\n    currentCrossings: number\n  ): boolean => {\n    const endpointIds = [(edge as { start?: string }).start, (edge as { end?: string }).end].filter(\n      (id): id is string => Boolean(id)\n    );\n    const candidateSegments = segmentsFor(candidate);\n    if (candidateSegments.length !== candidate.length - 1) {\n      return false;\n    }\n\n    for (const segment of candidateSegments) {\n      if (segmentHitsAnyRect(segment.a, segment.b, realNodeRects, endpointIds, -BUFFER)) {\n        return false;\n      }\n      if (segmentHitsAnyRect(segment.a, segment.b, labelRects, [], -BUFFER)) {\n        return false;\n      }\n    }\n\n    for (const other of visibleEdges) {\n      if (other === edge) {\n        continue;\n      }\n      for (const candidateSegment of candidateSegments) {\n        for (const otherSegment of segmentsFor(pointsFor(other))) {\n          if (sameAxisSegmentOverlapLength(candidateSegment, otherSegment, 0.5) >= MIN_SHARED) {\n            return false;\n          }\n        }\n      }\n    }\n\n    return strictCrossingCount(edge, candidate) <= currentCrossings;\n  };\n\n  for (let iteration = 0; iteration < MAX_ITERATIONS; iteration++) {\n    const currentCrossings = strictCrossingCount();\n    let fixed = false;\n\n    for (const edge of visibleEdges) {\n      const points = pointsFor(edge);\n      const rail = middleRail(points);\n      if (!rail) {\n        continue;\n      }\n      const blockers = blockingRectsFor(edge, rail.segment);\n      if (blockers.length === 0) {\n        continue;\n      }\n\n      const coords = rail.horizontal\n        ? [\n            Math.min(...blockers.map((entry) => entry.rect.top)) - CLEARANCE,\n            Math.max(...blockers.map((entry) => entry.rect.bottom)) + CLEARANCE,\n          ]\n        : [\n            Math.min(...blockers.map((entry) => entry.rect.left)) - CLEARANCE,\n            Math.max(...blockers.map((entry) => entry.rect.right)) + CLEARANCE,\n          ];\n\n      for (const coord of coords) {\n        const candidate = candidateByMovingRail(points, rail.segment, coord);\n        if (!candidate || !candidateIsSafe(edge, candidate, currentCrossings)) {\n          continue;\n        }\n        (edge as { points: PointLite[] }).points = candidate;\n        fixed = true;\n        break;\n      }\n      if (fixed) {\n        break;\n      }\n    }\n\n    if (!fixed) {\n      return;\n    }\n  }\n}\n\nexport function liftTopLaneTitleBandsAboveRails(\n  edges: MaterializedEdge[],\n  nodeByIdMap: Map<string, MaterializedNode>\n): void {\n  const CLEARANCE = 4;\n\n  interface LaneTitle {\n    node: MaterializedNode;\n    rect: RectLite;\n  }\n\n  const validTitleRect = (node: MaterializedNode): RectLite | undefined => {\n    const rect = (node as { groupTitleRect?: Partial<RectBounds> }).groupTitleRect;\n    if (\n      !rect ||\n      typeof rect.left !== 'number' ||\n      typeof rect.right !== 'number' ||\n      typeof rect.top !== 'number' ||\n      typeof rect.bottom !== 'number' ||\n      !Number.isFinite(rect.left) ||\n      !Number.isFinite(rect.right) ||\n      !Number.isFinite(rect.top) ||\n      !Number.isFinite(rect.bottom) ||\n      rect.right <= rect.left ||\n      rect.bottom <= rect.top\n    ) {\n      return undefined;\n    }\n    return { left: rect.left, right: rect.right, top: rect.top, bottom: rect.bottom };\n  };\n\n  const topLaneTitleFor = (node: MaterializedNode): LaneTitle | undefined => {\n    if (!(node as { isGroup?: boolean }).isGroup || (node as { parentId?: unknown }).parentId) {\n      return undefined;\n    }\n    const rawDirection = (node as { direction?: unknown }).direction;\n    const direction = typeof rawDirection === 'string' ? rawDirection.toUpperCase() : '';\n    if (direction === 'LR' || direction === 'RL' || direction === 'BT') {\n      return undefined;\n    }\n    const rect = validTitleRect(node);\n    const y = (node as { y?: number }).y;\n    const height = (node as { height?: number }).height;\n    if (\n      !rect ||\n      typeof y !== 'number' ||\n      typeof height !== 'number' ||\n      !Number.isFinite(y) ||\n      !Number.isFinite(height) ||\n      height <= 0\n    ) {\n      return undefined;\n    }\n    const titleWidth = rect.right - rect.left;\n    const titleHeight = rect.bottom - rect.top;\n    if (titleHeight <= 0 || titleWidth < titleHeight) {\n      return undefined;\n    }\n    return { node, rect };\n  };\n\n  const horizontalSegmentIntersectsTitle = (segment: SegmentLite, rect: RectLite): boolean => {\n    if (!segment.horizontal) {\n      return false;\n    }\n    const y = segment.a.y;\n    if (y <= rect.top + EPS_LOCAL || y >= rect.bottom - EPS_LOCAL) {\n      return false;\n    }\n    return overlapLength(segment.a.x, segment.b.x, rect.left, rect.right) >= MIN_SHARED;\n  };\n\n  const lanes = [...nodeByIdMap.values()]\n    .map(topLaneTitleFor)\n    .filter((lane): lane is LaneTitle => Boolean(lane));\n  if (lanes.length === 0) {\n    return;\n  }\n\n  let topDelta = 0;\n  for (const edge of edges) {\n    if ((edge as { isLayoutOnly?: boolean }).isLayoutOnly) {\n      continue;\n    }\n    const points = dedupeConsecutivePoints((edge as { points?: PointLite[] }).points ?? []);\n    for (const segment of segmentsFor(points)) {\n      for (const lane of lanes) {\n        if (!horizontalSegmentIntersectsTitle(segment, lane.rect)) {\n          continue;\n        }\n        topDelta = Math.max(topDelta, lane.rect.bottom - segment.a.y + CLEARANCE);\n      }\n    }\n  }\n\n  if (topDelta <= EPS_LOCAL) {\n    return;\n  }\n\n  for (const lane of lanes) {\n    const y = (lane.node as { y?: number }).y;\n    const height = (lane.node as { height?: number }).height;\n    if (\n      typeof y !== 'number' ||\n      typeof height !== 'number' ||\n      !Number.isFinite(y) ||\n      !Number.isFinite(height) ||\n      height <= 0\n    ) {\n      continue;\n    }\n    lane.node.y = y - topDelta / 2;\n    lane.node.height = height + topDelta;\n    lane.node.groupTitleRect = {\n      ...lane.rect,\n      top: lane.rect.top - topDelta,\n      bottom: lane.rect.bottom - topDelta,\n    };\n  }\n}\n\nexport function shiftLeftLaneTitleBandsLeftOfRails(\n  edges: MaterializedEdge[],\n  nodeByIdMap: Map<string, MaterializedNode>\n): void {\n  const CLEARANCE = 4;\n\n  interface LaneTitle {\n    node: MaterializedNode;\n    rect: RectLite;\n  }\n\n  const validTitleRect = (node: MaterializedNode): RectLite | undefined => {\n    const rect = (node as { groupTitleRect?: Partial<RectBounds> }).groupTitleRect;\n    if (\n      !rect ||\n      typeof rect.left !== 'number' ||\n      typeof rect.right !== 'number' ||\n      typeof rect.top !== 'number' ||\n      typeof rect.bottom !== 'number' ||\n      !Number.isFinite(rect.left) ||\n      !Number.isFinite(rect.right) ||\n      !Number.isFinite(rect.top) ||\n      !Number.isFinite(rect.bottom) ||\n      rect.right <= rect.left ||\n      rect.bottom <= rect.top\n    ) {\n      return undefined;\n    }\n    return { left: rect.left, right: rect.right, top: rect.top, bottom: rect.bottom };\n  };\n\n  const leftLaneTitleFor = (node: MaterializedNode): LaneTitle | undefined => {\n    if (!(node as { isGroup?: boolean }).isGroup || (node as { parentId?: unknown }).parentId) {\n      return undefined;\n    }\n    const rawDirection = (node as { direction?: unknown }).direction;\n    if (rawDirection !== 'LR') {\n      return undefined;\n    }\n    const rect = validTitleRect(node);\n    const x = (node as { x?: number }).x;\n    const width = (node as { width?: number }).width;\n    if (\n      !rect ||\n      typeof x !== 'number' ||\n      typeof width !== 'number' ||\n      !Number.isFinite(x) ||\n      !Number.isFinite(width) ||\n      width <= 0\n    ) {\n      return undefined;\n    }\n    const titleWidth = rect.right - rect.left;\n    const titleHeight = rect.bottom - rect.top;\n    if (titleWidth <= 0 || titleHeight < titleWidth) {\n      return undefined;\n    }\n    return { node, rect };\n  };\n\n  const verticalSegmentIntersectsTitle = (segment: SegmentLite, rect: RectLite): boolean => {\n    if (!segment.vertical) {\n      return false;\n    }\n    const x = segment.a.x;\n    if (x <= rect.left + EPS_LOCAL || x >= rect.right - EPS_LOCAL) {\n      return false;\n    }\n    return overlapLength(segment.a.y, segment.b.y, rect.top, rect.bottom) >= MIN_SHARED;\n  };\n\n  const horizontalSegmentIntersectsTitle = (segment: SegmentLite, rect: RectLite): boolean => {\n    if (!segment.horizontal) {\n      return false;\n    }\n    const y = segment.a.y;\n    if (y <= rect.top + EPS_LOCAL || y >= rect.bottom - EPS_LOCAL) {\n      return false;\n    }\n    return overlapLength(segment.a.x, segment.b.x, rect.left, rect.right) >= MIN_SHARED;\n  };\n\n  const lanes = [...nodeByIdMap.values()]\n    .map(leftLaneTitleFor)\n    .filter((lane): lane is LaneTitle => Boolean(lane));\n  if (lanes.length === 0) {\n    return;\n  }\n\n  let leftDelta = 0;\n  for (const edge of edges) {\n    if ((edge as { isLayoutOnly?: boolean }).isLayoutOnly) {\n      continue;\n    }\n    const points = dedupeConsecutivePoints((edge as { points?: PointLite[] }).points ?? []);\n    for (const segment of segmentsFor(points)) {\n      for (const lane of lanes) {\n        if (verticalSegmentIntersectsTitle(segment, lane.rect)) {\n          leftDelta = Math.max(leftDelta, lane.rect.right - segment.a.x + CLEARANCE);\n        } else if (horizontalSegmentIntersectsTitle(segment, lane.rect)) {\n          const segmentLeft = Math.min(segment.a.x, segment.b.x);\n          leftDelta = Math.max(leftDelta, lane.rect.right - segmentLeft + CLEARANCE);\n        }\n      }\n    }\n  }\n\n  if (leftDelta <= EPS_LOCAL) {\n    return;\n  }\n\n  for (const lane of lanes) {\n    const x = (lane.node as { x?: number }).x;\n    const width = (lane.node as { width?: number }).width;\n    if (\n      typeof x !== 'number' ||\n      typeof width !== 'number' ||\n      !Number.isFinite(x) ||\n      !Number.isFinite(width) ||\n      width <= 0\n    ) {\n      continue;\n    }\n    lane.node.x = x - leftDelta / 2;\n    lane.node.width = width + leftDelta;\n    lane.node.groupTitleRect = {\n      ...lane.rect,\n      left: lane.rect.left - leftDelta,\n      right: lane.rect.right - leftDelta,\n    };\n  }\n}\n\nexport function swapDestinationTerminalTailsToReduceCrossings(\n  edges: MaterializedEdge[],\n  nodeByIdMap: Map<string, MaterializedNode>\n): void {\n  const BUFFER = 2;\n  const MAX_ITERATIONS = 4;\n\n  interface TerminalTail {\n    tailStart: PointLite;\n    terminal: PointLite;\n  }\n\n  const { realNodeRects } = collectNodeRectEntries(nodeByIdMap.values());\n  const visibleEdges = edges.filter((edge) => !(edge as { isLayoutOnly?: boolean }).isLayoutOnly);\n\n  const replacementPointsFor = (\n    edge: MaterializedEdge,\n    replacements: EdgeReplacementMap = new Map()\n  ): PointLite[] =>\n    dedupeConsecutivePoints(\n      replacements.get(edge) ?? (edge as { points?: PointLite[] }).points ?? []\n    );\n\n  const crossingCount = (replacements: EdgeReplacementMap = new Map()): number => {\n    let count = 0;\n    for (let i = 0; i < visibleEdges.length; i++) {\n      const firstSegments = segmentsFor(replacementPointsFor(visibleEdges[i], replacements));\n      for (let j = i + 1; j < visibleEdges.length; j++) {\n        const secondSegments = segmentsFor(replacementPointsFor(visibleEdges[j], replacements));\n        for (const firstSegment of firstSegments) {\n          for (const secondSegment of secondSegments) {\n            if (\n              orthogonalSegmentsStrictlyCross(\n                firstSegment.a,\n                firstSegment.b,\n                secondSegment.a,\n                secondSegment.b,\n                EPS_LOCAL\n              )\n            ) {\n              count++;\n            }\n          }\n        }\n      }\n    }\n    return count;\n  };\n\n  const totalBends = (replacements: EdgeReplacementMap = new Map()): number =>\n    visibleEdges.reduce(\n      (sum, edge) => sum + countOrthogonalBends(replacementPointsFor(edge, replacements)),\n      0\n    );\n\n  const terminalTailFor = (edge: MaterializedEdge): TerminalTail | undefined => {\n    const points = replacementPointsFor(edge);\n    if (points.length < 4) {\n      return undefined;\n    }\n    const tailStart = points[points.length - 2];\n    const terminal = points[points.length - 1];\n    if (\n      !isHorizontalSegment(tailStart, terminal, EPS_LOCAL) &&\n      !isVerticalSegment(tailStart, terminal, EPS_LOCAL)\n    ) {\n      return undefined;\n    }\n    return { tailStart, terminal };\n  };\n\n  const candidateWithDestinationTail = (\n    edge: MaterializedEdge,\n    tail: TerminalTail\n  ): PointLite[] | undefined => {\n    const points = replacementPointsFor(edge);\n    if (points.length < 3) {\n      return undefined;\n    }\n    const start = points[0];\n    const firstTurn = points[1];\n\n    let connector: PointLite;\n    if (isHorizontalSegment(start, firstTurn, EPS_LOCAL)) {\n      connector = { x: firstTurn.x, y: tail.tailStart.y };\n    } else if (isVerticalSegment(start, firstTurn, EPS_LOCAL)) {\n      connector = { x: tail.tailStart.x, y: firstTurn.y };\n    } else {\n      return undefined;\n    }\n\n    const candidate = simplifyPolyline(\n      dedupeConsecutivePoints([start, firstTurn, connector, tail.tailStart, tail.terminal])\n    );\n    return segmentsFor(candidate).length === candidate.length - 1 ? candidate : undefined;\n  };\n\n  const pathHasNodeHit = (edge: MaterializedEdge, path: PointLite[]): boolean => {\n    const endpointIds = [(edge as { start?: string }).start, (edge as { end?: string }).end].filter(\n      (id): id is string => Boolean(id)\n    );\n    for (const segment of segmentsFor(path)) {\n      if (segmentHitsAnyRect(segment.a, segment.b, realNodeRects, endpointIds, -BUFFER)) {\n        return true;\n      }\n    }\n    return false;\n  };\n\n  const pathHasSharedTrack = (\n    edge: MaterializedEdge,\n    path: PointLite[],\n    replacements: EdgeReplacementMap\n  ): boolean => {\n    for (const other of visibleEdges) {\n      if (other === edge) {\n        continue;\n      }\n      for (const candidateSegment of segmentsFor(path)) {\n        for (const otherSegment of segmentsFor(replacementPointsFor(other, replacements))) {\n          if (sameAxisSegmentOverlapLength(candidateSegment, otherSegment, 0.5) >= MIN_SHARED) {\n            return true;\n          }\n        }\n      }\n    }\n    return false;\n  };\n\n  const candidateIsSafe = (\n    edge: MaterializedEdge,\n    path: PointLite[],\n    replacements: EdgeReplacementMap\n  ): boolean => !pathHasNodeHit(edge, path) && !pathHasSharedTrack(edge, path, replacements);\n\n  const edgesByDestination = (): Map<string, MaterializedEdge[]> => {\n    const result = new Map<string, MaterializedEdge[]>();\n    for (const edge of visibleEdges) {\n      const dstId = (edge as { end?: string }).end;\n      if (!dstId || !nodeByIdMap.has(dstId)) {\n        continue;\n      }\n      const points = replacementPointsFor(edge);\n      if (points.length < 4) {\n        continue;\n      }\n      const bucket = result.get(dstId) ?? [];\n      bucket.push(edge);\n      result.set(dstId, bucket);\n    }\n    return result;\n  };\n\n  for (let iteration = 0; iteration < MAX_ITERATIONS; iteration++) {\n    const currentCrossings = crossingCount();\n    if (currentCrossings === 0) {\n      return;\n    }\n    const currentBends = totalBends();\n\n    let bestReplacements: EdgeReplacementMap | undefined;\n    let bestCrossings = currentCrossings;\n    let bestBends = currentBends;\n\n    for (const destinationEdges of edgesByDestination().values()) {\n      for (let i = 0; i < destinationEdges.length; i++) {\n        for (let j = i + 1; j < destinationEdges.length; j++) {\n          const first = destinationEdges[i];\n          const second = destinationEdges[j];\n          const firstTail = terminalTailFor(first);\n          const secondTail = terminalTailFor(second);\n          if (!firstTail || !secondTail) {\n            continue;\n          }\n\n          const firstCandidate = candidateWithDestinationTail(first, secondTail);\n          const secondCandidate = candidateWithDestinationTail(second, firstTail);\n          if (!firstCandidate || !secondCandidate) {\n            continue;\n          }\n\n          const replacements = new Map<MaterializedEdge, PointLite[]>([\n            [first, firstCandidate],\n            [second, secondCandidate],\n          ]);\n          if (\n            !candidateIsSafe(first, firstCandidate, replacements) ||\n            !candidateIsSafe(second, secondCandidate, replacements)\n          ) {\n            continue;\n          }\n\n          const candidateCrossings = crossingCount(replacements);\n          const candidateBends = totalBends(replacements);\n          if (candidateCrossings >= currentCrossings) {\n            continue;\n          }\n          if (\n            candidateCrossings > bestCrossings ||\n            (candidateCrossings === bestCrossings && candidateBends >= bestBends)\n          ) {\n            continue;\n          }\n          bestReplacements = replacements;\n          bestCrossings = candidateCrossings;\n          bestBends = candidateBends;\n        }\n      }\n    }\n\n    if (!bestReplacements) {\n      return;\n    }\n\n    for (const [edge, points] of bestReplacements) {\n      (edge as { points: PointLite[] }).points = points;\n    }\n  }\n}\n\n// Crossing cleanup sometimes requires reordering a small channel bundle as a\n// transaction: moving either rail alone is neutral or worse, while swapping the\n// shared external tracks removes crossings. Keep the search local and bounded,\n// but score it globally so crossing count stays the first acceptance criterion.\nexport function reassignCrossingExternalRailChannels(\n  edges: MaterializedEdge[],\n  nodeByIdMap: Map<string, MaterializedNode>\n): void {\n  const BUFFER = 2;\n  const RAIL_CHANNEL_GAP = 12;\n  const MAX_ITERATIONS = 4;\n  const MAX_EXHAUSTIVE_COMPONENT = 6;\n\n  type RailAxis = 'horizontal' | 'vertical';\n\n  interface ExternalRail {\n    edge: MaterializedEdge;\n    points: PointLite[];\n    segmentIndex: number;\n    axis: RailAxis;\n    side: RectSide;\n    coord: number;\n    min: number;\n    max: number;\n  }\n\n  const { realNodeRects, labelNodeRects: labelRects } = collectNodeRectEntries(\n    nodeByIdMap.values()\n  );\n  const visibleEdges = edges.filter((edge) => !(edge as { isLayoutOnly?: boolean }).isLayoutOnly);\n\n  const replacementPointsFor = (\n    edge: MaterializedEdge,\n    replacements: EdgeReplacementMap = new Map()\n  ): PointLite[] =>\n    dedupeConsecutivePoints(\n      replacements.get(edge) ?? (edge as { points?: PointLite[] }).points ?? []\n    );\n\n  const strictCrossingCount = (replacements: EdgeReplacementMap = new Map()): number => {\n    let count = 0;\n    for (let i = 0; i < visibleEdges.length; i++) {\n      const firstSegments = segmentsFor(replacementPointsFor(visibleEdges[i], replacements));\n      for (let j = i + 1; j < visibleEdges.length; j++) {\n        const secondSegments = segmentsFor(replacementPointsFor(visibleEdges[j], replacements));\n        for (const firstSegment of firstSegments) {\n          for (const secondSegment of secondSegments) {\n            if (\n              orthogonalSegmentsStrictlyCross(\n                firstSegment.a,\n                firstSegment.b,\n                secondSegment.a,\n                secondSegment.b,\n                EPS_LOCAL\n              )\n            ) {\n              count++;\n            }\n          }\n        }\n      }\n    }\n    return count;\n  };\n\n  const totalBends = (replacements: EdgeReplacementMap = new Map()): number =>\n    visibleEdges.reduce(\n      (sum, edge) => sum + countOrthogonalBends(replacementPointsFor(edge, replacements)),\n      0\n    );\n\n  const endpointRectsFor = (\n    edge: MaterializedEdge\n  ): { src: RectLite; dst: RectLite } | undefined => {\n    const srcId = (edge as { start?: string }).start;\n    const dstId = (edge as { end?: string }).end;\n    const srcNode = srcId ? nodeByIdMap.get(srcId) : undefined;\n    const dstNode = dstId ? nodeByIdMap.get(dstId) : undefined;\n    const src = srcNode ? rectOfNodeBounds(srcNode) : undefined;\n    const dst = dstNode ? rectOfNodeBounds(dstNode) : undefined;\n    return src && dst ? { src, dst } : undefined;\n  };\n\n  const externalRailForSegment = (\n    edge: MaterializedEdge,\n    points: PointLite[],\n    segment: SegmentLite\n  ): ExternalRail | undefined => {\n    if (segment.index <= 0 || segment.index + 1 >= points.length - 1) {\n      return undefined;\n    }\n\n    const endpointRects = endpointRectsFor(edge);\n    if (!endpointRects) {\n      return undefined;\n    }\n\n    if (segment.vertical) {\n      const coord = segment.a.x;\n      const leftBound = Math.min(endpointRects.src.left, endpointRects.dst.left);\n      const rightBound = Math.max(endpointRects.src.right, endpointRects.dst.right);\n      const side: RectSide | undefined =\n        coord < leftBound - EPS_LOCAL\n          ? 'left'\n          : coord > rightBound + EPS_LOCAL\n            ? 'right'\n            : undefined;\n      if (!side) {\n        return undefined;\n      }\n      return {\n        edge,\n        points,\n        segmentIndex: segment.index,\n        axis: 'vertical',\n        side,\n        coord,\n        min: Math.min(segment.a.y, segment.b.y),\n        max: Math.max(segment.a.y, segment.b.y),\n      };\n    }\n\n    if (segment.horizontal) {\n      const coord = segment.a.y;\n      const topBound = Math.min(endpointRects.src.top, endpointRects.dst.top);\n      const bottomBound = Math.max(endpointRects.src.bottom, endpointRects.dst.bottom);\n      const side: RectSide | undefined =\n        coord < topBound - EPS_LOCAL\n          ? 'top'\n          : coord > bottomBound + EPS_LOCAL\n            ? 'bottom'\n            : undefined;\n      if (!side) {\n        return undefined;\n      }\n      return {\n        edge,\n        points,\n        segmentIndex: segment.index,\n        axis: 'horizontal',\n        side,\n        coord,\n        min: Math.min(segment.a.x, segment.b.x),\n        max: Math.max(segment.a.x, segment.b.x),\n      };\n    }\n\n    return undefined;\n  };\n\n  const collectExternalRails = (): ExternalRail[] => {\n    const rails: ExternalRail[] = [];\n    for (const edge of visibleEdges) {\n      const points = replacementPointsFor(edge);\n      for (const segment of segmentsFor(points)) {\n        const rail = externalRailForSegment(edge, points, segment);\n        if (rail) {\n          rails.push(rail);\n        }\n      }\n    }\n    return rails;\n  };\n\n  const railsInteract = (a: ExternalRail, b: ExternalRail): boolean =>\n    a.edge !== b.edge &&\n    a.axis === b.axis &&\n    a.side === b.side &&\n    overlapLength(a.min, a.max, b.min, b.max) >= MIN_SHARED;\n\n  const connectedComponents = (rails: ExternalRail[]): ExternalRail[][] => {\n    const result: ExternalRail[][] = [];\n    const seen = new Set<ExternalRail>();\n    for (const rail of rails) {\n      if (seen.has(rail)) {\n        continue;\n      }\n      const queue = [rail];\n      const component: ExternalRail[] = [];\n      seen.add(rail);\n      while (queue.length > 0) {\n        const current = queue.pop()!;\n        component.push(current);\n        for (const next of rails) {\n          if (!seen.has(next) && railsInteract(current, next)) {\n            seen.add(next);\n            queue.push(next);\n          }\n        }\n      }\n      if (component.length > 1) {\n        result.push(component);\n      }\n    }\n    return result;\n  };\n\n  const uniqueCoordsFor = (component: ExternalRail[]): number[] => {\n    const coords: number[] = [];\n    for (const rail of component) {\n      if (!coords.some((coord) => Math.abs(coord - rail.coord) < EPS_LOCAL)) {\n        coords.push(rail.coord);\n      }\n    }\n\n    while (coords.length < component.length) {\n      const min = Math.min(...coords);\n      const max = Math.max(...coords);\n      const side = component[0].side;\n      coords.push(\n        side === 'left' || side === 'top'\n          ? min - RAIL_CHANNEL_GAP * (component.length - coords.length)\n          : max + RAIL_CHANNEL_GAP * (component.length - coords.length)\n      );\n    }\n    return coords;\n  };\n\n  const coordinateAssignmentsFor = (component: ExternalRail[]): number[][] => {\n    const current = component.map((rail) => rail.coord);\n    const coords = uniqueCoordsFor(component);\n    const assignments: number[][] = [];\n\n    if (component.length <= MAX_EXHAUSTIVE_COMPONENT) {\n      const used = new Array(coords.length).fill(false);\n      const next: number[] = [];\n      const visit = () => {\n        if (next.length === component.length) {\n          if (next.some((coord, index) => Math.abs(coord - current[index]) >= EPS_LOCAL)) {\n            assignments.push([...next]);\n          }\n          return;\n        }\n        for (const [i, coord] of coords.entries()) {\n          if (used[i]) {\n            continue;\n          }\n          used[i] = true;\n          next.push(coord);\n          visit();\n          next.pop();\n          used[i] = false;\n        }\n      };\n      visit();\n      return assignments;\n    }\n\n    for (let i = 0; i < current.length; i++) {\n      for (let j = i + 1; j < current.length; j++) {\n        const assignment = [...current];\n        [assignment[i], assignment[j]] = [assignment[j], assignment[i]];\n        assignments.push(assignment);\n      }\n    }\n    return assignments;\n  };\n\n  const replacementsForAssignment = (\n    component: ExternalRail[],\n    assignment: number[]\n  ): EdgeReplacementMap | undefined => {\n    const draftByEdge = new Map<MaterializedEdge, PointLite[]>();\n    for (const [i, rail] of component.entries()) {\n      const coord = assignment[i];\n      const points =\n        draftByEdge.get(rail.edge) ?? rail.points.map((point) => ({ x: point.x, y: point.y }));\n      if (rail.axis === 'vertical') {\n        points[rail.segmentIndex].x = coord;\n        points[rail.segmentIndex + 1].x = coord;\n      } else {\n        points[rail.segmentIndex].y = coord;\n        points[rail.segmentIndex + 1].y = coord;\n      }\n      draftByEdge.set(rail.edge, points);\n    }\n\n    const replacements = new Map<MaterializedEdge, PointLite[]>();\n    for (const [edge, points] of draftByEdge) {\n      const simplified = simplifyPolyline(dedupeConsecutivePoints(points));\n      if (segmentsFor(simplified).length !== simplified.length - 1) {\n        return undefined;\n      }\n      replacements.set(edge, simplified);\n    }\n    return replacements;\n  };\n\n  const candidateIsSafe = (replacements: EdgeReplacementMap): boolean => {\n    for (const [edge, points] of replacements) {\n      const endpointIds = [\n        (edge as { start?: string }).start,\n        (edge as { end?: string }).end,\n      ].filter((id): id is string => Boolean(id));\n      for (const segment of segmentsFor(points)) {\n        if (segmentHitsAnyRect(segment.a, segment.b, realNodeRects, endpointIds, -BUFFER)) {\n          return false;\n        }\n        if (segmentHitsAnyRect(segment.a, segment.b, labelRects, [], -BUFFER)) {\n          return false;\n        }\n      }\n    }\n\n    for (let i = 0; i < visibleEdges.length; i++) {\n      const first = visibleEdges[i];\n      const firstChanged = replacements.has(first);\n      const firstSegments = segmentsFor(replacementPointsFor(first, replacements));\n      for (let j = i + 1; j < visibleEdges.length; j++) {\n        const second = visibleEdges[j];\n        if (!firstChanged && !replacements.has(second)) {\n          continue;\n        }\n        const secondSegments = segmentsFor(replacementPointsFor(second, replacements));\n        for (const firstSegment of firstSegments) {\n          for (const secondSegment of secondSegments) {\n            if (sameAxisSegmentOverlapLength(firstSegment, secondSegment, 0.5) >= MIN_SHARED) {\n              return false;\n            }\n          }\n        }\n      }\n    }\n\n    return true;\n  };\n\n  for (let iteration = 0; iteration < MAX_ITERATIONS; iteration++) {\n    const currentCrossings = strictCrossingCount();\n    if (currentCrossings === 0) {\n      return;\n    }\n\n    let bestReplacements: EdgeReplacementMap | undefined;\n    let bestCrossings = currentCrossings;\n    let bestBends = totalBends();\n    let bestDisplacement = Number.POSITIVE_INFINITY;\n\n    for (const component of connectedComponents(collectExternalRails())) {\n      for (const assignment of coordinateAssignmentsFor(component)) {\n        const replacements = replacementsForAssignment(component, assignment);\n        if (!replacements || !candidateIsSafe(replacements)) {\n          continue;\n        }\n\n        const candidateCrossings = strictCrossingCount(replacements);\n        if (candidateCrossings >= currentCrossings) {\n          continue;\n        }\n        const candidateBends = totalBends(replacements);\n        const candidateDisplacement = component.reduce(\n          (sum, rail, index) => sum + Math.abs(assignment[index] - rail.coord),\n          0\n        );\n\n        if (\n          candidateCrossings > bestCrossings ||\n          (candidateCrossings === bestCrossings &&\n            (candidateBends > bestBends ||\n              (candidateBends === bestBends && candidateDisplacement >= bestDisplacement)))\n        ) {\n          continue;\n        }\n\n        bestReplacements = replacements;\n        bestCrossings = candidateCrossings;\n        bestBends = candidateBends;\n        bestDisplacement = candidateDisplacement;\n      }\n    }\n\n    if (!bestReplacements) {\n      return;\n    }\n\n    for (const [edge, points] of bestReplacements) {\n      (edge as { points: PointLite[] }).points = points;\n    }\n  }\n}\n\nexport function shortcutRedundantOrthogonalJogs(\n  edges: MaterializedEdge[],\n  nodeByIdMap: Map<string, MaterializedNode>\n): void {\n  const BUFFER = 2;\n  const MAX_ITERATIONS = 8;\n\n  const { realNodeRects, labelNodeRects: labelRects } = collectNodeRectEntries(\n    nodeByIdMap.values()\n  );\n  const visibleEdges = edges.filter((edge) => !(edge as { isLayoutOnly?: boolean }).isLayoutOnly);\n\n  const pointsFor = (\n    edge: MaterializedEdge,\n    replacementEdge?: MaterializedEdge,\n    replacement?: PointLite[]\n  ): PointLite[] =>\n    dedupeConsecutivePoints(\n      edge === replacementEdge\n        ? (replacement ?? [])\n        : ((edge as { points?: PointLite[] }).points ?? [])\n    );\n\n  const pathLength = (points: PointLite[]): number =>\n    segmentsFor(points).reduce((sum, segment) => {\n      const dx = segment.a.x - segment.b.x;\n      const dy = segment.a.y - segment.b.y;\n      return sum + Math.hypot(dx, dy);\n    }, 0);\n\n  const strictCrossingCount = (\n    replacementEdge?: MaterializedEdge,\n    replacement?: PointLite[]\n  ): number => {\n    let count = 0;\n    for (let i = 0; i < visibleEdges.length; i++) {\n      const firstSegments = segmentsFor(pointsFor(visibleEdges[i], replacementEdge, replacement));\n      for (let j = i + 1; j < visibleEdges.length; j++) {\n        const secondSegments = segmentsFor(\n          pointsFor(visibleEdges[j], replacementEdge, replacement)\n        );\n        for (const firstSegment of firstSegments) {\n          for (const secondSegment of secondSegments) {\n            if (\n              orthogonalSegmentsStrictlyCross(\n                firstSegment.a,\n                firstSegment.b,\n                secondSegment.a,\n                secondSegment.b,\n                EPS_LOCAL\n              )\n            ) {\n              count++;\n            }\n          }\n        }\n      }\n    }\n    return count;\n  };\n\n  const segmentRunsAlongRectBorder = (segment: SegmentLite, rect: RectLite): boolean => {\n    if (segment.horizontal) {\n      const y = segment.a.y;\n      const onBorder = Math.abs(y - rect.top) < 1 || Math.abs(y - rect.bottom) < 1;\n      return (\n        onBorder && overlapLength(segment.a.x, segment.b.x, rect.left, rect.right) >= MIN_SHARED\n      );\n    }\n\n    if (segment.vertical) {\n      const x = segment.a.x;\n      const onBorder = Math.abs(x - rect.left) < 1 || Math.abs(x - rect.right) < 1;\n      return (\n        onBorder && overlapLength(segment.a.y, segment.b.y, rect.top, rect.bottom) >= MIN_SHARED\n      );\n    }\n\n    return false;\n  };\n\n  const endpointRectsFor = (edge: MaterializedEdge): RectLite[] => {\n    const endpointIds = [(edge as { start?: string }).start, (edge as { end?: string }).end].filter(\n      (id): id is string => Boolean(id)\n    );\n    const rects: RectLite[] = [];\n    for (const id of endpointIds) {\n      const node = nodeByIdMap.get(id);\n      const rect = node ? rectOfNodeBounds(node) : undefined;\n      if (rect) {\n        rects.push(rect);\n      }\n    }\n    return rects;\n  };\n\n  const shortcutCandidatesAt = (points: PointLite[], index: number): PointLite[][] => {\n    if (index + 3 >= points.length) {\n      return [];\n    }\n\n    const p0 = points[index];\n    const p1 = points[index + 1];\n    const p2 = points[index + 2];\n    const p3 = points[index + 3];\n    const isHVH =\n      isHorizontalSegment(p0, p1, EPS_LOCAL) &&\n      isVerticalSegment(p1, p2, EPS_LOCAL) &&\n      isHorizontalSegment(p2, p3, EPS_LOCAL);\n    const isVHV =\n      isVerticalSegment(p0, p1, EPS_LOCAL) &&\n      isHorizontalSegment(p1, p2, EPS_LOCAL) &&\n      isVerticalSegment(p2, p3, EPS_LOCAL);\n    if (!isHVH && !isVHV) {\n      return [];\n    }\n    const outerSegmentsOppose = isHVH\n      ? Math.sign(p1.x - p0.x) !== Math.sign(p3.x - p2.x)\n      : Math.sign(p1.y - p0.y) !== Math.sign(p3.y - p2.y);\n    if (!outerSegmentsOppose) {\n      return [];\n    }\n\n    const corners =\n      sameX(p0, p3, EPS_LOCAL) || sameY(p0, p3, EPS_LOCAL)\n        ? []\n        : [\n            { x: p0.x, y: p3.y },\n            { x: p3.x, y: p0.y },\n          ];\n    const rawCandidates =\n      corners.length === 0\n        ? [[...points.slice(0, index + 1), ...points.slice(index + 3)]]\n        : corners.map((corner) => [\n            ...points.slice(0, index + 1),\n            corner,\n            ...points.slice(index + 3),\n          ]);\n\n    const seen = new Set<string>();\n    return rawCandidates\n      .map((candidate) => simplifyPolyline(dedupeConsecutivePoints(candidate)))\n      .filter((candidate) => {\n        if (segmentsFor(candidate).length !== candidate.length - 1) {\n          return false;\n        }\n        if (!candidate.some((point) => samePoint(point, p3, EPS_LOCAL))) {\n          return false;\n        }\n        const key = candidate\n          .map((point) => `${point.x.toFixed(3)},${point.y.toFixed(3)}`)\n          .join('|');\n        if (seen.has(key)) {\n          return false;\n        }\n        seen.add(key);\n        return true;\n      });\n  };\n\n  const candidateIsSafe = (\n    edge: MaterializedEdge,\n    candidate: PointLite[],\n    currentCrossings: number\n  ): boolean => {\n    const endpointIds = [(edge as { start?: string }).start, (edge as { end?: string }).end].filter(\n      (id): id is string => Boolean(id)\n    );\n    const endpointRects = endpointRectsFor(edge);\n\n    for (const segment of segmentsFor(candidate)) {\n      if (segmentHitsAnyRect(segment.a, segment.b, realNodeRects, endpointIds, -BUFFER)) {\n        return false;\n      }\n      if (segmentHitsAnyRect(segment.a, segment.b, labelRects, [], -BUFFER)) {\n        return false;\n      }\n      if (endpointRects.some((rect) => segmentRunsAlongRectBorder(segment, rect))) {\n        return false;\n      }\n    }\n\n    for (const other of visibleEdges) {\n      if (other === edge) {\n        continue;\n      }\n      for (const candidateSegment of segmentsFor(candidate)) {\n        for (const otherSegment of segmentsFor(pointsFor(other))) {\n          if (sameAxisSegmentOverlapLength(candidateSegment, otherSegment, 0.5) >= MIN_SHARED) {\n            return false;\n          }\n        }\n      }\n    }\n\n    return strictCrossingCount(edge, candidate) <= currentCrossings;\n  };\n\n  for (let iteration = 0; iteration < MAX_ITERATIONS; iteration++) {\n    const currentCrossings = strictCrossingCount();\n    let bestEdge: { points?: PointLite[] } | undefined;\n    let bestPath: PointLite[] | undefined;\n    let bestCrossings = currentCrossings;\n    let bestBends = Number.POSITIVE_INFINITY;\n    let bestLength = Number.POSITIVE_INFINITY;\n\n    for (const edge of visibleEdges) {\n      const currentPoints = pointsFor(edge);\n      const currentBends = countOrthogonalBends(currentPoints, EPS_LOCAL);\n      const currentLength = pathLength(currentPoints);\n      for (let index = 0; index <= currentPoints.length - 4; index++) {\n        for (const candidate of shortcutCandidatesAt(currentPoints, index)) {\n          const candidateBends = countOrthogonalBends(candidate, EPS_LOCAL);\n          const candidateLength = pathLength(candidate);\n          const improvesShape =\n            candidateBends < currentBends ||\n            (candidateBends === currentBends && candidateLength < currentLength - EPS_LOCAL);\n          if (!improvesShape || !candidateIsSafe(edge, candidate, currentCrossings)) {\n            continue;\n          }\n\n          const candidateCrossings = strictCrossingCount(edge, candidate);\n          if (\n            candidateCrossings > bestCrossings ||\n            (candidateCrossings === bestCrossings &&\n              (candidateBends > bestBends ||\n                (candidateBends === bestBends && candidateLength >= bestLength)))\n          ) {\n            continue;\n          }\n\n          bestEdge = edge;\n          bestPath = candidate;\n          bestCrossings = candidateCrossings;\n          bestBends = candidateBends;\n          bestLength = candidateLength;\n        }\n      }\n    }\n\n    if (!bestEdge || !bestPath) {\n      return;\n    }\n\n    bestEdge.points = bestPath;\n  }\n}\n\nexport function resolveRenderedOrthogonalCrossings(\n  edges: MaterializedEdge[],\n  nodeByIdMap: Map<string, MaterializedNode>\n): void {\n  const ANCHOR = 20;\n  const EXTRA_CHANNEL_COUNT = 2;\n  const MAX_ITERATIONS = 4;\n  const MAX_PAIR_CANDIDATES_PER_EDGE = 48;\n\n  interface NodeInfo {\n    id: string;\n    cx: number;\n    cy: number;\n    rect: RectLite;\n  }\n\n  interface CrossingPair {\n    first: MaterializedEdge;\n    second: MaterializedEdge;\n    count: number;\n  }\n\n  interface CrossingSnapshot {\n    count: number;\n    pairs: CrossingPair[];\n    edgeSet: Set<MaterializedEdge>;\n    edges: MaterializedEdge[];\n  }\n\n  interface PairCandidate {\n    path: PointLite[];\n    segments: SegmentLite[];\n    sharedTrackConflicts: Set<MaterializedEdge>;\n    totalBends: number;\n    length: number;\n  }\n\n  interface PairOption {\n    edge: MaterializedEdge;\n    candidates: PairCandidate[];\n  }\n\n  interface PairReplacementScore {\n    replacements: EdgeReplacementMap;\n    crossings: number;\n    bends: number;\n    length: number;\n  }\n\n  interface PairScoringContext {\n    current: CrossingSnapshot;\n    currentBends: number;\n    currentLength: number;\n    baseBendsByEdge: Map<MaterializedEdge, number>;\n    baseLengthByEdge: Map<MaterializedEdge, number>;\n    baseSegments: Map<MaterializedEdge, SegmentLite[]>;\n  }\n\n  const realNodes: NodeInfo[] = [];\n  for (const node of nodeByIdMap.values()) {\n    if (\n      (node as { isGroup?: boolean }).isGroup ||\n      (node as { isEdgeLabel?: boolean }).isEdgeLabel\n    ) {\n      continue;\n    }\n    const cx = (node as { x?: number }).x ?? 0;\n    const cy = (node as { y?: number }).y ?? 0;\n    const rect = rectOfNodeBounds(node);\n    if (!rect) {\n      continue;\n    }\n    realNodes.push({\n      id: String((node as { id?: string }).id ?? ''),\n      cx,\n      cy,\n      rect,\n    });\n  }\n\n  if (realNodes.length === 0) {\n    return;\n  }\n\n  const nodeInfoById = new Map(realNodes.map((node) => [node.id, node]));\n  const realNodeRects = realNodes.map((node) => ({ id: node.id, rect: node.rect }));\n  const sides: RectSide[] = ['top', 'bottom', 'left', 'right'];\n  const outsideTracks = {\n    top: Math.min(...realNodes.map((node) => node.rect.top)) - ANCHOR,\n    bottom: Math.max(...realNodes.map((node) => node.rect.bottom)) + ANCHOR,\n    left: Math.min(...realNodes.map((node) => node.rect.left)) - ANCHOR,\n    right: Math.max(...realNodes.map((node) => node.rect.right)) + ANCHOR,\n  };\n\n  const visibleEdges = edges.filter((edge) => !(edge as { isLayoutOnly?: boolean }).isLayoutOnly);\n  const edgeIndex = new Map(visibleEdges.map((edge, index) => [edge, index]));\n\n  const outwardTracksForSide = (side: RectSide): number[] => {\n    const outward = side === 'left' || side === 'top' ? -1 : 1;\n    const tracks: number[] = [];\n    for (let channel = 0; channel <= EXTRA_CHANNEL_COUNT; channel++) {\n      tracks.push(outsideTracks[side] + outward * ANCHOR * channel);\n    }\n    return tracks;\n  };\n\n  const replacementPointsFor = (\n    edge: MaterializedEdge,\n    replacements: EdgeReplacementMap = new Map()\n  ): PointLite[] =>\n    dedupeConsecutivePoints(\n      replacements.get(edge) ?? (edge as { points?: PointLite[] }).points ?? []\n    );\n\n  const crossingCountBetweenSegments = (\n    firstSegments: SegmentLite[],\n    secondSegments: SegmentLite[]\n  ): number => {\n    let count = 0;\n    for (const firstSegment of firstSegments) {\n      for (const secondSegment of secondSegments) {\n        if (\n          orthogonalSegmentsStrictlyCross(\n            firstSegment.a,\n            firstSegment.b,\n            secondSegment.a,\n            secondSegment.b,\n            EPS_LOCAL\n          )\n        ) {\n          count++;\n        }\n      }\n    }\n    return count;\n  };\n\n  const crossingCountBetweenPaths = (first: PointLite[], second: PointLite[]): number =>\n    crossingCountBetweenSegments(segmentsFor(first), segmentsFor(second));\n\n  const crossingSnapshot = (replacements: EdgeReplacementMap = new Map()): CrossingSnapshot => {\n    let count = 0;\n    const pairs: CrossingPair[] = [];\n    const edgeSet = new Set<MaterializedEdge>();\n    const edgeOrder: MaterializedEdge[] = [];\n    const addEdge = (edge: MaterializedEdge): void => {\n      if (!edgeSet.has(edge)) {\n        edgeSet.add(edge);\n        edgeOrder.push(edge);\n      }\n    };\n\n    for (let i = 0; i < visibleEdges.length; i++) {\n      const first = visibleEdges[i];\n      const firstPoints = replacementPointsFor(first, replacements);\n      for (let j = i + 1; j < visibleEdges.length; j++) {\n        const second = visibleEdges[j];\n        const pairCount = crossingCountBetweenPaths(\n          firstPoints,\n          replacementPointsFor(second, replacements)\n        );\n        if (pairCount > 0) {\n          count += pairCount;\n          pairs.push({ first, second, count: pairCount });\n          addEdge(first);\n          addEdge(second);\n        }\n      }\n    }\n\n    edgeOrder.sort((a, b) => (edgeIndex.get(a) ?? 0) - (edgeIndex.get(b) ?? 0));\n    return {\n      count,\n      pairs,\n      edgeSet,\n      edges: edgeOrder,\n    };\n  };\n\n  const crossingCountWithReplacements = (\n    current: CrossingSnapshot,\n    replacements: EdgeReplacementMap\n  ): number => {\n    const changed = new Set(replacements.keys());\n    if (changed.size === 0) {\n      return current.count;\n    }\n\n    let currentAffected = 0;\n    for (const pair of current.pairs) {\n      if (changed.has(pair.first) || changed.has(pair.second)) {\n        currentAffected += pair.count;\n      }\n    }\n\n    let replacementAffected = 0;\n    for (let i = 0; i < visibleEdges.length; i++) {\n      const first = visibleEdges[i];\n      const firstChanged = changed.has(first);\n      const firstPoints = replacementPointsFor(first, replacements);\n      for (let j = i + 1; j < visibleEdges.length; j++) {\n        const second = visibleEdges[j];\n        if (!firstChanged && !changed.has(second)) {\n          continue;\n        }\n        replacementAffected += crossingCountBetweenPaths(\n          firstPoints,\n          replacementPointsFor(second, replacements)\n        );\n      }\n    }\n\n    return current.count - currentAffected + replacementAffected;\n  };\n\n  const crossingComponents = (snapshot: CrossingSnapshot): MaterializedEdge[][] => {\n    const neighbors = new Map<MaterializedEdge, Set<MaterializedEdge>>();\n    for (const pair of snapshot.pairs) {\n      const firstNeighbors = neighbors.get(pair.first) ?? new Set<MaterializedEdge>();\n      firstNeighbors.add(pair.second);\n      neighbors.set(pair.first, firstNeighbors);\n\n      const secondNeighbors = neighbors.get(pair.second) ?? new Set<MaterializedEdge>();\n      secondNeighbors.add(pair.first);\n      neighbors.set(pair.second, secondNeighbors);\n    }\n\n    const components: MaterializedEdge[][] = [];\n    const seen = new Set<MaterializedEdge>();\n    for (const edge of snapshot.edges) {\n      if (seen.has(edge)) {\n        continue;\n      }\n      const queue = [edge];\n      const component: MaterializedEdge[] = [];\n      seen.add(edge);\n      while (queue.length > 0) {\n        const current = queue.pop()!;\n        component.push(current);\n        for (const next of neighbors.get(current) ?? []) {\n          if (!seen.has(next)) {\n            seen.add(next);\n            queue.push(next);\n          }\n        }\n      }\n      component.sort((a, b) => (edgeIndex.get(a) ?? 0) - (edgeIndex.get(b) ?? 0));\n      if (component.length > 1) {\n        components.push(component);\n      }\n    }\n\n    return components;\n  };\n\n  const endpointIdsFor = (edge: MaterializedEdge): string[] =>\n    [(edge as { start?: string }).start, (edge as { end?: string }).end].filter(\n      (id): id is string => Boolean(id)\n    );\n\n  const pairSearchGroups = (snapshot: CrossingSnapshot): MaterializedEdge[][] => {\n    const groups: MaterializedEdge[][] = [];\n    for (const component of crossingComponents(snapshot)) {\n      const componentSet = new Set(component);\n      const componentEndpointIds = new Set(component.flatMap((edge) => endpointIdsFor(edge)));\n      const group = [...component];\n      for (const edge of visibleEdges) {\n        if (componentSet.has(edge)) {\n          continue;\n        }\n        if (endpointIdsFor(edge).some((id) => componentEndpointIds.has(id))) {\n          group.push(edge);\n        }\n      }\n      group.sort((a, b) => (edgeIndex.get(a) ?? 0) - (edgeIndex.get(b) ?? 0));\n      groups.push(group);\n    }\n    return groups;\n  };\n\n  const crossingCountWithSingleReplacement = (\n    current: CrossingSnapshot,\n    edge: MaterializedEdge,\n    replacement: PointLite[]\n  ): number =>\n    crossingCountWithReplacements(\n      current,\n      new Map<MaterializedEdge, PointLite[]>([[edge, replacement]])\n    );\n\n  const currentCrossingsByEdge = (current: CrossingSnapshot): Map<MaterializedEdge, number> => {\n    const result = new Map<MaterializedEdge, number>();\n    for (const pair of current.pairs) {\n      result.set(pair.first, (result.get(pair.first) ?? 0) + pair.count);\n      result.set(pair.second, (result.get(pair.second) ?? 0) + pair.count);\n    }\n    return result;\n  };\n\n  const pathLength = (points: PointLite[]): number =>\n    points.slice(1).reduce((sum, point, index) => {\n      const previous = points[index];\n      return sum + Math.abs(point.x - previous.x) + Math.abs(point.y - previous.y);\n    }, 0);\n\n  const totalBends = (replacements: EdgeReplacementMap = new Map()): number =>\n    visibleEdges.reduce(\n      (sum, edge) => sum + countOrthogonalBends(replacementPointsFor(edge, replacements)),\n      0\n    );\n\n  const totalLength = (replacements: EdgeReplacementMap = new Map()): number =>\n    visibleEdges.reduce(\n      (sum, edge) => sum + pathLength(replacementPointsFor(edge, replacements)),\n      0\n    );\n\n  const pathHasSegmentConflict = (\n    edge: MaterializedEdge,\n    path: PointLite[],\n    replacements: EdgeReplacementMap = new Map()\n  ): boolean => {\n    const pathSegments = segmentsFor(path);\n    for (const other of visibleEdges) {\n      if (other === edge) {\n        continue;\n      }\n      for (const candidateSegment of pathSegments) {\n        for (const otherSegment of segmentsFor(replacementPointsFor(other, replacements))) {\n          if (sameAxisSegmentOverlapLength(candidateSegment, otherSegment, 0.5) >= MIN_SHARED) {\n            return true;\n          }\n        }\n      }\n    }\n    return false;\n  };\n\n  const pathHitsNode = (edge: MaterializedEdge, path: PointLite[]): boolean => {\n    const endpointIds = [(edge as { start?: string }).start, (edge as { end?: string }).end].filter(\n      (id): id is string => Boolean(id)\n    );\n    for (const segment of segmentsFor(path)) {\n      if (segmentHitsAnyRect(segment.a, segment.b, realNodeRects, endpointIds, -2)) {\n        return true;\n      }\n    }\n    return false;\n  };\n\n  const pushOrthogonalCandidate = (candidates: PointLite[][], points: PointLite[]): void => {\n    const candidate = simplifyPolyline(dedupeConsecutivePoints(points));\n    if (segmentsFor(candidate).length === candidate.length - 1) {\n      candidates.push(candidate);\n    }\n  };\n\n  const sideIsHorizontal = (side: RectSide): boolean => side === 'left' || side === 'right';\n\n  const localTrackForSameSide = (src: PointLite, side: RectSide, dst: PointLite): number => {\n    switch (side) {\n      case 'left':\n        return Math.min(src.x, dst.x) - ANCHOR;\n      case 'right':\n        return Math.max(src.x, dst.x) + ANCHOR;\n      case 'top':\n        return Math.min(src.y, dst.y) - ANCHOR;\n      case 'bottom':\n        return Math.max(src.y, dst.y) + ANCHOR;\n    }\n  };\n\n  const addSameSideCandidates = (\n    candidates: PointLite[][],\n    src: PointLite,\n    srcSide: RectSide,\n    dst: PointLite\n  ): void => {\n    const outward = srcSide === 'left' || srcSide === 'top' ? -1 : 1;\n    const trackSeeds = [localTrackForSameSide(src, srcSide, dst), outsideTracks[srcSide]];\n    for (const seed of trackSeeds) {\n      for (let channel = 0; channel <= EXTRA_CHANNEL_COUNT; channel++) {\n        pushOrthogonalCandidate(\n          candidates,\n          buildSameSideTrackPath(src, srcSide, dst, seed + outward * ANCHOR * channel)\n        );\n      }\n    }\n  };\n\n  const addHorizontalToVerticalCandidates = (\n    candidates: PointLite[][],\n    src: PointLite,\n    srcSide: RectSide,\n    dst: PointLite,\n    dstSide: RectSide\n  ): void => {\n    for (const xTrack of outwardTracksForSide(srcSide)) {\n      for (const yTrack of outwardTracksForSide(dstSide)) {\n        pushOrthogonalCandidate(candidates, [\n          src,\n          { x: xTrack, y: src.y },\n          { x: xTrack, y: yTrack },\n          { x: dst.x, y: yTrack },\n          dst,\n        ]);\n      }\n    }\n  };\n\n  const addVerticalToHorizontalCandidates = (\n    candidates: PointLite[][],\n    src: PointLite,\n    srcSide: RectSide,\n    dst: PointLite,\n    dstSide: RectSide\n  ): void => {\n    for (const yTrack of outwardTracksForSide(srcSide)) {\n      for (const xTrack of outwardTracksForSide(dstSide)) {\n        pushOrthogonalCandidate(candidates, [\n          src,\n          { x: src.x, y: yTrack },\n          { x: xTrack, y: yTrack },\n          { x: xTrack, y: dst.y },\n          dst,\n        ]);\n      }\n    }\n  };\n\n  const addHorizontalPairCandidates = (\n    candidates: PointLite[][],\n    src: PointLite,\n    srcSide: RectSide,\n    dst: PointLite,\n    dstSide: RectSide\n  ): void => {\n    const yTracks = [...outwardTracksForSide('top'), ...outwardTracksForSide('bottom')];\n    for (const srcTrack of outwardTracksForSide(srcSide)) {\n      for (const dstTrack of outwardTracksForSide(dstSide)) {\n        for (const yTrack of yTracks) {\n          pushOrthogonalCandidate(candidates, [\n            src,\n            { x: srcTrack, y: src.y },\n            { x: srcTrack, y: yTrack },\n            { x: dstTrack, y: yTrack },\n            { x: dstTrack, y: dst.y },\n            dst,\n          ]);\n        }\n      }\n    }\n  };\n\n  const addVerticalPairCandidates = (\n    candidates: PointLite[][],\n    src: PointLite,\n    srcSide: RectSide,\n    dst: PointLite,\n    dstSide: RectSide\n  ): void => {\n    const xTracks = [...outwardTracksForSide('left'), ...outwardTracksForSide('right')];\n    for (const srcTrack of outwardTracksForSide(srcSide)) {\n      for (const dstTrack of outwardTracksForSide(dstSide)) {\n        for (const xTrack of xTracks) {\n          pushOrthogonalCandidate(candidates, [\n            src,\n            { x: src.x, y: srcTrack },\n            { x: xTrack, y: srcTrack },\n            { x: xTrack, y: dstTrack },\n            { x: dst.x, y: dstTrack },\n            dst,\n          ]);\n        }\n      }\n    }\n  };\n\n  const dedupeCandidatePaths = (candidates: PointLite[][]): PointLite[][] => {\n    const seen = new Set<string>();\n    return candidates\n      .map((candidate) => dedupeConsecutivePoints(candidate))\n      .filter((candidate) => {\n        const key = candidate\n          .map((point) => `${point.x.toFixed(3)},${point.y.toFixed(3)}`)\n          .join('|');\n        if (seen.has(key) || candidate.length < 2) {\n          return false;\n        }\n        seen.add(key);\n        return true;\n      });\n  };\n\n  const buildCandidatesForSides = (\n    src: PointLite,\n    srcSide: RectSide,\n    dst: PointLite,\n    dstSide: RectSide\n  ): PointLite[][] => {\n    const candidates: PointLite[][] = [];\n    const base = buildOrthogonalPortPath(src, srcSide, dst, dstSide, ANCHOR, EPS_LOCAL);\n    if (base) {\n      pushOrthogonalCandidate(candidates, base);\n    }\n    if (srcSide === dstSide) {\n      addSameSideCandidates(candidates, src, srcSide, dst);\n    }\n\n    const srcHorizontal = sideIsHorizontal(srcSide);\n    const dstHorizontal = sideIsHorizontal(dstSide);\n    if (srcHorizontal && !dstHorizontal) {\n      addHorizontalToVerticalCandidates(candidates, src, srcSide, dst, dstSide);\n    } else if (!srcHorizontal && dstHorizontal) {\n      addVerticalToHorizontalCandidates(candidates, src, srcSide, dst, dstSide);\n    } else if (srcHorizontal) {\n      addHorizontalPairCandidates(candidates, src, srcSide, dst, dstSide);\n    } else {\n      addVerticalPairCandidates(candidates, src, srcSide, dst, dstSide);\n    }\n\n    return dedupeCandidatePaths(candidates);\n  };\n\n  const addVerticalDepartureOuterTrackCandidates = (\n    candidates: PointLite[][],\n    first: PointLite,\n    departure: PointLite,\n    dstNode: NodeInfo\n  ): void => {\n    const externalXTracks = [...outwardTracksForSide('left'), ...outwardTracksForSide('right')];\n    const externalYTracks = [...outwardTracksForSide('top'), ...outwardTracksForSide('bottom')];\n    for (const side of sides) {\n      const dst = portForRectSide(dstNode, side);\n      const targetYTracks =\n        side === 'top' || side === 'bottom' ? outwardTracksForSide(side) : externalYTracks;\n      for (const track of externalXTracks) {\n        pushOrthogonalCandidate(candidates, [\n          first,\n          departure,\n          { x: track, y: departure.y },\n          { x: track, y: dst.y },\n          dst,\n        ]);\n        for (const targetTrack of targetYTracks) {\n          pushOrthogonalCandidate(candidates, [\n            first,\n            departure,\n            { x: track, y: departure.y },\n            { x: track, y: targetTrack },\n            { x: dst.x, y: targetTrack },\n            dst,\n          ]);\n        }\n      }\n    }\n  };\n\n  const addHorizontalDepartureOuterTrackCandidates = (\n    candidates: PointLite[][],\n    first: PointLite,\n    departure: PointLite,\n    dstNode: NodeInfo\n  ): void => {\n    const externalXTracks = [...outwardTracksForSide('left'), ...outwardTracksForSide('right')];\n    const externalYTracks = [...outwardTracksForSide('top'), ...outwardTracksForSide('bottom')];\n    for (const side of sides) {\n      const dst = portForRectSide(dstNode, side);\n      const targetXTracks =\n        side === 'left' || side === 'right' ? outwardTracksForSide(side) : externalXTracks;\n      for (const track of externalYTracks) {\n        pushOrthogonalCandidate(candidates, [\n          first,\n          departure,\n          { x: departure.x, y: track },\n          { x: dst.x, y: track },\n          dst,\n        ]);\n        for (const targetTrack of targetXTracks) {\n          pushOrthogonalCandidate(candidates, [\n            first,\n            departure,\n            { x: departure.x, y: track },\n            { x: targetTrack, y: track },\n            { x: targetTrack, y: dst.y },\n            dst,\n          ]);\n        }\n      }\n    }\n  };\n\n  const terminalPreservingOuterTrackCandidates = (edge: MaterializedEdge): PointLite[][] => {\n    const srcId = (edge as { start?: string }).start;\n    const dstId = (edge as { end?: string }).end;\n    const dstNode = dstId ? nodeInfoById.get(dstId) : undefined;\n    if (!srcId || !dstNode) {\n      return [];\n    }\n\n    const points = dedupeConsecutivePoints((edge as { points?: PointLite[] }).points ?? []);\n    if (points.length < 4) {\n      return [];\n    }\n\n    const first = points[0];\n    const departure = points[1];\n    const candidates: PointLite[][] = [];\n    if (isVerticalSegment(first, departure, EPS_LOCAL)) {\n      addVerticalDepartureOuterTrackCandidates(candidates, first, departure, dstNode);\n    } else if (isHorizontalSegment(first, departure, EPS_LOCAL)) {\n      addHorizontalDepartureOuterTrackCandidates(candidates, first, departure, dstNode);\n    }\n\n    return candidates;\n  };\n\n  const candidatePathsFor = (edge: MaterializedEdge): PointLite[][] => {\n    const srcId = (edge as { start?: string }).start;\n    const dstId = (edge as { end?: string }).end;\n    const srcNode = srcId ? nodeInfoById.get(srcId) : undefined;\n    const dstNode = dstId ? nodeInfoById.get(dstId) : undefined;\n    if (!srcNode || !dstNode) {\n      return [];\n    }\n\n    const candidates: PointLite[][] = [];\n    for (const srcSide of sides) {\n      const srcPort = portForRectSide(srcNode, srcSide);\n      for (const dstSide of sides) {\n        candidates.push(\n          ...buildCandidatesForSides(srcPort, srcSide, portForRectSide(dstNode, dstSide), dstSide)\n        );\n      }\n    }\n    candidates.push(...terminalPreservingOuterTrackCandidates(edge));\n    return candidates;\n  };\n\n  const currentSegmentsByEdge = (): Map<MaterializedEdge, SegmentLite[]> =>\n    new Map(visibleEdges.map((edge) => [edge, segmentsFor(replacementPointsFor(edge))] as const));\n\n  const sharedTrackConflictsFor = (\n    edge: MaterializedEdge,\n    candidateSegments: SegmentLite[],\n    baseSegments: Map<MaterializedEdge, SegmentLite[]>\n  ): Set<MaterializedEdge> => {\n    const conflicts = new Set<MaterializedEdge>();\n    for (const other of visibleEdges) {\n      if (other === edge) {\n        continue;\n      }\n      const otherSegments = baseSegments.get(other) ?? segmentsFor(replacementPointsFor(other));\n      if (\n        candidateSegments.some((candidateSegment) =>\n          otherSegments.some(\n            (otherSegment) =>\n              sameAxisSegmentOverlapLength(candidateSegment, otherSegment, 0.5) >= MIN_SHARED\n          )\n        )\n      ) {\n        conflicts.add(other);\n      }\n    }\n    return conflicts;\n  };\n\n  const pairCandidatesFor = (\n    edge: MaterializedEdge,\n    current: CrossingSnapshot,\n    baseSegments: Map<MaterializedEdge, SegmentLite[]>,\n    crossingCountByEdge: Map<MaterializedEdge, number>\n  ): PairCandidate[] => {\n    const seen = new Set<string>();\n    const candidates = candidatePathsFor(edge)\n      .map((candidate) => simplifyPolyline(dedupeConsecutivePoints(candidate)))\n      .filter((candidate) => {\n        if (pathHitsNode(edge, candidate)) {\n          return false;\n        }\n        const key = candidate\n          .map((point) => `${point.x.toFixed(3)},${point.y.toFixed(3)}`)\n          .join('|');\n        if (seen.has(key) || candidate.length < 2) {\n          return false;\n        }\n        seen.add(key);\n        return true;\n      })\n      .map((candidate) => {\n        const candidateSegments = segmentsFor(candidate);\n        let replacementAffected = 0;\n        for (const other of visibleEdges) {\n          if (other === edge) {\n            continue;\n          }\n          replacementAffected += crossingCountBetweenSegments(\n            candidateSegments,\n            baseSegments.get(other) ?? segmentsFor(replacementPointsFor(other))\n          );\n        }\n        return {\n          candidate,\n          candidateSegments,\n          crossings: current.count - (crossingCountByEdge.get(edge) ?? 0) + replacementAffected,\n          bends: countOrthogonalBends(candidate, EPS_LOCAL),\n          totalBends: countOrthogonalBends(candidate),\n          length: pathLength(candidate),\n        };\n      })\n      .filter(({ crossings }) => crossings <= current.count)\n      .sort((a, b) => a.crossings - b.crossings || a.bends - b.bends || a.length - b.length);\n    return candidates.slice(0, MAX_PAIR_CANDIDATES_PER_EDGE).map((candidate) => {\n      return {\n        path: candidate.candidate,\n        segments: candidate.candidateSegments,\n        sharedTrackConflicts: sharedTrackConflictsFor(\n          edge,\n          candidate.candidateSegments,\n          baseSegments\n        ),\n        totalBends: candidate.totalBends,\n        length: candidate.length,\n      };\n    });\n  };\n\n  const pairCrossingCount = (\n    current: CrossingSnapshot,\n    firstEdge: MaterializedEdge,\n    firstCandidate: PairCandidate,\n    secondEdge: MaterializedEdge,\n    secondCandidate: PairCandidate,\n    baseSegments: Map<MaterializedEdge, SegmentLite[]>\n  ): number => {\n    let currentAffected = 0;\n    for (const pair of current.pairs) {\n      if (\n        pair.first === firstEdge ||\n        pair.second === firstEdge ||\n        pair.first === secondEdge ||\n        pair.second === secondEdge\n      ) {\n        currentAffected += pair.count;\n      }\n    }\n\n    let replacementAffected = crossingCountBetweenSegments(\n      firstCandidate.segments,\n      secondCandidate.segments\n    );\n    for (const other of visibleEdges) {\n      if (other === firstEdge || other === secondEdge) {\n        continue;\n      }\n      const otherSegments = baseSegments.get(other) ?? segmentsFor(replacementPointsFor(other));\n      replacementAffected +=\n        crossingCountBetweenSegments(firstCandidate.segments, otherSegments) +\n        crossingCountBetweenSegments(secondCandidate.segments, otherSegments);\n    }\n\n    return current.count - currentAffected + replacementAffected;\n  };\n\n  const conflictsOnlyWith = (candidate: PairCandidate, edge: MaterializedEdge): boolean => {\n    for (const conflict of candidate.sharedTrackConflicts) {\n      if (conflict !== edge) {\n        return false;\n      }\n    }\n    return true;\n  };\n\n  const candidatesShareTrack = (\n    firstCandidate: PairCandidate,\n    secondCandidate: PairCandidate\n  ): boolean =>\n    firstCandidate.segments.some((firstSegment) =>\n      secondCandidate.segments.some(\n        (secondSegment) =>\n          sameAxisSegmentOverlapLength(firstSegment, secondSegment, 0.5) >= MIN_SHARED\n      )\n    );\n\n  const pairCandidatesAreCompatible = (\n    first: PairOption,\n    firstCandidate: PairCandidate,\n    second: PairOption,\n    secondCandidate: PairCandidate\n  ): boolean =>\n    conflictsOnlyWith(firstCandidate, second.edge) &&\n    conflictsOnlyWith(secondCandidate, first.edge) &&\n    !candidatesShareTrack(firstCandidate, secondCandidate);\n\n  const scorePairReplacement = (\n    context: PairScoringContext,\n    first: PairOption,\n    firstCandidate: PairCandidate,\n    second: PairOption,\n    secondCandidate: PairCandidate\n  ): PairReplacementScore | undefined => {\n    const crossings = pairCrossingCount(\n      context.current,\n      first.edge,\n      firstCandidate,\n      second.edge,\n      secondCandidate,\n      context.baseSegments\n    );\n    if (crossings >= context.current.count) {\n      return undefined;\n    }\n\n    return {\n      replacements: new Map<MaterializedEdge, PointLite[]>([\n        [first.edge, firstCandidate.path],\n        [second.edge, secondCandidate.path],\n      ]),\n      crossings,\n      bends:\n        context.currentBends -\n        (context.baseBendsByEdge.get(first.edge) ?? 0) -\n        (context.baseBendsByEdge.get(second.edge) ?? 0) +\n        firstCandidate.totalBends +\n        secondCandidate.totalBends,\n      length:\n        context.currentLength -\n        (context.baseLengthByEdge.get(first.edge) ?? 0) -\n        (context.baseLengthByEdge.get(second.edge) ?? 0) +\n        firstCandidate.length +\n        secondCandidate.length,\n    };\n  };\n\n  const pairScoreIsBetter = (\n    candidate: PairReplacementScore,\n    best: PairReplacementScore\n  ): boolean =>\n    candidate.crossings < best.crossings ||\n    (candidate.crossings === best.crossings &&\n      (candidate.bends < best.bends ||\n        (candidate.bends === best.bends && candidate.length < best.length)));\n\n  const bestScoreForOptionPair = (\n    context: PairScoringContext,\n    first: PairOption,\n    second: PairOption,\n    best: PairReplacementScore\n  ): PairReplacementScore => {\n    let pairBest = best;\n    for (const firstCandidate of first.candidates) {\n      for (const secondCandidate of second.candidates) {\n        if (!pairCandidatesAreCompatible(first, firstCandidate, second, secondCandidate)) {\n          continue;\n        }\n        const score = scorePairReplacement(context, first, firstCandidate, second, secondCandidate);\n        if (score && pairScoreIsBetter(score, pairBest)) {\n          pairBest = score;\n        }\n      }\n    }\n    return pairBest;\n  };\n\n  const bestPairedReplacement = (current: CrossingSnapshot): EdgeReplacementMap | undefined => {\n    const currentBends = totalBends();\n    const currentLength = totalLength();\n    const baseSegments = currentSegmentsByEdge();\n    const crossingCountByEdge = currentCrossingsByEdge(current);\n    const baseBendsByEdge = new Map(\n      visibleEdges.map((edge) => [edge, countOrthogonalBends(replacementPointsFor(edge))] as const)\n    );\n    const baseLengthByEdge = new Map(\n      visibleEdges.map((edge) => [edge, pathLength(replacementPointsFor(edge))] as const)\n    );\n    const optionsByEdge = new Map<MaterializedEdge, PairOption>();\n    const groups = pairSearchGroups(current);\n    for (const group of groups) {\n      for (const edge of group) {\n        if (optionsByEdge.has(edge)) {\n          continue;\n        }\n        const candidates = pairCandidatesFor(edge, current, baseSegments, crossingCountByEdge);\n        if (candidates.length > 0) {\n          optionsByEdge.set(edge, { edge, candidates });\n        }\n      }\n    }\n\n    let best: PairReplacementScore = {\n      replacements: new Map(),\n      crossings: current.count,\n      bends: currentBends,\n      length: currentLength,\n    };\n    const scoringContext: PairScoringContext = {\n      current,\n      currentBends,\n      currentLength,\n      baseBendsByEdge,\n      baseLengthByEdge,\n      baseSegments,\n    };\n\n    for (const group of groups) {\n      const crossingEdgeSet = new Set(group.filter((edge) => current.edgeSet.has(edge)));\n      const options = group\n        .map((edge) => optionsByEdge.get(edge))\n        .filter((option): option is PairOption => Boolean(option));\n      for (let i = 0; i < options.length; i++) {\n        const first = options[i];\n        for (let j = i + 1; j < options.length; j++) {\n          const second = options[j];\n          if (!crossingEdgeSet.has(first.edge) && !crossingEdgeSet.has(second.edge)) {\n            continue;\n          }\n          best = bestScoreForOptionPair(scoringContext, first, second, best);\n        }\n      }\n    }\n\n    return best.replacements.size > 0 ? best.replacements : undefined;\n  };\n\n  for (let iteration = 0; iteration < MAX_ITERATIONS; iteration++) {\n    const current = crossingSnapshot();\n    const currentCrossings = current.count;\n    if (currentCrossings === 0) {\n      return;\n    }\n\n    let bestEdge: { points?: PointLite[] } | undefined;\n    let bestPath: PointLite[] | undefined;\n    let bestCrossings = currentCrossings;\n    let bestBends = Number.POSITIVE_INFINITY;\n\n    for (const edge of current.edges) {\n      const currentEdgeBends = countOrthogonalBends(replacementPointsFor(edge), EPS_LOCAL);\n      for (const candidate of candidatePathsFor(edge)) {\n        const candidateHitsNode = pathHitsNode(edge, candidate);\n        const candidateHasSegmentConflict =\n          !candidateHitsNode && pathHasSegmentConflict(edge, candidate);\n        const candidateCrossings = crossingCountWithSingleReplacement(current, edge, candidate);\n        const candidateBends = countOrthogonalBends(candidate, EPS_LOCAL);\n        if (candidateHitsNode || candidateHasSegmentConflict) {\n          continue;\n        }\n        const improvesCurrentEdge =\n          candidateCrossings < currentCrossings ||\n          (candidateCrossings === currentCrossings && candidateBends < currentEdgeBends);\n        if (!improvesCurrentEdge) {\n          continue;\n        }\n        if (\n          candidateCrossings > bestCrossings ||\n          (candidateCrossings === bestCrossings && candidateBends >= bestBends)\n        ) {\n          continue;\n        }\n        bestEdge = edge;\n        bestPath = candidate;\n        bestCrossings = candidateCrossings;\n        bestBends = candidateBends;\n      }\n    }\n\n    if (bestEdge && bestPath) {\n      bestEdge.points = bestPath;\n      continue;\n    }\n\n    const pairedReplacement = bestPairedReplacement(current);\n    if (!pairedReplacement) {\n      return;\n    }\n    for (const [edge, points] of pairedReplacement) {\n      (edge as { points: PointLite[] }).points = points;\n    }\n  }\n}\n", "// cspell:ignore Hegemann Wybrow\n\nimport type { NodeBoundsInfo } from './geometry.js';\nimport {\n  buildOrthogonalPortPath,\n  buildSameSideTrackPath,\n  collectRealNodeBounds,\n  countOrthogonalBends,\n  orthogonalSegmentsCross,\n  orthogonalSegmentsForPoints,\n  portForRectSide,\n  sameAxisSegmentOverlapLength,\n  segmentHitsAnyRect,\n} from './geometry.js';\nimport type { RectSide } from './geometry.js';\n\nconst EPS = 1e-3;\nconst MIN_SHARED = 8;\n\nexport function simplifyDetouredEdges(edges: any[], nodes: any[]): void {\n  const { nodeInfoById, realNodeRects } = collectRealNodeBounds(nodes);\n\n  const sides: RectSide[] = ['top', 'bottom', 'left', 'right'];\n\n  // Anchor offset for port exit. Each port's first/last segment must\n  // extend in the port's perpendicular direction by at least this many\n  // units before turning, so (a) the port-direction check in\n  // validateLayout is satisfied and (b) the segment does not hug the\n  // node's boundary. Matches raykov's ANCHOR_OFFSET.\n  const ANCHOR = 20;\n\n  const outsideTracks = {\n    top: Math.min(...realNodeRects.map((node) => node.rect.top)) - ANCHOR,\n    bottom: Math.max(...realNodeRects.map((node) => node.rect.bottom)) + ANCHOR,\n    left: Math.min(...realNodeRects.map((node) => node.rect.left)) - ANCHOR,\n    right: Math.max(...realNodeRects.map((node) => node.rect.right)) + ANCHOR,\n  };\n\n  const buildOrthogonalPathCandidates = (\n    src: { x: number; y: number },\n    srcSide: RectSide,\n    dst: { x: number; y: number },\n    dstSide: RectSide\n  ): { x: number; y: number }[][] => {\n    const paths: { x: number; y: number }[][] = [];\n    const base = buildOrthogonalPortPath(src, srcSide, dst, dstSide, ANCHOR, EPS);\n    if (base) {\n      paths.push(base);\n    }\n\n    // Crossing-reduction extension of the same-side detour rule above:\n    // when the local \"just outside these two ports\" track still crosses\n    // an existing connector, also try the corresponding global outer\n    // channel. This mirrors Wybrow-style post-route nudging/ordering:\n    // preserve the port pair and topology class, but move the maximal\n    // middle segment into an uncongested alley if safety checks accept it.\n    if (srcSide === dstSide) {\n      paths.push(buildSameSideTrackPath(src, srcSide, dst, outsideTracks[srcSide]));\n    }\n\n    return paths;\n  };\n\n  const pathHitsNode = (pts: { x: number; y: number }[], excludeIds: string[]): boolean => {\n    for (let i = 0; i < pts.length - 1; i++) {\n      const a = pts[i];\n      const b = pts[i + 1];\n      if (segmentHitsAnyRect(a, b, realNodeRects, excludeIds, 1)) {\n        return true;\n      }\n    }\n    return false;\n  };\n\n  const pathConflictCount = (\n    path: { x: number; y: number }[],\n    currentEdge: any,\n    includeIncidentEdges = false\n  ): number => {\n    let conflicts = 0;\n    const pathSegments = orthogonalSegmentsForPoints(path, EPS);\n    const currentStart = (currentEdge as { start?: string }).start;\n    const currentEnd = (currentEdge as { end?: string }).end;\n    for (const other of edges) {\n      if (other === currentEdge || (other as { isLayoutOnly?: boolean }).isLayoutOnly) {\n        continue;\n      }\n      const otherStart = (other as { start?: string }).start;\n      const otherEnd = (other as { end?: string }).end;\n      if (\n        !includeIncidentEdges &&\n        currentStart &&\n        currentEnd &&\n        (otherStart === currentStart ||\n          otherStart === currentEnd ||\n          otherEnd === currentStart ||\n          otherEnd === currentEnd)\n      ) {\n        continue;\n      }\n      const otherPts = (other as { points?: { x: number; y: number }[] }).points;\n      if (!otherPts || otherPts.length < 2) {\n        continue;\n      }\n      for (const pathSegment of pathSegments) {\n        for (const otherSegment of orthogonalSegmentsForPoints(otherPts, EPS)) {\n          if (\n            orthogonalSegmentsCross(\n              pathSegment.a,\n              pathSegment.b,\n              otherSegment.a,\n              otherSegment.b,\n              EPS,\n              EPS\n            )\n          ) {\n            conflicts++;\n            continue;\n          }\n          if (sameAxisSegmentOverlapLength(pathSegment, otherSegment, EPS) >= MIN_SHARED) {\n            conflicts++;\n          }\n        }\n      }\n    }\n    return conflicts;\n  };\n\n  const BEND_THRESHOLD = 4;\n\n  // Collect which node faces are already claimed by other edges so the\n  // rewrite loop below can reject a candidate port pair whose face is\n  // contested. This realizes Hegemann-Wolff's bend-or-end global\n  // feasibility rule (src d30cdbe1): two edges claiming the same node\n  // face must be feasibility-checked as a set, never accepted as a\n  // sequential patch.\n  //\n  // Iter 9 defect: raykov routed L_D_E_0 around H with 4 bends and\n  // L_E_F_0 cleanly at E.top in parallel; this pass then rewrote\n  // L_D_E_0 to the 2-bend (D.top, E.top) L-shape because it only\n  // checked against real-node obstacles and was blind to the E.top\n  // claim L_E_F_0 had already made.\n  //\n  // Note the face-detection uses `nearestSideOfRect` which picks\n  // whichever of the 4 rect edges the point is closest to. The\n  // polyline endpoints at this point in the pipeline are ALREADY\n  // transformed to TB coordinates but the final endpoint-clip pass\n  // (which snaps each endpoint onto the actual rect boundary) runs\n  // LATER, so the raw attach points may sit a few units inside the\n  // node rect. Nearest-side works regardless of whether the point is\n  // on, just outside, or a few units inside the rect.\n  const nearestSideOfRect = (pt: { x: number; y: number }, info: NodeBoundsInfo): RectSide => {\n    const dTop = Math.abs(pt.y - info.rect.top);\n    const dBottom = Math.abs(pt.y - info.rect.bottom);\n    const dLeft = Math.abs(pt.x - info.rect.left);\n    const dRight = Math.abs(pt.x - info.rect.right);\n    let best: RectSide = 'top';\n    let bestDist = dTop;\n    if (dBottom < bestDist) {\n      best = 'bottom';\n      bestDist = dBottom;\n    }\n    if (dLeft < bestDist) {\n      best = 'left';\n      bestDist = dLeft;\n    }\n    if (dRight < bestDist) {\n      best = 'right';\n      bestDist = dRight;\n    }\n    return best;\n  };\n\n  interface FaceClaim {\n    side: RectSide;\n    edgeId: string;\n  }\n  const faceClaims = new Map<string, FaceClaim[]>();\n  const addFaceClaim = (nodeId: string, side: RectSide, edgeId: string) => {\n    const claims = faceClaims.get(nodeId) ?? [];\n    claims.push({ side, edgeId });\n    faceClaims.set(nodeId, claims);\n  };\n  for (const e of edges) {\n    if ((e as { isLayoutOnly?: boolean }).isLayoutOnly) {\n      continue;\n    }\n    const pts = (e as { points?: { x: number; y: number }[] }).points ?? [];\n    if (pts.length < 1) {\n      continue;\n    }\n    const eId = (e as { id?: string }).id ?? '';\n    const startId = (e as { start?: string }).start;\n    const endId = (e as { end?: string }).end;\n    if (startId) {\n      const info = nodeInfoById.get(startId);\n      if (info) {\n        addFaceClaim(startId, nearestSideOfRect(pts[0], info), eId);\n      }\n    }\n    if (endId) {\n      const info = nodeInfoById.get(endId);\n      if (info) {\n        addFaceClaim(endId, nearestSideOfRect(pts[pts.length - 1], info), eId);\n      }\n    }\n  }\n\n  const faceIsClaimed = (nodeId: string, side: RectSide, ignoreEdgeId: string): boolean => {\n    return (\n      faceClaims.get(nodeId)?.some((c) => c.edgeId !== ignoreEdgeId && c.side === side) ?? false\n    );\n  };\n\n  for (const edge of edges) {\n    if (edge.isLayoutOnly) {\n      continue;\n    }\n    const pts = edge.points as { x: number; y: number }[] | undefined;\n    if (!pts || pts.length < 2) {\n      continue;\n    }\n    const currentBends = countOrthogonalBends(pts, EPS);\n    if (currentBends < BEND_THRESHOLD) {\n      continue;\n    }\n    const srcId = edge.start as string | undefined;\n    const dstId = edge.end as string | undefined;\n    if (!srcId || !dstId) {\n      continue;\n    }\n    const srcInfo = nodeInfoById.get(srcId);\n    const dstInfo = nodeInfoById.get(dstId);\n    if (!srcInfo || !dstInfo) {\n      continue;\n    }\n    const edgeId = (edge as { id?: string }).id ?? '';\n    const currentCrossingConflicts = pathConflictCount(pts, edge, true);\n    const currentNonIncidentConflicts = pathConflictCount(pts, edge);\n\n    let bestPath: { x: number; y: number }[] | undefined;\n    let bestCrossingConflicts = currentCrossingConflicts;\n    let bestBends = currentBends;\n\n    for (const srcSide of sides) {\n      if (faceIsClaimed(srcId, srcSide, edgeId)) {\n        continue;\n      }\n      const srcPort = portForRectSide(srcInfo, srcSide);\n      for (const dstSide of sides) {\n        if (faceIsClaimed(dstId, dstSide, edgeId)) {\n          continue;\n        }\n        const dstPort = portForRectSide(dstInfo, dstSide);\n        for (const path of buildOrthogonalPathCandidates(srcPort, srcSide, dstPort, dstSide)) {\n          if (pathHitsNode(path, [srcId, dstId])) {\n            continue;\n          }\n\n          const pathBends = countOrthogonalBends(path, EPS);\n          if (currentCrossingConflicts > 0) {\n            const pathCrossingConflicts = pathConflictCount(path, edge, true);\n            if (\n              pathCrossingConflicts > bestCrossingConflicts ||\n              (pathCrossingConflicts === bestCrossingConflicts && pathBends >= bestBends)\n            ) {\n              continue;\n            }\n            bestCrossingConflicts = pathCrossingConflicts;\n            bestBends = pathBends;\n            bestPath = path;\n            continue;\n          }\n\n          if (pathConflictCount(path, edge) > currentNonIncidentConflicts) {\n            continue;\n          }\n          if (pathBends < bestBends) {\n            bestBends = pathBends;\n            bestPath = path;\n          }\n        }\n      }\n    }\n\n    if (bestPath) {\n      (edge as { points: { x: number; y: number }[] }).points = bestPath;\n      // Refresh face claims for this edge so downstream iterations\n      // see the new attach sides. The loop mutates edges in place;\n      // stale claims would let two edges both commit to the same face.\n      const refreshSrc = faceClaims.get(srcId);\n      if (refreshSrc) {\n        faceClaims.set(\n          srcId,\n          refreshSrc.filter((c) => c.edgeId !== edgeId)\n        );\n      }\n      const refreshDst = faceClaims.get(dstId);\n      if (refreshDst) {\n        faceClaims.set(\n          dstId,\n          refreshDst.filter((c) => c.edgeId !== edgeId)\n        );\n      }\n      addFaceClaim(srcId, nearestSideOfRect(bestPath[0], srcInfo), edgeId);\n      addFaceClaim(dstId, nearestSideOfRect(bestPath[bestPath.length - 1], dstInfo), edgeId);\n    }\n  }\n}\n", "// cspell:ignore Helmers Wybrow\nimport type { Edge, Node } from '../../../types.js';\nimport {\n  dedupeConsecutivePoints,\n  inflateRect,\n  rectContainsRect,\n  rectFromCenterSize,\n  rectOfNodeBounds,\n  rectsOverlap,\n  segmentBoundsOverlapRect,\n} from './geometry.js';\nimport type { RectBounds } from './geometry.js';\n\nconst EPS = 1e-3;\nconst MARKER_CLEARANCE_LENGTH = 10;\nconst MARKER_CLEARANCE_HALF_WIDTH = 7;\n\nfunction markerClearanceRectFor(\n  pts: { x: number; y: number }[],\n  atStart: boolean\n): RectBounds | undefined {\n  const terminalIndex = atStart ? 0 : pts.length - 1;\n  const step = atStart ? 1 : -1;\n  const tip = pts[terminalIndex];\n  const inner = pts[terminalIndex + step];\n  if (!tip || !inner) {\n    return undefined;\n  }\n\n  const dx = inner.x - tip.x;\n  const dy = inner.y - tip.y;\n  const len = Math.abs(dx) + Math.abs(dy);\n  if (len < EPS) {\n    return undefined;\n  }\n\n  if (Math.abs(dy) <= EPS) {\n    const x2 = tip.x + Math.sign(dx) * MARKER_CLEARANCE_LENGTH;\n    return {\n      left: Math.min(tip.x, x2),\n      right: Math.max(tip.x, x2),\n      top: tip.y - MARKER_CLEARANCE_HALF_WIDTH,\n      bottom: tip.y + MARKER_CLEARANCE_HALF_WIDTH,\n    };\n  }\n\n  if (Math.abs(dx) <= EPS) {\n    const y2 = tip.y + Math.sign(dy) * MARKER_CLEARANCE_LENGTH;\n    return {\n      left: tip.x - MARKER_CLEARANCE_HALF_WIDTH,\n      right: tip.x + MARKER_CLEARANCE_HALF_WIDTH,\n      top: Math.min(tip.y, y2),\n      bottom: Math.max(tip.y, y2),\n    };\n  }\n\n  return {\n    left: Math.min(tip.x, inner.x),\n    right: Math.max(tip.x, inner.x),\n    top: Math.min(tip.y, inner.y),\n    bottom: Math.max(tip.y, inner.y),\n  };\n}\n\nfunction normalizeRect(rect: RectBounds): RectBounds {\n  return {\n    left: Math.min(rect.left, rect.right),\n    right: Math.max(rect.left, rect.right),\n    top: Math.min(rect.top, rect.bottom),\n    bottom: Math.max(rect.top, rect.bottom),\n  };\n}\n\nfunction labelOverlapsOwnMarker(rect: RectBounds, pts: { x: number; y: number }[]): boolean {\n  const visiblePts = dedupeConsecutivePoints(pts);\n  const startMarker = markerClearanceRectFor(visiblePts, true);\n  const endMarker = markerClearanceRectFor(visiblePts, false);\n  return [startMarker, endMarker].some(\n    (marker) => marker && rectsOverlap(rect, normalizeRect(marker))\n  );\n}\n\nexport function anchorLabelsToPolyline(edges: Edge[], nodeByIdMap: Map<string, Node>): void {\n  // Build a set of foreign polylines once for overlap checks. Labelled\n  // originals that haven't been anchored yet are still included \u2014 their\n  // polylines exist, even if their labels haven't moved.\n  type RectLite = RectBounds;\n  interface SegmentLite {\n    edgeId: string;\n    p1: { x: number; y: number };\n    p2: { x: number; y: number };\n  }\n  const allEdgeSegments: SegmentLite[] = [];\n  for (const other of edges) {\n    if (other.isLayoutOnly) {\n      continue;\n    }\n    const pts = other.points;\n    if (!pts || pts.length < 2) {\n      continue;\n    }\n    for (let i = 0; i < pts.length - 1; i++) {\n      allEdgeSegments.push({ edgeId: other.id, p1: pts[i], p2: pts[i + 1] });\n    }\n  }\n\n  const foreignNodeRects: { nodeId: string; rect: RectLite }[] = [];\n  // Collect top-level lane groups so we can re-assign a label's parentId to\n  // whichever lane geometrically contains its anchored position. Without\n  // this, labels whose anchor crosses a lane boundary are reported as\n  // node-overlap violations against sibling lane groups.\n  const laneGroups: { id: string; rect: RectLite }[] = [];\n  for (const n of nodeByIdMap.values()) {\n    const isGroup = n.isGroup;\n    const parentId = n.parentId;\n    if (isGroup && !parentId) {\n      const rect = rectOfNodeBounds(n);\n      if (rect) {\n        laneGroups.push({\n          id: n.id,\n          rect,\n        });\n      }\n      continue;\n    }\n    if (isGroup) {\n      continue;\n    }\n    if (n.isEdgeLabel) {\n      continue;\n    }\n    const rect = rectOfNodeBounds(n);\n    if (!rect) {\n      continue;\n    }\n    foreignNodeRects.push({\n      nodeId: n.id,\n      rect,\n    });\n  }\n\n  // Inflation margin for foreign-edge / foreign-node proximity. The layout\n  // validator's `edge-border-hugging` check fires when a polyline runs\n  // within ~2u of a label's visual border (EPS_BORDER). Inflate the label\n  // rect we test by a little more than that when rejecting candidates, so\n  // no chosen placement will trigger the hug check. 3u preserves the buffer\n  // used by the old pre-label detour pass.\n  const LABEL_PLACEMENT_BUFFER = 3;\n  const LABEL_LANE_MARGIN = 1;\n  // Mermaid's point marker occupies roughly 10u at the edge endpoint; keep\n  // labels a little farther away so the arrowhead remains visually readable.\n  const LABEL_ENDPOINT_CLEARANCE = 12;\n\n  const labelOverlapsForeignNode = (labelId: string, rect: RectLite): boolean => {\n    const buffered = inflateRect(rect, LABEL_PLACEMENT_BUFFER);\n    for (const { nodeId, rect: nr } of foreignNodeRects) {\n      if (nodeId === labelId) {\n        continue;\n      }\n      if (rectsOverlap(buffered, nr)) {\n        return true;\n      }\n    }\n    return false;\n  };\n\n  const labelOverlapsForeignEdge = (edgeId: string, rect: RectLite): boolean => {\n    const buffered = inflateRect(rect, LABEL_PLACEMENT_BUFFER);\n    for (const s of allEdgeSegments) {\n      if (s.edgeId === edgeId) {\n        continue;\n      }\n      if (segmentBoundsOverlapRect(s.p1, s.p2, buffered)) {\n        return true;\n      }\n    }\n    return false;\n  };\n\n  const labelOverlapsAnything = (labelId: string, edgeId: string, rect: RectLite): boolean =>\n    labelOverlapsForeignNode(labelId, rect) || labelOverlapsForeignEdge(edgeId, rect);\n\n  const placedLabelRects: { labelId: string; rect: RectLite }[] = [];\n\n  const findContainingLane = (rect: RectLite): string | undefined => {\n    for (const { id, rect: laneRect } of laneGroups) {\n      if (rectContainsRect(laneRect, rect)) {\n        return id;\n      }\n    }\n    return undefined;\n  };\n\n  const overlapsPlacedLabel = (labelId: string, rect: RectLite): boolean =>\n    placedLabelRects.some(\n      (placed) => placed.labelId !== labelId && rectsOverlap(rect, placed.rect)\n    );\n\n  interface SegmentCandidate {\n    idx: number;\n    length: number;\n    orientation: 'horizontal' | 'vertical';\n    midX: number;\n    midY: number;\n  }\n\n  for (const edge of edges) {\n    if (edge.isLayoutOnly) {\n      continue;\n    }\n    const labelId = edge.labelNodeId;\n    if (!labelId) {\n      continue;\n    }\n    const labelNode = nodeByIdMap.get(labelId);\n    if (!labelNode) {\n      continue;\n    }\n    const pts = edge.points;\n    if (!pts || pts.length < 2) {\n      continue;\n    }\n    const lw = labelNode.width ?? 0;\n    const lh = labelNode.height ?? 0;\n    if (lw <= 0 || lh <= 0) {\n      continue;\n    }\n\n    // Collect every non-zero segment with orientation.\n    const segments: SegmentCandidate[] = [];\n    for (let i = 0; i < pts.length - 1; i++) {\n      const a = pts[i];\n      const b = pts[i + 1];\n      const dx = Math.abs(a.x - b.x);\n      const dy = Math.abs(a.y - b.y);\n      if (dx < EPS && dy < EPS) {\n        continue;\n      }\n      if (dx >= EPS && dy >= EPS) {\n        continue; // non-orthogonal \u2014 should not happen post-orthogonalize\n      }\n      segments.push({\n        idx: i,\n        length: dx + dy,\n        orientation: dx >= EPS ? 'horizontal' : 'vertical',\n        midX: (a.x + b.x) / 2,\n        midY: (a.y + b.y) / 2,\n      });\n    }\n\n    if (segments.length === 0) {\n      continue;\n    }\n\n    // \u00A7118: middle segments only (exclude first and last). Fall back to\n    // any segment if the polyline has fewer than 3 segments (the paper is\n    // silent on degenerate cases \u2014 Mermaid calibration).\n    const middleSegments =\n      segments.length >= 3\n        ? segments.filter((s) => s.idx > 0 && s.idx < segments.length - 1)\n        : segments;\n    const poolBase = middleSegments.length > 0 ? middleSegments : segments;\n\n    // Label long axis: horizontal if wider than tall, else vertical. The\n    // label is drawn horizontally inside its bbox regardless, so the long\n    // axis only drives preference, not hard filtering.\n    const labelLongAxis: 'horizontal' | 'vertical' = lw >= lh ? 'horizontal' : 'vertical';\n\n    // Candidate ranking: (a) length >= labelExtent + 2, (b) orientation\n    // matching label long axis preferred, (c) longest tie-break.\n    const rankSegments = (pool: SegmentCandidate[]): SegmentCandidate[] => {\n      return [...pool].sort((a, b) => {\n        const aLongAxis = a.orientation === labelLongAxis;\n        const bLongAxis = b.orientation === labelLongAxis;\n        if (aLongAxis !== bLongAxis) {\n          return aLongAxis ? -1 : 1;\n        }\n        const aFits = a.length >= (a.orientation === 'horizontal' ? lw : lh) + 2;\n        const bFits = b.length >= (b.orientation === 'horizontal' ? lw : lh) + 2;\n        if (aFits !== bFits) {\n          return aFits ? -1 : 1;\n        }\n        return b.length - a.length;\n      });\n    };\n\n    // Try the middle-segment pool first (\u00A7118), then expand to include\n    // every orthogonal segment if the middle-only pool yields no\n    // lane-containing, overlap-free candidate. The \"any segment\" expansion\n    // is a Mermaid-specific adaptation for cross-lane edges whose only\n    // middle segment is the vertical lane-crossing leg (which by\n    // construction straddles a lane boundary and cannot host the label).\n    //\n    // Per-segment, if the midpoint (t=0.5) collides with a foreign edge\n    // or label, walk along the segment at additional parametric positions\n    // t \u2208 {0.25, 0.75, 0.15, 0.85, 0.1, 0.9} before moving on. Helmers diss.pdf\n    // \u00A7118 requires \"one of e's middle segments\" but is silent on the\n    // exact anchor position along that segment, so along-segment shift is\n    // consistent with the paper (Mermaid adaptation). Paper-adjacent to\n    // Wybrow-Marriott alley-midpoint centering (src `e8804c93`), which\n    // picks the placement with widest clearance to foreign geometry.\n    const firstVisibleSegment = segments[0];\n    const lastVisibleSegment = segments[segments.length - 1];\n    const ALONG_SEGMENT_TS = [0.5, 0.25, 0.75, 0.05, 0.95, 0.15, 0.85, 0.1, 0.9];\n    const anchorAtT = (seg: SegmentCandidate, t: number): { midX: number; midY: number } => {\n      const a = pts[seg.idx];\n      const b = pts[seg.idx + 1];\n      return {\n        midX: a.x + (b.x - a.x) * t,\n        midY: a.y + (b.y - a.y) * t,\n      };\n    };\n    const clamp = (value: number, min: number, max: number): number =>\n      Math.min(max, Math.max(min, value));\n    const pointInsideRectInclusive = (\n      point: { midX: number; midY: number },\n      rect: RectLite\n    ): boolean =>\n      point.midX >= rect.left - EPS &&\n      point.midX <= rect.right + EPS &&\n      point.midY >= rect.top - EPS &&\n      point.midY <= rect.bottom + EPS;\n    const placementForAnchor = (anchor: {\n      midX: number;\n      midY: number;\n    }): { laneId: string; anchor: { midX: number; midY: number }; rect: RectLite } | undefined => {\n      const centeredRect = rectFromCenterSize(anchor.midX, anchor.midY, lw, lh);\n      const centeredLane = findContainingLane(centeredRect);\n      if (centeredLane) {\n        return { laneId: centeredLane, anchor, rect: centeredRect };\n      }\n\n      // If the segment is close to a lane border, keep the label box inside\n      // the lane while requiring the original segment point to remain inside\n      // that box. The validator then sees the edge passing through the label.\n      const containingLane = laneGroups.find(({ rect }) => pointInsideRectInclusive(anchor, rect));\n      if (!containingLane) {\n        return undefined;\n      }\n\n      const minX = containingLane.rect.left + lw / 2 + LABEL_LANE_MARGIN;\n      const maxX = containingLane.rect.right - lw / 2 - LABEL_LANE_MARGIN;\n      const minY = containingLane.rect.top + lh / 2 + LABEL_LANE_MARGIN;\n      const maxY = containingLane.rect.bottom - lh / 2 - LABEL_LANE_MARGIN;\n      if (minX > maxX || minY > maxY) {\n        return undefined;\n      }\n\n      const clampedAnchor = {\n        midX: clamp(anchor.midX, minX, maxX),\n        midY: clamp(anchor.midY, minY, maxY),\n      };\n      const clampedRect = rectFromCenterSize(clampedAnchor.midX, clampedAnchor.midY, lw, lh);\n      return pointInsideRectInclusive(anchor, clampedRect)\n        ? { laneId: containingLane.id, anchor: clampedAnchor, rect: clampedRect }\n        : undefined;\n    };\n    const distanceAlongSegment = (\n      seg: SegmentCandidate,\n      anchor: { midX: number; midY: number },\n      endpoint: { x: number; y: number }\n    ): number =>\n      seg.orientation === 'horizontal'\n        ? Math.abs(anchor.midX - endpoint.x)\n        : Math.abs(anchor.midY - endpoint.y);\n    const labelClearsTerminalEndpoints = (\n      seg: SegmentCandidate,\n      anchor: { midX: number; midY: number }\n    ): boolean => {\n      const labelHalfExtent = seg.orientation === 'horizontal' ? lw / 2 : lh / 2;\n      const requiredDistance = labelHalfExtent + LABEL_ENDPOINT_CLEARANCE;\n      if (seg === firstVisibleSegment) {\n        const start = pts[seg.idx];\n        if (distanceAlongSegment(seg, anchor, start) + EPS < requiredDistance) {\n          return false;\n        }\n      }\n      if (seg === lastVisibleSegment) {\n        const end = pts[seg.idx + 1];\n        if (distanceAlongSegment(seg, anchor, end) + EPS < requiredDistance) {\n          return false;\n        }\n      }\n      return true;\n    };\n    const tryPool = (\n      pool: SegmentCandidate[]\n    ): { laneId: string; anchor: { midX: number; midY: number } } | undefined => {\n      const rankedPool = rankSegments(pool);\n      for (const seg of rankedPool) {\n        for (const t of ALONG_SEGMENT_TS) {\n          const anchor = anchorAtT(seg, t);\n          if (!labelClearsTerminalEndpoints(seg, anchor)) {\n            continue;\n          }\n          const placement = placementForAnchor(anchor);\n          if (!placement) {\n            continue;\n          }\n          if (labelOverlapsOwnMarker(placement.rect, pts)) {\n            continue;\n          }\n          if (overlapsPlacedLabel(labelId, placement.rect)) {\n            continue;\n          }\n          if (!labelOverlapsAnything(labelId, edge.id, placement.rect)) {\n            return { laneId: placement.laneId, anchor: placement.anchor };\n          }\n        }\n      }\n      return undefined;\n    };\n\n    const findLaneContainingFallback = (\n      pool: SegmentCandidate[],\n      requireEndpointClearance: boolean,\n      allowForeignEdgeOverlap = false\n    ): { laneId: string; anchor: { midX: number; midY: number } } | undefined => {\n      const rankedPool = rankSegments(pool);\n      for (const seg of rankedPool) {\n        const anchor = { midX: seg.midX, midY: seg.midY };\n        if (requireEndpointClearance && !labelClearsTerminalEndpoints(seg, anchor)) {\n          continue;\n        }\n        const placement = placementForAnchor(anchor);\n        if (\n          placement &&\n          !labelOverlapsOwnMarker(placement.rect, pts) &&\n          !overlapsPlacedLabel(labelId, placement.rect) &&\n          !labelOverlapsForeignNode(labelId, placement.rect) &&\n          (allowForeignEdgeOverlap || !labelOverlapsForeignEdge(edge.id, placement.rect))\n        ) {\n          return { laneId: placement.laneId, anchor: placement.anchor };\n        }\n      }\n      return undefined;\n    };\n\n    const chosen =\n      tryPool(poolBase) ??\n      (poolBase.length < segments.length ? tryPool(segments) : undefined) ??\n      findLaneContainingFallback(segments, true) ??\n      findLaneContainingFallback(segments, false) ??\n      findLaneContainingFallback(segments, false, true);\n\n    if (chosen) {\n      labelNode.x = chosen.anchor.midX;\n      labelNode.y = chosen.anchor.midY;\n      labelNode.parentId = chosen.laneId;\n      const chosenRect = rectFromCenterSize(chosen.anchor.midX, chosen.anchor.midY, lw, lh);\n      const priorIdx = placedLabelRects.findIndex((placed) => placed.labelId === labelId);\n      if (priorIdx >= 0) {\n        placedLabelRects[priorIdx] = { labelId, rect: chosenRect };\n      } else {\n        placedLabelRects.push({ labelId, rect: chosenRect });\n      }\n    }\n  }\n}\n", "// cspell:ignore Hegemann Kandinsky Siebenhaller\nimport type { Edge, Node } from '../../../types.js';\nimport {\n  classifyThreeSegmentRoute,\n  collectRealNodeBounds,\n  getNodePairGeometry,\n  segmentConflictsWithAnyEdge,\n  segmentHitsAnyRect,\n} from './geometry.js';\n\nconst EPS = 1e-6;\nconst MIN_PORT_SPACING = 8;\nconst PORT_SHIFT = MIN_PORT_SPACING / 2;\nconst LABEL_CLEARANCE_BUFFER = 3;\n\ninterface PointLite {\n  x: number;\n  y: number;\n}\n\ninterface LabelDim {\n  w: number;\n  h: number;\n}\n\nfunction pairKey(a: string, b: string): string {\n  return a < b ? `${a}::${b}` : `${b}::${a}`;\n}\n\n/**\n * Iter 12 \u2014 co-route sibling straight-line rescue.\n *\n * Fires only on the narrow \"4-point U-detour around a collinear blocker\n * where the obvious straight line is geometrically clear\" shape. For each\n * eligible edge, shifts the source and destination attach points by\n * MIN_PORT_SPACING/2 along the shared face and replaces the polyline\n * with a 2-point straight line. The shift direction is chosen by trying\n * both +delta and -delta and picking whichever doesn't introduce a new\n * edge crossing or leave the node's face span.\n *\n * Paper backing: Hegemann & Wolff \"On the smoothing of orthogonal\n * connector layouts\" (NotebookLM src b65b3d45) \u00A74.2 / Fig. 11 \u2014\n * joint-feasibility via port distribution rather than face exclusion.\n * Mermaid-specific narrowing: we only rescue the exact 4-point shape to\n * minimize blast radius.\n */\nexport function straightenCollinearSiblingDetours(edges: Edge[], nodes: Node[]): void {\n  const { nodeInfoById, realNodeRects } = collectRealNodeBounds(nodes);\n  // Side table of label-node dimensions so we can grow the rescue delta\n  // far enough to clear a label sitting on the sibling line.\n  const labelDimById = new Map<string, LabelDim>();\n  for (const n of nodes) {\n    const id = n.id;\n    if (n.isGroup) {\n      continue;\n    }\n    if (n.isEdgeLabel) {\n      labelDimById.set(id, {\n        w: n.width ?? 0,\n        h: n.height ?? 0,\n      });\n      continue;\n    }\n  }\n\n  // For a given (this-edge, axis) pair, find the largest label half-extent\n  // among any edge sharing the same node pair (anti-parallel siblings) plus\n  // this edge's own label. Used to grow the rescue shift past the label so\n  // anchorLabelsToPolyline can place the label clear of the sibling.\n  const labelClearanceFor = (\n    thisEdge: Edge,\n    thisSrcId: string,\n    thisDstId: string,\n    axis: 'x' | 'y'\n  ): number => {\n    const targetPair = pairKey(thisSrcId, thisDstId);\n    let maxHalf = 0;\n    const consider = (labelId: string | undefined) => {\n      if (!labelId) {\n        return;\n      }\n      const dim = labelDimById.get(labelId);\n      if (!dim) {\n        return;\n      }\n      const half = axis === 'x' ? dim.w / 2 : dim.h / 2;\n      if (half > maxHalf) {\n        maxHalf = half;\n      }\n    };\n    consider(thisEdge.labelNodeId);\n    for (const other of edges) {\n      if (other === thisEdge) {\n        continue;\n      }\n      if (other.isLayoutOnly) {\n        continue;\n      }\n      const oSrc = other.start;\n      const oDst = other.end;\n      if (!oSrc || !oDst) {\n        continue;\n      }\n      if (pairKey(oSrc, oDst) !== targetPair) {\n        continue;\n      }\n      consider(other.labelNodeId);\n    }\n    return maxHalf > 0 ? maxHalf + LABEL_CLEARANCE_BUFFER : 0;\n  };\n\n  for (const edge of edges) {\n    if (edge.isLayoutOnly) {\n      continue;\n    }\n    const pts = edge.points;\n    if (!classifyThreeSegmentRoute(pts, EPS)) {\n      continue;\n    }\n\n    const nodePair = getNodePairGeometry(edge, nodeInfoById, EPS);\n    if (!nodePair) {\n      continue;\n    }\n    const { srcId, dstId, srcInfo, dstInfo, collinearX, collinearY } = nodePair;\n    if (collinearX === collinearY) {\n      continue;\n    }\n\n    let targetSrc: PointLite;\n    let targetDst: PointLite;\n    if (collinearX) {\n      const dstBelow = dstInfo.cy > srcInfo.cy;\n      targetSrc = { x: srcInfo.cx, y: dstBelow ? srcInfo.rect.bottom : srcInfo.rect.top };\n      targetDst = { x: dstInfo.cx, y: dstBelow ? dstInfo.rect.top : dstInfo.rect.bottom };\n    } else {\n      const dstEast = dstInfo.cx > srcInfo.cx;\n      targetSrc = { x: dstEast ? srcInfo.rect.right : srcInfo.rect.left, y: srcInfo.cy };\n      targetDst = { x: dstEast ? dstInfo.rect.left : dstInfo.rect.right, y: dstInfo.cy };\n    }\n\n    if (segmentHitsAnyRect(targetSrc, targetDst, realNodeRects, [srcId, dstId], 1)) {\n      continue;\n    }\n\n    // The rescue moves the line perpendicular to its own direction: a\n    // horizontal rescued line shifts in y (so the label HEIGHT determines\n    // clearance), a vertical one shifts in x (label WIDTH). collinearX\n    // means the rescued line is vertical (nodes share a column).\n    //\n    // When the edge (or an anti-parallel sibling) carries a label, the\n    // small PORT_SHIFT would leave the rescued straight inside the label's\n    // bbox \u2014 the label would visually overlap this line. We grow the\n    // shift to clear the label rect. If the wider shift won't fit on the\n    // node face, the bounds check below rejects it and we fall through\n    // without rescuing, which keeps the original 4-point detour \u2014 also\n    // correct, since the detour routes far away from the label.\n    const shiftAxis: 'x' | 'y' = collinearX ? 'x' : 'y';\n    const labelShift = labelClearanceFor(edge, srcId, dstId, shiftAxis);\n    const effectiveShift = labelShift > PORT_SHIFT ? labelShift : PORT_SHIFT;\n    const deltas = [0, effectiveShift, -effectiveShift];\n    for (const delta of deltas) {\n      const shiftedSrc = { ...targetSrc };\n      const shiftedDst = { ...targetDst };\n      if (collinearX) {\n        shiftedSrc.x += delta;\n        shiftedDst.x += delta;\n        if (shiftedSrc.x <= srcInfo.rect.left || shiftedSrc.x >= srcInfo.rect.right) {\n          continue;\n        }\n        if (shiftedDst.x <= dstInfo.rect.left || shiftedDst.x >= dstInfo.rect.right) {\n          continue;\n        }\n      } else {\n        shiftedSrc.y += delta;\n        shiftedDst.y += delta;\n        if (shiftedSrc.y <= srcInfo.rect.top || shiftedSrc.y >= srcInfo.rect.bottom) {\n          continue;\n        }\n        if (shiftedDst.y <= dstInfo.rect.top || shiftedDst.y >= dstInfo.rect.bottom) {\n          continue;\n        }\n      }\n\n      if (segmentHitsAnyRect(shiftedSrc, shiftedDst, realNodeRects, [srcId, dstId], 1)) {\n        continue;\n      }\n\n      if (segmentConflictsWithAnyEdge(shiftedSrc, shiftedDst, edges, edge, { epsilon: EPS })) {\n        continue;\n      }\n\n      edge.points = [shiftedSrc, shiftedDst];\n      break;\n    }\n  }\n}\n", "import type { Edge, Node } from '../../../types.js';\nimport {\n  collectNodeRectEntries,\n  dedupeConsecutivePoints,\n  overlapLength,\n  orthogonalSegmentsForPoints,\n  orthogonalSegmentsStrictlyCross,\n  rectOfNodeBounds,\n  segmentHitsAnyRect,\n} from './geometry.js';\nimport type { OrthogonalSegment, Point } from './geometry.js';\n\nexport function nudgeSharedInteriorSubpaths(edges: Edge[], nodeByIdMap: Map<string, Node>): void {\n  const EPS_LOCAL = 1e-3;\n  const MIN_SHARED = 8;\n  const TRACK_SHIFT = 7;\n  const MIN_TRACK_GAP = TRACK_SHIFT;\n  const SOURCE_DETOUR_STUB = 20;\n  const BUFFER = 2;\n  const MAX_ITERATIONS = 12;\n\n  type PointLite = Point;\n\n  interface SegmentLite extends OrthogonalSegment {\n    edge: Edge;\n    interior: boolean;\n  }\n\n  const { realNodeRects, labelNodeRects: labelRects } = collectNodeRectEntries(\n    nodeByIdMap.values()\n  );\n\n  const segmentsFor = (edge: Edge, points: PointLite[]): SegmentLite[] => {\n    return orthogonalSegmentsForPoints(points, EPS_LOCAL).map((segment) => ({\n      ...segment,\n      edge,\n      interior: segment.index >= 1 && segment.index <= points.length - 3,\n    }));\n  };\n\n  const allSegments = (): SegmentLite[] => {\n    const result: SegmentLite[] = [];\n    for (const edge of edges) {\n      if (edge.isLayoutOnly) {\n        continue;\n      }\n      const points = edge.points;\n      if (!points || points.length < 2) {\n        continue;\n      }\n      result.push(...segmentsFor(edge, dedupeConsecutivePoints(points)));\n    }\n    return result;\n  };\n\n  const hasCrowdedParallelTrack = (a: SegmentLite, b: SegmentLite): boolean => {\n    if (a.horizontal && b.horizontal) {\n      return (\n        overlapLength(a.a.x, a.b.x, b.a.x, b.b.x) >= MIN_SHARED &&\n        Math.abs(a.a.y - b.a.y) < MIN_TRACK_GAP\n      );\n    }\n    if (a.vertical && b.vertical) {\n      return (\n        overlapLength(a.a.y, a.b.y, b.a.y, b.b.y) >= MIN_SHARED &&\n        Math.abs(a.a.x - b.a.x) < MIN_TRACK_GAP\n      );\n    }\n    return false;\n  };\n\n  const candidateIsSafe = (edge: Edge, candidate: PointLite[]): boolean => {\n    const sourceId = edge.start;\n    const targetId = edge.end;\n    const candidateSegments = segmentsFor(edge, candidate);\n    if (candidateSegments.length !== candidate.length - 1) {\n      return false;\n    }\n\n    const endpointIds = [sourceId, targetId].filter((id): id is string => Boolean(id));\n    const ownLabelIds = edge.labelNodeId ? [edge.labelNodeId] : [];\n    for (const segment of candidateSegments) {\n      if (segmentHitsAnyRect(segment.a, segment.b, realNodeRects, endpointIds, -BUFFER)) {\n        return false;\n      }\n      if (segmentHitsAnyRect(segment.a, segment.b, labelRects, ownLabelIds, -BUFFER)) {\n        return false;\n      }\n    }\n\n    for (const other of edges) {\n      if (other === edge || other.isLayoutOnly) {\n        continue;\n      }\n      const otherPoints = other.points;\n      if (!otherPoints || otherPoints.length < 2) {\n        continue;\n      }\n      for (const candidateSegment of candidateSegments) {\n        for (const otherSegment of segmentsFor(other, dedupeConsecutivePoints(otherPoints))) {\n          if (hasCrowdedParallelTrack(candidateSegment, otherSegment)) {\n            return false;\n          }\n          if (\n            orthogonalSegmentsStrictlyCross(\n              candidateSegment.a,\n              candidateSegment.b,\n              otherSegment.a,\n              otherSegment.b,\n              EPS_LOCAL\n            )\n          ) {\n            return false;\n          }\n        }\n      }\n    }\n\n    return true;\n  };\n\n  const shiftedCandidate = (segment: SegmentLite, shift: number): PointLite[] | undefined => {\n    const points = dedupeConsecutivePoints(segment.edge.points ?? []);\n    if (points.length < 4 || segment.index >= points.length - 1) {\n      return undefined;\n    }\n    const candidate = points.map((p) => ({ ...p }));\n    if (segment.horizontal) {\n      candidate[segment.index].y += shift;\n      candidate[segment.index + 1].y += shift;\n    } else if (segment.vertical) {\n      candidate[segment.index].x += shift;\n      candidate[segment.index + 1].x += shift;\n    } else {\n      return undefined;\n    }\n    return segmentsFor(segment.edge, candidate).length === candidate.length - 1\n      ? candidate\n      : undefined;\n  };\n\n  type NodeRect = NonNullable<ReturnType<typeof rectOfNodeBounds>>;\n\n  interface SourceDetourContext {\n    sourceCenter: Point;\n    targetCenter: Point;\n    sourceRect: NodeRect;\n    tail: PointLite[];\n  }\n\n  const nodeCenter = (node: Node, rect: NodeRect): Point => ({\n    x: node.x ?? (rect.left + rect.right) / 2,\n    y: node.y ?? (rect.top + rect.bottom) / 2,\n  });\n\n  const sourceDetourContextFor = (segment: SegmentLite): SourceDetourContext | undefined => {\n    const edge = segment.edge;\n    const points = dedupeConsecutivePoints(edge.points ?? []);\n    if (points.length !== 4 || segment.index !== 1) {\n      return undefined;\n    }\n\n    const sourceNode = edge.start ? nodeByIdMap.get(edge.start) : undefined;\n    const targetNode = edge.end ? nodeByIdMap.get(edge.end) : undefined;\n    const sourceRect = sourceNode ? rectOfNodeBounds(sourceNode) : undefined;\n    const targetRect = targetNode ? rectOfNodeBounds(targetNode) : undefined;\n    const tail = points.slice(segment.index + 2);\n    if (!sourceNode || !targetNode || !sourceRect || !targetRect || tail.length === 0) {\n      return undefined;\n    }\n\n    return {\n      sourceCenter: nodeCenter(sourceNode, sourceRect),\n      targetCenter: nodeCenter(targetNode, targetRect),\n      sourceRect,\n      tail,\n    };\n  };\n\n  const verticalSourceDetour = (\n    segment: SegmentLite,\n    shift: number,\n    sourceCenter: Point,\n    targetCenter: Point,\n    sourceRect: NodeRect,\n    tail: PointLite[]\n  ): PointLite[] | undefined => {\n    const targetBelow = targetCenter.y >= sourceCenter.y;\n    const sourcePortY = targetBelow ? sourceRect.bottom : sourceRect.top;\n    const stubY = sourcePortY + (targetBelow ? SOURCE_DETOUR_STUB : -SOURCE_DETOUR_STUB);\n    if (\n      (targetBelow && segment.b.y <= stubY + EPS_LOCAL) ||\n      (!targetBelow && segment.b.y >= stubY - EPS_LOCAL)\n    ) {\n      return undefined;\n    }\n\n    const railX = segment.a.x + shift;\n    return dedupeConsecutivePoints(\n      [\n        { x: sourceCenter.x, y: sourcePortY },\n        { x: sourceCenter.x, y: stubY },\n        { x: railX, y: stubY },\n        { x: railX, y: segment.b.y },\n        ...tail,\n      ],\n      EPS_LOCAL\n    );\n  };\n\n  const horizontalSourceDetour = (\n    segment: SegmentLite,\n    shift: number,\n    sourceCenter: Point,\n    targetCenter: Point,\n    sourceRect: NodeRect,\n    tail: PointLite[]\n  ): PointLite[] | undefined => {\n    const targetRight = targetCenter.x >= sourceCenter.x;\n    const sourcePortX = targetRight ? sourceRect.right : sourceRect.left;\n    const stubX = sourcePortX + (targetRight ? SOURCE_DETOUR_STUB : -SOURCE_DETOUR_STUB);\n    if (\n      (targetRight && segment.b.x <= stubX + EPS_LOCAL) ||\n      (!targetRight && segment.b.x >= stubX - EPS_LOCAL)\n    ) {\n      return undefined;\n    }\n\n    const railY = segment.a.y + shift;\n    return dedupeConsecutivePoints(\n      [\n        { x: sourcePortX, y: sourceCenter.y },\n        { x: stubX, y: sourceCenter.y },\n        { x: stubX, y: railY },\n        { x: segment.b.x, y: railY },\n        ...tail,\n      ],\n      EPS_LOCAL\n    );\n  };\n\n  const sourceDetourCandidate = (segment: SegmentLite, shift: number): PointLite[] | undefined => {\n    const context = sourceDetourContextFor(segment);\n    if (!context) {\n      return undefined;\n    }\n\n    if (segment.vertical) {\n      return verticalSourceDetour(\n        segment,\n        shift,\n        context.sourceCenter,\n        context.targetCenter,\n        context.sourceRect,\n        context.tail\n      );\n    }\n    if (segment.horizontal) {\n      return horizontalSourceDetour(\n        segment,\n        shift,\n        context.sourceCenter,\n        context.targetCenter,\n        context.sourceRect,\n        context.tail\n      );\n    }\n\n    return undefined;\n  };\n\n  const shifts = [\n    -TRACK_SHIFT,\n    TRACK_SHIFT,\n    -2 * TRACK_SHIFT,\n    2 * TRACK_SHIFT,\n    -3 * TRACK_SHIFT,\n    3 * TRACK_SHIFT,\n  ];\n\n  for (let iteration = 0; iteration < MAX_ITERATIONS; iteration++) {\n    const segments = allSegments();\n    let fixed = false;\n\n    for (let i = 0; i < segments.length && !fixed; i++) {\n      for (let j = i + 1; j < segments.length && !fixed; j++) {\n        const first = segments[i];\n        const second = segments[j];\n        if (first.edge === second.edge || !hasCrowdedParallelTrack(first, second)) {\n          continue;\n        }\n\n        const candidates = [first, second].filter((segment) => segment.interior);\n        for (const segment of candidates) {\n          for (const shift of shifts) {\n            const direct = shiftedCandidate(segment, shift);\n            if (direct && candidateIsSafe(segment.edge, direct)) {\n              segment.edge.points = direct;\n              fixed = true;\n              break;\n            }\n\n            const detoured = sourceDetourCandidate(segment, shift);\n            if (detoured && candidateIsSafe(segment.edge, detoured)) {\n              segment.edge.points = detoured;\n              fixed = true;\n              break;\n            }\n          }\n          if (fixed) {\n            break;\n          }\n        }\n      }\n    }\n\n    if (!fixed) {\n      return;\n    }\n  }\n}\n", "import type { LayoutData } from '../../../types.js';\nimport { log } from '../../../../logger.js';\nimport { collectLayoutNodeRects, segmentBoundsOverlapRect } from './geometry.js';\n\nexport interface ValidationIssue {\n  type: 'edge-node-overlap' | 'edge-edge-crossing';\n  edgeId: string;\n  /** Second edge ID (for crossings) or node ID (for overlaps) */\n  targetId: string;\n  detail: string;\n}\n\n/**\n * Checks if two line segments intersect.\n * Uses the CCW (counter-clockwise) orientation test.\n * Returns true only for proper intersections: touching endpoints\n * or collinear segments return false.\n */\nfunction segmentsIntersect(\n  p1: { x: number; y: number },\n  p2: { x: number; y: number },\n  p3: { x: number; y: number },\n  p4: { x: number; y: number }\n): boolean {\n  const d1x = p2.x - p1.x;\n  const d1y = p2.y - p1.y;\n  const d2x = p4.x - p3.x;\n  const d2y = p4.y - p3.y;\n\n  const cross = d1x * d2y - d1y * d2x;\n  if (Math.abs(cross) < 1e-10) {\n    return false; // parallel or collinear\n  }\n\n  const dx = p3.x - p1.x;\n  const dy = p3.y - p1.y;\n  const t = (dx * d2y - dy * d2x) / cross;\n  const u = (dx * d1y - dy * d1x) / cross;\n\n  // Strict interior intersection to avoid false positives at shared nodes.\n  const eps = 0.01;\n  return t > eps && t < 1 - eps && u > eps && u < 1 - eps;\n}\n\n/**\n * Final validation pass: scans the completed layout for remaining quality\n * issues. Does not attempt fixes, just logs warnings so developers can\n * identify problems during debugging.\n *\n * Checks:\n * 1. Edge segments that still pass through non-endpoint nodes\n * 2. Edge segments that cross other edge segments\n */\nexport function validateSwimlanesLayout(layout: LayoutData): ValidationIssue[] {\n  const nodes = layout.nodes ?? [];\n  const edges = (layout.edges ?? []) as any[];\n  const issues: ValidationIssue[] = [];\n\n  if (!edges.length || !nodes.length) {\n    return issues;\n  }\n\n  const nodeRects = collectLayoutNodeRects(nodes);\n\n  const epsilon = 1; // tighter than the fix pass: catch marginal overlaps\n  const edgeSegments: {\n    edgeId: string;\n    start: string;\n    end: string;\n    p1: { x: number; y: number };\n    p2: { x: number; y: number };\n  }[] = [];\n\n  for (const edge of edges) {\n    if (edge.isLayoutOnly) {\n      continue;\n    }\n    const points = edge.points as { x: number; y: number }[] | undefined;\n    if (!points || points.length < 2) {\n      continue;\n    }\n    const edgeStart = edge.start as string | undefined;\n    const edgeEnd = edge.end as string | undefined;\n    const ownLabelId = edge.labelNodeId as string | undefined;\n    const edgeId = (edge.id as string) ?? `${edgeStart}->${edgeEnd}`;\n\n    for (const rect of nodeRects) {\n      if (rect.nodeId === edgeStart || rect.nodeId === edgeEnd) {\n        continue;\n      }\n      if (ownLabelId && rect.nodeId === ownLabelId) {\n        continue;\n      }\n      for (let i = 0; i < points.length - 1; i++) {\n        if (segmentBoundsOverlapRect(points[i], points[i + 1], rect, -epsilon)) {\n          issues.push({\n            type: 'edge-node-overlap',\n            edgeId,\n            targetId: rect.nodeId,\n            detail: `segment ${i} passes through node \"${rect.nodeId}\"`,\n          });\n          break;\n        }\n      }\n    }\n\n    for (let i = 0; i < points.length - 1; i++) {\n      edgeSegments.push({\n        edgeId,\n        start: edgeStart!,\n        end: edgeEnd!,\n        p1: points[i],\n        p2: points[i + 1],\n      });\n    }\n  }\n\n  const crossingPairs = new Set<string>();\n  for (let i = 0; i < edgeSegments.length; i++) {\n    for (let j = i + 1; j < edgeSegments.length; j++) {\n      const a = edgeSegments[i];\n      const b = edgeSegments[j];\n      if (a.edgeId === b.edgeId) {\n        continue;\n      }\n\n      if (a.start === b.start || a.start === b.end || a.end === b.start || a.end === b.end) {\n        continue;\n      }\n\n      if (segmentsIntersect(a.p1, a.p2, b.p1, b.p2)) {\n        const pairKey = a.edgeId < b.edgeId ? `${a.edgeId}|${b.edgeId}` : `${b.edgeId}|${a.edgeId}`;\n        if (!crossingPairs.has(pairKey)) {\n          crossingPairs.add(pairKey);\n          issues.push({\n            type: 'edge-edge-crossing',\n            edgeId: a.edgeId,\n            targetId: b.edgeId,\n            detail: `edges \"${a.edgeId}\" and \"${b.edgeId}\" cross`,\n          });\n        }\n      }\n    }\n  }\n\n  if (issues.length > 0) {\n    const overlaps = issues.filter((i) => i.type === 'edge-node-overlap').length;\n    const crossings = issues.filter((i) => i.type === 'edge-edge-crossing').length;\n    log.warn(\n      `[SWIMLANE_VALIDATE] ${issues.length} issue(s) detected: ` +\n        `${overlaps} edge-node overlap(s), ${crossings} edge crossing(s)`\n    );\n    for (const issue of issues) {\n      log.warn(`[SWIMLANE_VALIDATE]   ${issue.type}: ${issue.detail}`);\n    }\n  }\n\n  return issues;\n}\n", "// cspell:ignore raykov Wybrow\nimport type { LayoutData } from '../../types.js';\nimport {\n  clipEdgeEndpointsToNodeBoundaries,\n  prepareEdgeEndpointsForRenderer,\n} from './direction/endpointClip.js';\nimport { orthogonalizePolyline, simplifyPolyline } from './direction/geometry.js';\nimport { applyBtDirectionTransform, applyLrDirectionTransform } from './direction/lrTransform.js';\nimport { portSwapToLShape } from './direction/portSwap.js';\nimport { collapseShortTerminalStub } from './direction/terminalStub.js';\nimport {\n  collapseRedundantRectangularDoglegs,\n  liftObstacleHuggingSameSideRails,\n  liftTopLaneTitleBandsAboveRails,\n  reassignCrossingExternalRailChannels,\n  resolveRenderedOrthogonalCrossings,\n  separateSharedRenderedTerminalLanes,\n  shiftLeftLaneTitleBandsLeftOfRails,\n  shortcutRedundantOrthogonalJogs,\n  swapDestinationTerminalTailsToReduceCrossings,\n} from './direction/materializedGeometry.js';\nimport { simplifyDetouredEdges } from './direction/detourSimplification.js';\nimport { anchorLabelsToPolyline } from './direction/labelAnchoring.js';\nimport { straightenCollinearSiblingDetours } from './direction/siblingSharedFaceRouting.js';\nimport { nudgeSharedInteriorSubpaths } from './direction/sharedTrackNudging.js';\nexport { validateSwimlanesLayout } from './direction/validation.js';\n\n/** Applies direction transforms and post-routing cleanup to a swimlane layout. */\nexport function postProcessSwimlaneLayout(layout: LayoutData, direction?: string): void {\n  const nodes = layout.nodes ?? [];\n  const edges = layout.edges ?? [];\n  const contentNodes = nodes.filter((n) => !n.isGroup);\n\n  // TB is the canonical orientation. LR/RL rotate rank progression onto X;\n  // BT mirrors the canonical Y progression. Cleanup passes below operate in\n  // whichever coordinate system this step leaves behind.\n  if (\n    (direction === 'LR' || direction === 'RL') &&\n    contentNodes.length > 0 &&\n    !applyLrDirectionTransform(layout, direction)\n  ) {\n    return;\n  }\n\n  if (direction === 'BT' && contentNodes.length > 0 && !applyBtDirectionTransform(layout)) {\n    return;\n  }\n\n  for (const edge of edges) {\n    if ((edge as { isLayoutOnly?: boolean }).isLayoutOnly) {\n      continue;\n    }\n    const pts = (edge as { points?: { x: number; y: number }[] }).points;\n    if (!pts || pts.length < 2) {\n      continue;\n    }\n    (edge as { points: { x: number; y: number }[] }).points = simplifyPolyline(\n      orthogonalizePolyline(pts)\n    );\n  }\n\n  simplifyDetouredEdges(edges as any[], nodes);\n\n  // Prefer shorter sibling routes when a local port shift keeps them clear.\n  straightenCollinearSiblingDetours(edges as any[], nodes);\n\n  // Swap a source port only when it produces a clear L-shape with fewer bends.\n  portSwapToLShape(edges as any[], nodes);\n\n  const nodeByIdMap = new Map<string, any>();\n  for (const n of nodes) {\n    nodeByIdMap.set(String(n.id), n);\n  }\n  // Initial label anchoring against the routed polylines. The cleanup passes\n  // below (nudging, terminal-lane splits, crossing resolution) can still reshape\n  // these polylines, so labels are re-anchored once more at the end.\n  anchorLabelsToPolyline(edges, nodeByIdMap);\n\n  clipEdgeEndpointsToNodeBoundaries(edges, nodeByIdMap);\n\n  // Retarget short terminal stubs that are hidden by endpoint clipping.\n  collapseShortTerminalStub(edges, nodeByIdMap);\n\n  // Wybrow-style shared-track nudge. The router may legitimately bundle\n  // connectors onto the same rail, but before rendering those coincident\n  // middle rails must be separated into nearby parallel tracks. This pass\n  // keeps endpoint stubs pinned and only offsets interior H/V segments whose\n  // same-axis span overlaps another edge.\n  nudgeSharedInteriorSubpaths(edges, nodeByIdMap);\n\n  // Materialized-render terminal lane split. The raw layout can still look\n  // valid while the renderer's endpoint clipping creates coincident first/last\n  // stubs on a shared node face. Split those visible terminal rails before the\n  // endpoint-duplication handoff pins them.\n  separateSharedRenderedTerminalLanes(edges, nodeByIdMap);\n\n  // Once terminal lanes have been separated, some earlier same-track detours\n  // become unnecessary. Remove only provably redundant rectangular doglegs;\n  // safety checks preserve obstacle clearance and the newly split lanes.\n  collapseRedundantRectangularDoglegs(edges, nodeByIdMap);\n\n  // Same-side rails can be routed just inside a taller intervening node's\n  // border. Lift those rails outside the blocker before crossing cleanup.\n  liftObstacleHuggingSameSideRails(edges, nodeByIdMap);\n\n  // Some shared-destination crossings only improve when two terminal ports\n  // exchange places together. Try that bounded transaction before falling back\n  // to whole-edge reroutes.\n  swapDestinationTerminalTailsToReduceCrossings(edges, nodeByIdMap);\n\n  const finalizeRenderedEdges = (): void => {\n    resolveRenderedOrthogonalCrossings(edges, nodeByIdMap);\n    reassignCrossingExternalRailChannels(edges, nodeByIdMap);\n    shortcutRedundantOrthogonalJogs(edges, nodeByIdMap);\n    anchorLabelsToPolyline(edges, nodeByIdMap);\n    prepareEdgeEndpointsForRenderer(edges, nodeByIdMap);\n    liftObstacleHuggingSameSideRails(edges, nodeByIdMap);\n    anchorLabelsToPolyline(edges, nodeByIdMap);\n    prepareEdgeEndpointsForRenderer(edges, nodeByIdMap);\n  };\n\n  // Wybrow-style crossing cleanup for the materialized render geometry. This\n  // pass only activates when strict H/V crossings remain after the lower-level\n  // nudging passes. It tries bounded port-pair and outer-channel candidates,\n  // preserving obstacle clearance and accepting only candidates that reduce the\n  // rendered crossing count or shorten an equally crossing route.\n  finalizeRenderedEdges();\n\n  // Renderer endpoint preparation materializes the visible endpoint geometry.\n  // Run the shared-track pass once more on that visible shape, then refresh\n  // labels and endpoint handoff. `prepareEdgeEndpointsForRenderer` is\n  // idempotent, so unchanged edges do not accumulate duplicate endpoints.\n  nudgeSharedInteriorSubpaths(edges, nodeByIdMap);\n\n  // Endpoint preparation materializes the renderer-facing terminal stubs. In\n  // long return-edge cases those stubs can reveal a crossing that was not\n  // present in the pre-materialized route, so run the bounded cleanup once\n  // more and then re-prepare the endpoints it reshaped.\n  finalizeRenderedEdges();\n\n  // Swimlane title bands are visual headers, not routing obstacles. After all\n  // edge geometry is final, move the aligned title bands out of any clear rail\n  // that still crosses the title section.\n  liftTopLaneTitleBandsAboveRails(edges, nodeByIdMap);\n  shiftLeftLaneTitleBandsLeftOfRails(edges, nodeByIdMap);\n  // Moving one aligned title band can expose a second title/rail interaction\n  // after the group bounds settle. The passes are idempotent, so one bounded\n  // repeat keeps headers out of late crossing-cleanup routes without rerouting\n  // the edges again.\n  liftTopLaneTitleBandsAboveRails(edges, nodeByIdMap);\n  shiftLeftLaneTitleBandsLeftOfRails(edges, nodeByIdMap);\n}\n", "import type { Graph, EdgeRef, NodeId } from './helpers.js';\n// cspell:ignore acyclicity topo indeg preds succs\n\n// Normalize/validate a Graph view; ensure nodeById exists and edges refer to known nodes\nexport function normalizeGraph(g: Graph): Graph {\n  const nodeById = new Map(g.nodeById);\n  // Filter edges with unknown endpoints and de-duplicate by id+endpoints\n  const seen = new Set<string>();\n  const edges: EdgeRef[] = [];\n  for (const e of g.edges) {\n    if (!nodeById.has(e.src) || !nodeById.has(e.dst)) {\n      continue;\n    }\n    const key = `${e.id}:${e.src}->${e.dst}`;\n    if (seen.has(key)) {\n      continue;\n    }\n    seen.add(key);\n    edges.push(e);\n  }\n  const nodes = [...nodeById.keys()];\n  return { nodes, edges, layout: g.layout, nodeById };\n}\n\n// Return incoming edges for v\nexport function incoming(g: Graph, v: NodeId): EdgeRef[] {\n  return g.edges.filter((e) => e.dst === v);\n}\n\n// Return outgoing edges for v\nexport function outgoing(g: Graph, v: NodeId): EdgeRef[] {\n  return g.edges.filter((e) => e.src === v);\n}\n\nexport function buildSuccessorMap(g: Graph): Map<NodeId, NodeId[]> {\n  const succs = new Map<NodeId, NodeId[]>();\n  for (const v of g.nodes) {\n    succs.set(v, []);\n  }\n  for (const e of g.edges) {\n    succs.get(e.src)!.push(e.dst);\n  }\n  return succs;\n}\n\nexport function buildSortedSuccessorMap(g: Graph): Map<NodeId, NodeId[]> {\n  const succs = buildSuccessorMap(g);\n  for (const successors of succs.values()) {\n    successors.sort((a, b) => a.localeCompare(b));\n  }\n  return succs;\n}\n\nexport function buildInDegreeMap(g: Graph): Map<NodeId, number> {\n  const indeg = new Map<NodeId, number>();\n  for (const v of g.nodes) {\n    indeg.set(v, 0);\n  }\n  for (const e of g.edges) {\n    indeg.set(e.dst, (indeg.get(e.dst) ?? 0) + 1);\n  }\n  return indeg;\n}\n\nexport function sortedZeroInDegreeNodes(indeg: Map<NodeId, number>): NodeId[] {\n  return [...indeg.entries()]\n    .filter(([, degree]) => degree === 0)\n    .map(([id]) => id)\n    .sort((a, b) => a.localeCompare(b));\n}\n\nexport function buildPredecessorSuccessorMaps(\n  g: Graph,\n  includeEdge: (edge: EdgeRef) => boolean = () => true\n): { preds: Map<NodeId, NodeId[]>; succs: Map<NodeId, NodeId[]> } {\n  const preds = new Map<NodeId, NodeId[]>();\n  const succs = new Map<NodeId, NodeId[]>();\n  for (const v of g.nodes) {\n    preds.set(v, []);\n    succs.set(v, []);\n  }\n  for (const e of g.edges) {\n    if (!includeEdge(e)) {\n      continue;\n    }\n    succs.get(e.src)!.push(e.dst);\n    preds.get(e.dst)!.push(e.src);\n  }\n  return { preds, succs };\n}\n\nexport function buildLayersFromRanks(\n  g: Graph,\n  order: NodeId[],\n  rankOf: Record<NodeId, number>,\n  opts?: { skipGroups?: boolean }\n): NodeId[][] {\n  let maxRank = 0;\n  for (const v of g.nodes) {\n    if (opts?.skipGroups && g.nodeById.get(v)?.isGroup) {\n      continue;\n    }\n    maxRank = Math.max(maxRank, rankOf[v] ?? 0);\n  }\n\n  const layers: NodeId[][] = Array.from({ length: maxRank + 1 }, () => []);\n  for (const v of order) {\n    if (opts?.skipGroups && g.nodeById.get(v)?.isGroup) {\n      continue;\n    }\n    layers[Math.max(0, rankOf[v] ?? 0)].push(v);\n  }\n  return layers;\n}\n\n// Detect acyclicity via DFS (white/gray/black sets)\nexport function isAcyclic(g: Graph): boolean {\n  const color: Record<NodeId, 0 | 1 | 2> = Object.create(null);\n  for (const v of g.nodes) {\n    color[v] = 0; // 0 white, 1 gray, 2 black\n  }\n\n  const adj = buildSuccessorMap(g);\n\n  const dfs = (u: NodeId): boolean => {\n    color[u] = 1; // gray\n    for (const v of adj.get(u) ?? []) {\n      if (color[v] === 0 && !dfs(v)) {\n        return false;\n      }\n      if (color[v] === 1) {\n        // back-edge\n        return false;\n      }\n    }\n    color[u] = 2; // black\n    return true;\n  };\n\n  for (const v of g.nodes) {\n    if (color[v] === 0 && !dfs(v)) {\n      return false;\n    }\n  }\n  return true;\n}\n\n// Topological sort (Kahn). Returns null if cycles exist.\nexport function topoSortIfAcyclic(g: Graph): NodeId[] | null {\n  const indeg = buildInDegreeMap(g);\n  const queue = sortedZeroInDegreeNodes(indeg);\n  const order: NodeId[] = [];\n  const adj = buildSortedSuccessorMap(g);\n\n  while (queue.length) {\n    const u = queue.shift()!;\n    order.push(u);\n    for (const v of adj.get(u) ?? []) {\n      indeg.set(v, (indeg.get(v) ?? 0) - 1);\n      if ((indeg.get(v) ?? 0) === 0) {\n        // insert keeping sorted order for determinism\n        let i = 0;\n        while (i < queue.length && queue[i] < v) {\n          i++;\n        }\n        queue.splice(i, 0, v);\n      }\n    }\n  }\n\n  return order.length === g.nodes.length ? order : null;\n}\n\n/**\n * Build an index map from node IDs to their positions in a layer.\n * This is used for efficient lookups during crossing minimization.\n */\nexport function buildLayerIndex(layer: NodeId[]): Map<NodeId, number> {\n  const m = new Map<NodeId, number>();\n  let index = 0;\n  for (const id of layer) {\n    m.set(id, index);\n    index++;\n  }\n  return m;\n}\n\nexport function countInversions(values: number[]): number {\n  const tmp = new Array<number>(values.length);\n  const count = (left: number, right: number): number => {\n    if (right - left <= 1) {\n      return 0;\n    }\n    const mid = (left + right) >> 1;\n    let inversions = count(left, mid) + count(mid, right);\n    let i = left;\n    let j = mid;\n    let k = left;\n    while (i < mid || j < right) {\n      if (j >= right || (i < mid && values[i] <= values[j])) {\n        tmp[k++] = values[i++];\n      } else {\n        tmp[k++] = values[j++];\n        inversions += mid - i;\n      }\n    }\n    for (let t = left; t < right; t++) {\n      values[t] = tmp[t];\n    }\n    return inversions;\n  };\n  return count(0, values.length);\n}\n", "import type { Graph, Edge, EdgeRef, NodeId } from './helpers.js';\nimport { normalizeGraph } from './phase0.helpers.js';\n// cspell:ignore Graphviz acyc Eades\n\nexport interface CycleRemovalResult {\n  acyclic: Graph;\n  reversed: Edge[]; // edges that were reversed (original orientation)\n}\n\n// Deterministic DFS-based cycle removal (similar to Graphviz dot back-edge marking)\nexport function removeCycles_DFS(g: Graph): CycleRemovalResult {\n  const gn = normalizeGraph(g);\n\n  // Build adjacency with deterministic order\n  const adj = new Map<NodeId, EdgeRef[]>();\n  for (const v of gn.nodes) {\n    adj.set(v, []);\n  }\n  for (const e of gn.edges) {\n    adj.get(e.src)!.push(e);\n  }\n  for (const arr of adj.values()) {\n    arr.sort((a, b) => (a.dst === b.dst ? a.id.localeCompare(b.id) : a.dst.localeCompare(b.dst)));\n  }\n\n  const color: Record<NodeId, 0 | 1 | 2> = Object.create(null);\n  for (const v of gn.nodes) {\n    color[v] = 0; // 0 white, 1 gray, 2 black\n  }\n\n  const reversed: EdgeRef[] = [];\n\n  const dfs = (u: NodeId) => {\n    color[u] = 1;\n    for (const e of adj.get(u) ?? []) {\n      const v = e.dst;\n      if (color[v] === 0) {\n        dfs(v);\n      } else if (color[v] === 1) {\n        // back-edge u->v; mark for reversal\n        reversed.push(e);\n      }\n    }\n    color[u] = 2;\n  };\n\n  // Visit in deterministic order\n  const nodesSorted = [...gn.nodes].sort((a, b) => a.localeCompare(b));\n  for (const v of nodesSorted) {\n    if (color[v] === 0) {\n      dfs(v);\n    }\n  }\n\n  // Build acyclic edge set by reversing all marked edges\n  const toReverse = new Set<string>(reversed.map((e) => `${e.id}:${e.src}->${e.dst}`));\n  const acycEdges: EdgeRef[] = gn.edges.map((e) =>\n    toReverse.has(`${e.id}:${e.src}->${e.dst}`)\n      ? { id: e.id, src: e.dst, dst: e.src, weight: e.weight, ref: e.ref }\n      : e\n  );\n\n  const acyclic: Graph = {\n    nodes: [...gn.nodes],\n    edges: acycEdges,\n    layout: gn.layout,\n    nodeById: new Map(gn.nodeById),\n  };\n  return { acyclic, reversed };\n}\n", "import type { Graph, NodeId } from './helpers.js';\n\n/**\n * Options controlling how layers are assigned in the Sugiyama pipeline.\n */\nexport interface LayeringOptions {\n  /** If true, a node with exactly one incoming edge inherits its predecessor's layer. */\n  compactSingleInput?: boolean;\n  /** If true, ignore edges from other lanes when calculating layer positions. */\n  ignoreCrossLaneEdges?: boolean;\n  /** If true, try to lift nodes to reduce crossings between layers. */\n  optimizeRanksByCrossings?: boolean;\n  /** Diagram direction, used by lane-aware rank heuristics with direction-specific failure modes. */\n  direction?: 'TB' | 'LR' | 'BT' | 'RL';\n}\n\n/**\n * Computes the \"top lane\" (outermost group container) for each node.\n *\n * Returns a map from node id -\\> lane id (top-level group) or null if the node\n * does not belong to any lane.\n */\nexport function buildTopLaneMap(g: Graph): Map<NodeId, string | null> {\n  const cache = new Map<NodeId, string | null>();\n\n  const resolve = (id: NodeId): string | null => {\n    if (cache.has(id)) {\n      return cache.get(id)!;\n    }\n    const node = g.nodeById.get(id) as any;\n    if (!node) {\n      cache.set(id, null);\n      return null;\n    }\n    const parentId = node.parentId as NodeId | undefined;\n    if (!parentId) {\n      cache.set(id, null);\n      return null;\n    }\n    const parentLane = resolve(parentId);\n    const lane = parentLane ?? parentId;\n    cache.set(id, lane);\n    return lane;\n  };\n\n  for (const id of g.nodes) {\n    resolve(id);\n  }\n  return cache;\n}\n\nexport function createTopLaneResolver(g: Graph): (id: NodeId) => string | null {\n  const topLaneMap = buildTopLaneMap(g);\n  return (id: NodeId): string | null => topLaneMap.get(id) ?? null;\n}\n\nexport function buildTopLaneOrder(g: Graph): string[] {\n  const lanes: string[] = [];\n  for (const node of g.layout.nodes ?? []) {\n    if (node.isGroup && !node.parentId) {\n      lanes.push(node.id);\n    }\n  }\n  return [...new Set(lanes)].reverse();\n}\n\nexport function resolveTopLaneOrder(g: Graph, preferredOrder?: string[]): string[] {\n  const sourceOrder = buildTopLaneOrder(g);\n  if (!preferredOrder || preferredOrder.length === 0) {\n    return sourceOrder;\n  }\n\n  const sourceLaneIds = new Set(sourceOrder);\n  const seen = new Set<string>();\n  const resolved: string[] = [];\n  for (const laneId of preferredOrder) {\n    if (!sourceLaneIds.has(laneId) || seen.has(laneId)) {\n      continue;\n    }\n    seen.add(laneId);\n    resolved.push(laneId);\n  }\n  for (const laneId of sourceOrder) {\n    if (seen.has(laneId)) {\n      continue;\n    }\n    resolved.push(laneId);\n  }\n  return resolved;\n}\n", "/**\n * Configuration constants for the Swimlanes layout algorithm.\n * Centralizes all magic numbers and default values for maintainability.\n */\n\n/**\n * Edge routing and spacing constants\n */\nexport const EDGE_ROUTING = {\n  /** Spacing between parallel edges in the same corridor (px) */\n  EDGE_GAP: 12,\n\n  /** Horizontal offset from lane boundary to corridor center (px) */\n  LANE_MARGIN: 20,\n} as const;\n\n/**\n * Numerical precision constants\n */\nexport const PRECISION = {\n  /** Epsilon for floating-point comparisons */\n  EPSILON: 1e-6,\n} as const;\n\n/**\n * Layer assignment constants\n */\nexport const LAYERING = {\n  /** Default number of iterations for gravity-based layering */\n  GRAVITY_ITERATIONS: 8,\n\n  /** Maximum number of passes for crossing-based rank optimization */\n  MAX_CROSSING_OPTIMIZATION_PASSES: 4,\n\n  /** Whether to compact single-input nodes by default */\n  DEFAULT_COMPACT_SINGLE_INPUT: true,\n} as const;\n\n/**\n * Coordinate assignment constants\n */\nexport const COORDINATES = {\n  /** Default vertical gap between layers (px) */\n  DEFAULT_LAYER_GAP: 100,\n\n  /** Default horizontal gap between nodes (px) */\n  DEFAULT_NODE_GAP: 40,\n} as const;\n", "import type { Graph, NodeId } from './helpers.js';\nimport {\n  buildPredecessorSuccessorMaps,\n  normalizeGraph,\n  topoSortIfAcyclic,\n} from './phase0.helpers.js';\n// cspell:ignore preorder postorder preds topo\n\nexport interface DrivingTreeBlock {\n  id: number;\n  nodes: NodeId[];\n  edges: [NodeId, NodeId][];\n}\n\nexport interface DrivingTree {\n  parent: Map<NodeId, NodeId | null>;\n  children: Map<NodeId, NodeId[]>;\n  roots: NodeId[];\n  componentOf: Map<NodeId, number>;\n  blocks: DrivingTreeBlock[];\n  nodeBlocks: Map<NodeId, number[]>;\n  adjacency: Map<NodeId, NodeId[]>;\n  preorder: NodeId[];\n  postorder: NodeId[];\n  topologicalOrder: NodeId[];\n}\n\nexport interface DrivingTreeBuildOptions {\n  rankHint?: Record<NodeId, number>;\n  laneOf?: (id: NodeId) => string | null;\n}\n\n// Build the spanning forest and traversal metadata used by tree ordering.\nexport function buildDrivingTree(graph: Graph, opts?: DrivingTreeBuildOptions): DrivingTree {\n  const g = normalizeGraph(graph);\n  const laneOf = opts?.laneOf ?? (() => null);\n  const rankHint = opts?.rankHint;\n\n  const { preds } = buildPredecessorSuccessorMaps(g);\n  for (const arr of preds.values()) {\n    arr.sort((a, b) => a.localeCompare(b));\n  }\n\n  const topoOrder = topoSortIfAcyclic(g) ?? [...g.nodes].sort((a, b) => a.localeCompare(b));\n  const topoIndex = new Map<NodeId, number>();\n  for (const [idx, id] of topoOrder.entries()) {\n    topoIndex.set(id, idx);\n  }\n\n  const parent = new Map<NodeId, NodeId | null>();\n  const children = new Map<NodeId, NodeId[]>();\n  for (const node of g.nodes) {\n    children.set(node, []);\n  }\n\n  for (const node of topoOrder) {\n    const candidates = (preds.get(node) ?? []).filter((p) => parent.has(p));\n    if (candidates.length > 0) {\n      const chosen = chooseParent(node, candidates, {\n        laneOf,\n        rankHint,\n        topoIndex,\n      });\n      parent.set(node, chosen);\n      children.get(chosen)!.push(node);\n    } else if (!parent.has(node)) {\n      parent.set(node, null);\n    }\n  }\n\n  for (const node of g.nodes) {\n    if (!parent.has(node)) {\n      parent.set(node, null);\n    }\n  }\n\n  const rootSet = new Set<NodeId>();\n  for (const node of g.nodes) {\n    if ((parent.get(node) ?? null) === null) {\n      rootSet.add(node);\n    }\n  }\n  const roots = [...rootSet].sort((a, b) => {\n    const ta = topoIndex.get(a) ?? 0;\n    const tb = topoIndex.get(b) ?? 0;\n    if (ta === tb) {\n      return a.localeCompare(b);\n    }\n    return ta - tb;\n  });\n\n  const adjacency = buildAdjacency(g);\n  const adjacencyList = new Map<NodeId, NodeId[]>();\n  for (const [node, set] of adjacency.entries()) {\n    adjacencyList.set(\n      node,\n      [...set].sort((a, b) => a.localeCompare(b))\n    );\n  }\n\n  const componentOf = assignComponents(adjacencyList);\n  const blocks = computeBlocks(adjacencyList);\n  const nodeBlocks = new Map<NodeId, number[]>();\n  for (const node of g.nodes) {\n    nodeBlocks.set(node, []);\n  }\n  for (const block of blocks) {\n    for (const node of block.nodes) {\n      const list = nodeBlocks.get(node);\n      if (list) {\n        list.push(block.id);\n      } else {\n        nodeBlocks.set(node, [block.id]);\n      }\n    }\n  }\n\n  const preorder: NodeId[] = [];\n  const postorder: NodeId[] = [];\n  const seen = new Set<NodeId>();\n\n  const walk = (node: NodeId) => {\n    if (seen.has(node)) {\n      return;\n    }\n    seen.add(node);\n    preorder.push(node);\n    for (const child of children.get(node) ?? []) {\n      walk(child);\n    }\n    postorder.push(node);\n  };\n\n  for (const root of roots) {\n    walk(root);\n  }\n  for (const node of topoOrder) {\n    walk(node);\n  }\n\n  return {\n    parent,\n    children,\n    roots,\n    componentOf,\n    blocks,\n    nodeBlocks,\n    adjacency: adjacencyList,\n    preorder,\n    postorder,\n    topologicalOrder: topoOrder,\n  };\n}\n\ninterface ParentSelectionContext {\n  laneOf: (id: NodeId) => string | null;\n  rankHint?: Record<NodeId, number>;\n  topoIndex: Map<NodeId, number>;\n}\n\nfunction chooseParent(node: NodeId, candidates: NodeId[], ctx: ParentSelectionContext): NodeId {\n  const laneNode = ctx.laneOf(node);\n  const sorted = [...candidates].sort((a, b) => {\n    const laneA = ctx.laneOf(a);\n    const laneB = ctx.laneOf(b);\n    const sameLaneA = laneA != null && laneA === laneNode;\n    const sameLaneB = laneB != null && laneB === laneNode;\n    if (sameLaneA !== sameLaneB) {\n      return sameLaneA ? -1 : 1;\n    }\n\n    const rankA = ctx.rankHint?.[a];\n    const rankB = ctx.rankHint?.[b];\n    if (rankA != null && rankB != null && rankA !== rankB) {\n      return rankB - rankA;\n    }\n\n    const idxA = ctx.topoIndex.get(a) ?? 0;\n    const idxB = ctx.topoIndex.get(b) ?? 0;\n    if (idxA !== idxB) {\n      return idxA - idxB;\n    }\n\n    return a.localeCompare(b);\n  });\n  return sorted[0];\n}\n\nfunction buildAdjacency(g: Graph): Map<NodeId, Set<NodeId>> {\n  const adjacency = new Map<NodeId, Set<NodeId>>();\n  for (const node of g.nodes) {\n    adjacency.set(node, new Set<NodeId>());\n  }\n  for (const e of g.edges) {\n    adjacency.get(e.src)!.add(e.dst);\n    adjacency.get(e.dst)!.add(e.src);\n  }\n  return adjacency;\n}\n\nfunction assignComponents(adjacency: Map<NodeId, NodeId[]>): Map<NodeId, number> {\n  const componentOf = new Map<NodeId, number>();\n  let componentId = 0;\n  for (const node of adjacency.keys()) {\n    if (componentOf.has(node)) {\n      continue;\n    }\n    const stack: NodeId[] = [node];\n    while (stack.length > 0) {\n      const cur = stack.pop()!;\n      if (componentOf.has(cur)) {\n        continue;\n      }\n      componentOf.set(cur, componentId);\n      for (const next of adjacency.get(cur) ?? []) {\n        if (!componentOf.has(next)) {\n          stack.push(next);\n        }\n      }\n    }\n    componentId++;\n  }\n  return componentOf;\n}\n\nfunction computeBlocks(adjacency: Map<NodeId, NodeId[]>): DrivingTreeBlock[] {\n  const discovery = new Map<NodeId, number>();\n  const low = new Map<NodeId, number>();\n  const edgeStack: [NodeId, NodeId][] = [];\n  const blocks: DrivingTreeBlock[] = [];\n  let time = 0;\n\n  const visit = (node: NodeId, parent: NodeId | null) => {\n    discovery.set(node, ++time);\n    low.set(node, time);\n\n    for (const next of adjacency.get(node) ?? []) {\n      if (next === parent) {\n        continue;\n      }\n      if (!discovery.has(next)) {\n        edgeStack.push([node, next]);\n        visit(next, node);\n        low.set(node, Math.min(low.get(node) ?? time, low.get(next) ?? time));\n        if ((low.get(next) ?? 0) >= (discovery.get(node) ?? 0)) {\n          blocks.push(popBlock(node, next, edgeStack, blocks.length));\n        }\n      } else if ((discovery.get(next) ?? 0) < (discovery.get(node) ?? 0)) {\n        edgeStack.push([node, next]);\n        low.set(node, Math.min(low.get(node) ?? time, discovery.get(next) ?? time));\n      }\n    }\n  };\n\n  for (const node of adjacency.keys()) {\n    if (!discovery.has(node)) {\n      visit(node, null);\n    }\n  }\n\n  return blocks;\n}\n\nfunction popBlock(u: NodeId, v: NodeId, stack: [NodeId, NodeId][], id: number): DrivingTreeBlock {\n  const edges: [NodeId, NodeId][] = [];\n  const nodes = new Set<NodeId>();\n  while (stack.length > 0) {\n    const edge = stack.pop()!;\n    edges.push(edge);\n    nodes.add(edge[0]);\n    nodes.add(edge[1]);\n    if ((edge[0] === u && edge[1] === v) || (edge[0] === v && edge[1] === u)) {\n      break;\n    }\n  }\n  return { id, edges, nodes: [...nodes] };\n}\n", "import type { Graph, NodeId } from './helpers.js';\nimport type { DrivingTree } from './driving-tree.js';\n\n/**\n * Computes crossing counts for each parent/child pair in the driving tree.\n *\n * Uses a binary-lifting LCA over the driving tree and counts, for every edge,\n * how many layers it spans below the LCA. These per-layer counts are then\n * accumulated to obtain, for each parent -\\> child edge in the tree, an\n * approximate \"subtree crossing\" score used when ordering children.\n */\nexport function computeSubtreeCrossCounts(\n  g: Graph,\n  rankOf: Record<NodeId, number>,\n  tree: DrivingTree\n): Map<NodeId, Map<NodeId, number>> {\n  const nodes = [...g.nodes];\n  const indexOf = new Map<NodeId, number>();\n  for (const [i, node] of nodes.entries()) {\n    indexOf.set(node, i);\n  }\n  const n = nodes.length;\n\n  const parentIdx = new Array<number>(n).fill(-1);\n  const depth = new Array<number>(n).fill(0);\n\n  const queue: NodeId[] = [];\n  const seen = new Set<NodeId>();\n\n  // Seed BFS from roots\n  for (const node of nodes) {\n    const parentId = tree.parent.get(node) ?? null;\n    const idx = indexOf.get(node);\n    if (idx == null) {\n      continue;\n    }\n    if (parentId == null) {\n      parentIdx[idx] = -1;\n      depth[idx] = 0;\n      if (!seen.has(node)) {\n        seen.add(node);\n        queue.push(node);\n      }\n    }\n  }\n\n  while (queue.length > 0) {\n    const current = queue.shift()!;\n    const currentIdx = indexOf.get(current);\n    if (currentIdx == null) {\n      continue;\n    }\n    const childList = tree.children.get(current) ?? [];\n    for (const child of childList) {\n      if (seen.has(child)) {\n        continue;\n      }\n      const childIdx = indexOf.get(child);\n      if (childIdx == null) {\n        continue;\n      }\n      parentIdx[childIdx] = currentIdx;\n      depth[childIdx] = depth[currentIdx] + 1;\n      seen.add(child);\n      queue.push(child);\n    }\n  }\n\n  // Ensure all nodes are represented even if disconnected in the tree\n  for (const node of nodes) {\n    if (seen.has(node)) {\n      continue;\n    }\n    const idx = indexOf.get(node);\n    if (idx == null) {\n      continue;\n    }\n    parentIdx[idx] = -1;\n    depth[idx] = 0;\n    seen.add(node);\n  }\n\n  const maxLog = Math.max(1, Math.ceil(Math.log2(Math.max(1, n))) + 1);\n  const up: number[][] = Array.from({ length: maxLog }, () => new Array<number>(n).fill(-1));\n  for (let i = 0; i < n; i++) {\n    up[0][i] = parentIdx[i];\n  }\n  for (let k = 1; k < maxLog; k++) {\n    for (let i = 0; i < n; i++) {\n      const prev = up[k - 1][i];\n      up[k][i] = prev === -1 ? -1 : up[k - 1][prev];\n    }\n  }\n\n  const lcaIndex = (aIdx: number, bIdx: number): number => {\n    if (aIdx === -1 || bIdx === -1) {\n      return -1;\n    }\n    if (depth[aIdx] < depth[bIdx]) {\n      [aIdx, bIdx] = [bIdx, aIdx];\n    }\n    const diff = depth[aIdx] - depth[bIdx];\n    for (let k = 0; k < maxLog; k++) {\n      if ((diff >> k) & 1) {\n        aIdx = up[k][aIdx];\n        if (aIdx === -1) {\n          return -1;\n        }\n      }\n    }\n    if (aIdx === bIdx) {\n      return aIdx;\n    }\n    for (let k = maxLog - 1; k >= 0; k--) {\n      const upA = up[k][aIdx];\n      const upB = up[k][bIdx];\n      if (upA === -1 || upB === -1) {\n        continue;\n      }\n      if (upA !== upB) {\n        aIdx = upA;\n        bIdx = upB;\n      }\n    }\n    return up[0][aIdx];\n  };\n\n  const ownCounts = Array.from({ length: n }, () => new Map<number, number>());\n\n  // Count, for each LCA, how many edges pass through each layer below it.\n  for (const edge of g.edges) {\n    let src = edge.src;\n    let dst = edge.dst;\n    let ru = rankOf[src];\n    let rv = rankOf[dst];\n    if (ru == null || rv == null) {\n      continue;\n    }\n    if (ru > rv) {\n      [src, dst] = [dst, src];\n      [ru, rv] = [rv, ru];\n    }\n    if (ru == null || rv == null || ru === rv) {\n      continue;\n    }\n    const upperIdx = indexOf.get(src);\n    const lowerIdx = indexOf.get(dst);\n    if (upperIdx == null || lowerIdx == null) {\n      continue;\n    }\n    const lca = lcaIndex(upperIdx, lowerIdx);\n    if (lca === -1) {\n      continue;\n    }\n    const bucket = ownCounts[lca];\n    for (let layer = ru; layer < rv; layer++) {\n      bucket.set(layer, (bucket.get(layer) ?? 0) + 1);\n    }\n  }\n\n  const crossCounts = new Map<NodeId, Map<NodeId, number>>();\n\n  const mergeInto = (target: Map<number, number>, source: Map<number, number>) => {\n    if (source.size === 0) {\n      return;\n    }\n    for (const [layer, value] of source) {\n      target.set(layer, (target.get(layer) ?? 0) + value);\n    }\n  };\n\n  const visited = new Set<NodeId>();\n  const dfs = (node: NodeId): Map<number, number> => {\n    const idx = indexOf.get(node);\n    visited.add(node);\n    const base = idx == null ? undefined : ownCounts[idx];\n    const accumulator = base ? new Map<number, number>(base) : new Map<number, number>();\n    const childList = tree.children.get(node) ?? [];\n    for (const child of childList) {\n      const childMap = dfs(child);\n      const parentLayer = rankOf[node];\n      if (parentLayer != null) {\n        let map = crossCounts.get(node);\n        if (!map) {\n          map = new Map<NodeId, number>();\n          crossCounts.set(node, map);\n        }\n        let value = childMap.get(parentLayer) ?? 0;\n        const childLayer = rankOf[child];\n        if (childLayer != null && childLayer > parentLayer) {\n          value += 1;\n        }\n        map.set(child, value);\n      }\n      mergeInto(accumulator, childMap);\n    }\n    return accumulator;\n  };\n\n  for (const root of tree.roots) {\n    if (!visited.has(root)) {\n      dfs(root);\n    }\n  }\n  for (const node of nodes) {\n    if (!visited.has(node)) {\n      dfs(node);\n    }\n  }\n\n  return crossCounts;\n}\n", "import type { NodeId } from './helpers.js';\n\n// cspell:ignore multitree\n/**\n * Utilities shared by the multitree-based layer ordering logic.\n */\nexport function annotateMinimumLayers(\n  nodes: NodeId[],\n  children: Map<NodeId, NodeId[]>,\n  rankOf: Record<NodeId, number>\n): Map<NodeId, number> {\n  const minLayer = new Map<NodeId, number>();\n\n  const annotate = (node: NodeId) => {\n    let minL = rankOf[node] ?? 0;\n    const childList = [...(children.get(node) ?? [])];\n    childList.sort(compareByRankThenId(rankOf));\n    for (const child of childList) {\n      annotate(child);\n      const childMin = minLayer.get(child);\n      if (childMin != null) {\n        minL = Math.min(minL, childMin);\n      }\n    }\n    minLayer.set(node, minL);\n  };\n\n  for (const node of nodes) {\n    annotate(node);\n  }\n\n  return minLayer;\n}\n\nexport function compareByRankThenId(rankOf: Record<NodeId, number>) {\n  return (a: NodeId, b: NodeId) => {\n    const ra = rankOf[a] ?? 0;\n    const rb = rankOf[b] ?? 0;\n    return ra === rb ? a.localeCompare(b) : ra - rb;\n  };\n}\n\n/**\n * Emits nodes into layers in tree traversal order, using the provided\n * orderChildren function to determine the order of children.\n */\nexport function emitNodesInTreeOrder(\n  roots: NodeId[],\n  allNodes: NodeId[],\n  rankOf: Record<NodeId, number>,\n  orderChildren: (node: NodeId) => NodeId[]\n): NodeId[][] {\n  let maxRank = 0;\n  for (const node of allNodes) {\n    const r = rankOf[node] ?? 0;\n    if (r > maxRank) {\n      maxRank = r;\n    }\n  }\n\n  const layers: NodeId[][] = Array.from({ length: maxRank + 1 }, () => []);\n  const emitted = new Set<NodeId>();\n\n  const emit = (node: NodeId) => {\n    if (emitted.has(node)) {\n      return;\n    }\n    emitted.add(node);\n    const layer = rankOf[node] ?? 0;\n    if (!layers[layer]) {\n      layers[layer] = [];\n    }\n    layers[layer].push(node);\n    for (const child of orderChildren(node)) {\n      emit(child);\n    }\n  };\n\n  for (const root of roots) {\n    emit(root);\n  }\n\n  // Fallback for isolated nodes (if any were not connected through spanning forest)\n  for (const node of allNodes) {\n    if (!emitted.has(node)) {\n      const layer = rankOf[node] ?? 0;\n      if (!layers[layer]) {\n        layers[layer] = [];\n      }\n      layers[layer].push(node);\n      emitted.add(node);\n    }\n  }\n\n  return layers;\n}\n\n/**\n * Removes duplicate nodes from each layer while preserving order.\n */\nexport function deduplicateLayers(layers: NodeId[][]): NodeId[][] {\n  const result: NodeId[][] = [];\n  for (const layer of layers) {\n    const seen = new Set<NodeId>();\n    const deduped: NodeId[] = [];\n    for (const id of layer) {\n      if (seen.has(id)) {\n        continue;\n      }\n      seen.add(id);\n      deduped.push(id);\n    }\n    result.push(deduped);\n  }\n  return result;\n}\n", "import type { Graph, NodeId } from './helpers.js';\nimport { buildDrivingTree } from './driving-tree.js';\nimport { computeSubtreeCrossCounts } from './phase2.crossCounts.js';\nimport {\n  annotateMinimumLayers,\n  compareByRankThenId,\n  emitNodesInTreeOrder,\n  deduplicateLayers,\n} from './phase2.multitree.core.js';\n\n// cspell:ignore multitree Multitree\n\n/**\n * Creates a function that orders children by crossing counts and minimum layers.\n * Children in future layers are ordered by their minimum layer, while children\n * in the current layer are ordered by crossing counts.\n */\nfunction createChildOrderer(\n  children: Map<NodeId, NodeId[]>,\n  rankOf: Record<NodeId, number>,\n  crossCounts: Map<NodeId, Map<NodeId, number>>,\n  minLayer: Map<NodeId, number>\n): (node: NodeId) => NodeId[] {\n  return (node: NodeId): NodeId[] => {\n    const raw = children.get(node) ?? [];\n    if (raw.length === 0) {\n      return [];\n    }\n    const layer = rankOf[node] ?? 0;\n    const future: { child: NodeId; min: number }[] = [];\n    const present: NodeId[] = [];\n    const crossMap = crossCounts.get(node);\n\n    for (const child of raw) {\n      const minL = minLayer.get(child) ?? layer;\n      if (minL > layer) {\n        future.push({ child, min: minL });\n      } else {\n        present.push(child);\n      }\n    }\n\n    future.sort((a, b) => {\n      if (a.min === b.min) {\n        return a.child.localeCompare(b.child);\n      }\n      return a.min - b.min;\n    });\n\n    present.sort((a, b) => {\n      const ca = crossMap?.get(a) ?? 0;\n      const cb = crossMap?.get(b) ?? 0;\n      if (ca !== cb) {\n        return ca - cb;\n      }\n      const ma = minLayer.get(a) ?? layer;\n      const mb = minLayer.get(b) ?? layer;\n      if (ma !== mb) {\n        return ma - mb;\n      }\n      return a.localeCompare(b);\n    });\n\n    return [...future.map((item) => item.child), ...present];\n  };\n}\n\n/**\n * Builds a layering (array of layers) by traversing the driving tree in a\n * multitree order that tries to minimize crossings.\n */\nexport function buildMultitreeLayerOrder(\n  g: Graph,\n  rankOf: Record<NodeId, number>,\n  laneOf: (id: NodeId) => string | null\n): NodeId[][] {\n  const tree = buildDrivingTree(g, {\n    rankHint: rankOf,\n    laneOf,\n  });\n  const { children, roots } = tree;\n\n  // Ensure all nodes have a children entry\n  for (const node of g.nodes) {\n    if (!children.has(node)) {\n      children.set(node, []);\n    }\n  }\n\n  const crossCounts = computeSubtreeCrossCounts(g, rankOf, tree);\n\n  const rootsSorted = [...roots].sort(compareByRankThenId(rankOf));\n\n  // Annotate each node with the minimum layer in its subtree\n  const minLayer = annotateMinimumLayers(rootsSorted, children, rankOf);\n\n  // Create a function to order children by crossing counts\n  const orderChildren = createChildOrderer(children, rankOf, crossCounts, minLayer);\n\n  // Emit nodes in tree order\n  let layers = emitNodesInTreeOrder(rootsSorted, g.nodes, rankOf, orderChildren);\n\n  // Deduplicate each layer\n  layers = deduplicateLayers(layers);\n\n  return layers;\n}\n", "import type { Graph, NodeId, EdgeRef } from './helpers.js';\nimport {\n  buildLayerIndex,\n  buildPredecessorSuccessorMaps,\n  countInversions,\n} from './phase0.helpers.js';\nimport { LAYERING } from './config.js';\nimport { createTopLaneResolver } from './phase2.options.js';\nimport { buildMultitreeLayerOrder } from './phase2.multitree.order.js';\n// cspell:ignore acyclicity preds\n\nfunction countCrossingsBetweenAdjacent(upper: NodeId[], lower: NodeId[], edges: EdgeRef[]): number {\n  const upperSet = new Set(upper);\n  const lowerSet = new Set(lower);\n  const li = buildLayerIndex(lower);\n  const vs: number[] = [];\n  for (const e of edges) {\n    if (upperSet.has(e.src) && lowerSet.has(e.dst)) {\n      vs.push(li.get(e.dst)!);\n    }\n  }\n  return countInversions(vs);\n}\n\nfunction totalCrossings(\n  layers: NodeId[][],\n  edges: EdgeRef[],\n  rankOf: Record<NodeId, number>\n): number {\n  const expanded: EdgeRef[] = [];\n  for (const e of edges) {\n    const ru = rankOf[e.src];\n    const rv = rankOf[e.dst];\n    if (ru == null || rv == null || ru === rv) {\n      continue;\n    }\n    let upper = e.src;\n    let lower = e.dst;\n    let rUpper = ru;\n    let rLower = rv;\n    if (ru > rv) {\n      upper = e.dst;\n      lower = e.src;\n      rUpper = rv;\n      rLower = ru;\n    }\n    for (let L = rUpper; L < rLower; L++) {\n      expanded.push({ id: `${e.id}@${L}`, src: upper, dst: lower, ref: e.ref });\n    }\n  }\n  let sum = 0;\n  for (let i = 0; i + 1 < layers.length; i++) {\n    sum += countCrossingsBetweenAdjacent(layers[i], layers[i + 1], expanded);\n  }\n  return sum;\n}\n\n/**\n * Greedy local search that tries to lift nodes to reduce crossings while\n * preserving acyclicity (rank(v) \u0003e= rank(u)+1 for every edge u-\\>v).\n */\nexport function optimizeRanksByCrossings(\n  g: Graph,\n  initialRank: Record<NodeId, number>\n): Record<NodeId, number> {\n  const rankOf: Record<NodeId, number> = { ...initialRank } as any;\n  const { preds } = buildPredecessorSuccessorMaps(g);\n\n  const laneOf = createTopLaneResolver(g);\n\n  const layers = buildMultitreeLayerOrder(g, rankOf, laneOf);\n  let best = totalCrossings(layers, g.edges, rankOf);\n  const maxPasses = LAYERING.MAX_CROSSING_OPTIMIZATION_PASSES;\n  for (let pass = 0; pass < maxPasses; pass++) {\n    let changed = false;\n    const nodesByRank = [...g.nodes].sort((a, b) => (rankOf[b] ?? 0) - (rankOf[a] ?? 0));\n    for (const v of nodesByRank) {\n      const r = rankOf[v] ?? 0;\n      if (r === 0) {\n        continue;\n      }\n      let lb = 0;\n      for (const u of preds.get(v) ?? []) {\n        lb = Math.max(lb, (rankOf[u] ?? 0) + 1);\n      }\n      if (lb >= r) {\n        continue;\n      }\n      const old = r;\n      rankOf[v] = lb;\n      const trialLayers = buildMultitreeLayerOrder(g, rankOf, laneOf);\n      const score = totalCrossings(trialLayers, g.edges, rankOf);\n      if (score < best) {\n        best = score;\n        changed = true;\n      } else {\n        rankOf[v] = old;\n      }\n    }\n    if (!changed) {\n      break;\n    }\n  }\n  return rankOf;\n}\n", "import type { Graph, NodeId } from './helpers.js';\nimport { createTopLaneResolver } from './phase2.options.js';\n\n/**\n * Heuristic to push nodes with only cross-lane outgoing edges downward so\n * that same-lane successors have room to appear above them.\n */\nexport function adjustCrossLaneSources(g: Graph, rankOf: Record<NodeId, number>): void {\n  const topLaneOf = createTopLaneResolver(g);\n\n  const nodesByRank = [...g.nodes].sort(\n    (a, b) => (rankOf[a] ?? 0) - (rankOf[b] ?? 0) || a.localeCompare(b)\n  );\n  for (const v of nodesByRank) {\n    const laneV = topLaneOf(v);\n    if (!laneV) {\n      continue;\n    }\n    const outEdges = g.edges.filter((e) => e.src === v);\n    if (outEdges.length === 0) {\n      continue;\n    }\n    let hasSameLaneSucc = false;\n    let crossLaneCount = 0;\n    for (const e of outEdges) {\n      const laneDst = topLaneOf(e.dst);\n      if (laneDst == null || laneDst === laneV) {\n        hasSameLaneSucc = true;\n      } else {\n        crossLaneCount++;\n      }\n    }\n    if (crossLaneCount === 0 || hasSameLaneSucc) {\n      continue;\n    }\n\n    let crossLaneIncoming = 0;\n    let hasSameLanePred = false;\n    for (const e of g.edges) {\n      if (e.dst !== v) {\n        continue;\n      }\n      const laneSrc = topLaneOf(e.src);\n      if (!laneSrc) {\n        continue;\n      }\n      if (laneSrc === laneV) {\n        hasSameLanePred = true;\n      } else {\n        crossLaneIncoming++;\n      }\n    }\n    if (crossLaneIncoming > 0 || !hasSameLanePred) {\n      continue;\n    }\n    const current = rankOf[v] ?? 0;\n    const target = current + crossLaneCount;\n    // Ensure we still respect predecessor constraints\n    let lb = 0;\n    for (const e of g.edges) {\n      if (e.dst === v) {\n        lb = Math.max(lb, (rankOf[e.src] ?? 0) + 1);\n      }\n    }\n    const newRank = Math.max(current, lb, target);\n    if (newRank !== current) {\n      rankOf[v] = newRank;\n    }\n  }\n}\n", "import type { Graph, Layering, NodeId } from './helpers.js';\nimport { incoming, topoSortIfAcyclic, normalizeGraph } from './phase0.helpers.js';\nimport type { LayeringOptions } from './phase2.options.js';\nimport { createTopLaneResolver } from './phase2.options.js';\nimport { optimizeRanksByCrossings } from './phase2.crossOptimization.js';\nimport { adjustCrossLaneSources } from './phase2.crossLaneAdjust.js';\nimport { buildMultitreeLayerOrder } from './phase2.multitree.order.js';\n\n/**\n * Classic longest-path layering with optional compaction and lane awareness.\n */\nexport function assignLayers_LongestPath(gAcyclic: Graph, opts?: LayeringOptions): Layering {\n  const g = normalizeGraph(gAcyclic);\n  const order = topoSortIfAcyclic(g) ?? [...g.nodes].sort();\n  const compact = opts?.compactSingleInput ?? false;\n\n  const topLaneOf = createTopLaneResolver(g);\n\n  let rankOf: Record<NodeId, number> = Object.create(null);\n  for (const v of order) {\n    const incAll = incoming(g, v);\n    const inc = opts?.ignoreCrossLaneEdges\n      ? incAll.filter((e) => {\n          const laneSrc = topLaneOf(e.src);\n          const laneDst = topLaneOf(v);\n          if (!laneSrc || !laneDst) {\n            return true;\n          }\n          return laneSrc === laneDst;\n        })\n      : incAll;\n    if (inc.length === 0) {\n      rankOf[v] = 0;\n    } else if (compact && inc.length === 1) {\n      const u = inc[0].src;\n      // Only compact if predecessor is in a different lane than v\n      const laneU = topLaneOf(u);\n      const laneV = topLaneOf(v);\n      if (laneU !== laneV) {\n        rankOf[v] = rankOf[u] ?? 0;\n      } else {\n        rankOf[v] = (rankOf[u] ?? 0) + 1;\n      }\n    } else {\n      let mx = -Infinity;\n      for (const e of inc) {\n        mx = Math.max(mx, (rankOf[e.src] ?? 0) + 1);\n      }\n      rankOf[v] = mx === -Infinity ? 0 : mx;\n    }\n  }\n\n  // Optional: revisit ranks using a greedy crossing reduction respecting precedence constraints\n  if (opts?.optimizeRanksByCrossings ?? false) {\n    rankOf = optimizeRanksByCrossings(g, rankOf);\n  }\n\n  if (opts?.ignoreCrossLaneEdges) {\n    adjustCrossLaneSources(g, rankOf);\n  }\n\n  const layers = buildMultitreeLayerOrder(g, rankOf, topLaneOf);\n\n  return { layers, rankOf, dummy: new Set<NodeId>() };\n}\n", "import type { Graph, Layering, NodeId } from './helpers.js';\nimport {\n  buildLayersFromRanks,\n  buildPredecessorSuccessorMaps,\n  topoSortIfAcyclic,\n  normalizeGraph,\n} from './phase0.helpers.js';\nimport type { LayeringOptions } from './phase2.options.js';\nimport { createTopLaneResolver } from './phase2.options.js';\nimport { LAYERING } from './config.js';\nimport { assignLayers_LongestPath } from './phase2.longestPath.js';\n\n// cspell:ignore acyclicity preds succs\n\n/**\n * Gravity-based layering algorithm that minimizes edge lengths while maintaining acyclicity.\n */\nexport function assignLayers_Gravity(gAcyclic: Graph, opts?: LayeringOptions): Layering {\n  const g = normalizeGraph(gAcyclic);\n  // Initial ranks from longest path (gives feasible lower bounds)\n  const base = assignLayers_LongestPath(g, {\n    compactSingleInput: opts?.compactSingleInput,\n    ignoreCrossLaneEdges: opts?.ignoreCrossLaneEdges,\n    optimizeRanksByCrossings: opts?.optimizeRanksByCrossings,\n  });\n  const rankOf: Record<NodeId, number> = { ...base.rankOf } as any;\n\n  const topLaneOf = createTopLaneResolver(g);\n\n  const { preds, succs } = buildPredecessorSuccessorMaps(g, (e) => {\n    if (opts?.ignoreCrossLaneEdges) {\n      const laneSrc = topLaneOf(e.src);\n      const laneDst = topLaneOf(e.dst);\n      if (laneSrc && laneDst && laneSrc !== laneDst) {\n        return false;\n      }\n    }\n    return true;\n  });\n\n  const order = topoSortIfAcyclic(g) ?? [...g.nodes];\n  const revOrder = [...order].reverse();\n\n  const clampFeasible = (v: NodeId, desired: number): number => {\n    // Lower bound from predecessors: max(rank[u] + 1)\n    let lb = 0;\n    for (const u of preds.get(v) ?? []) {\n      lb = Math.max(lb, (rankOf[u] ?? 0) + 1);\n    }\n    // Upper bound from successors: min(rank[w] - 1)\n    let ub = Number.POSITIVE_INFINITY;\n    const s = succs.get(v) ?? [];\n    if (s.length > 0) {\n      ub = Math.min(...s.map((w) => (rankOf[w] ?? 0) - 1));\n    }\n    if (!Number.isFinite(ub)) {\n      ub = Math.max(lb, desired);\n    }\n    return Math.min(Math.max(desired, lb), ub);\n  };\n\n  // Iterative relaxation\n  const iters = LAYERING.GRAVITY_ITERATIONS;\n  const relaxOrder = (nodeOrder: NodeId[]): boolean => {\n    let changed = false;\n    for (const v of nodeOrder) {\n      const ps = preds.get(v) ?? [];\n      const ss = succs.get(v) ?? [];\n      if (ps.length === 0 && ss.length === 0) {\n        continue;\n      }\n      const predAvg =\n        ps.length > 0\n          ? ps.reduce((a, u) => a + (rankOf[u] ?? 0) + 1, 0) / ps.length\n          : (rankOf[v] ?? 0);\n      const succAvg =\n        ss.length > 0\n          ? ss.reduce((a, w) => a + (rankOf[w] ?? 0) - 1, 0) / ss.length\n          : (rankOf[v] ?? 0);\n      const desired = Math.round((predAvg + succAvg) / 2);\n      const clamped = clampFeasible(v, desired);\n      if (clamped !== rankOf[v]) {\n        rankOf[v] = clamped;\n        changed = true;\n      }\n    }\n    return changed;\n  };\n\n  for (let it = 0; it < iters; it++) {\n    const forwardChanged = relaxOrder(order);\n    // backward pass helps propagate upper bounds\n    const backwardChanged = relaxOrder(revOrder);\n    if (!forwardChanged && !backwardChanged) {\n      break;\n    }\n  }\n\n  // Final feasibility fix-ups (ensure r(v) >= r(u)+1)\n  for (const v of order) {\n    let lb = 0;\n    for (const u of preds.get(v) ?? []) {\n      lb = Math.max(lb, (rankOf[u] ?? 0) + 1);\n    }\n    if ((rankOf[v] ?? 0) < lb) {\n      rankOf[v] = lb;\n    }\n  }\n  for (const v of revOrder) {\n    const s = succs.get(v) ?? [];\n    if (s.length > 0) {\n      const ub = Math.min(...s.map((w) => (rankOf[w] ?? 0) - 1));\n      if ((rankOf[v] ?? 0) > ub) {\n        rankOf[v] = ub;\n      }\n    }\n  }\n\n  const layers = buildLayersFromRanks(g, order, rankOf);\n\n  return { layers, rankOf, dummy: new Set<NodeId>() };\n}\n", "import type { Graph, Layering, NodeId } from './helpers.js';\nimport {\n  buildInDegreeMap,\n  buildLayersFromRanks,\n  buildSortedSuccessorMap,\n  incoming,\n  normalizeGraph,\n  sortedZeroInDegreeNodes,\n  topoSortIfAcyclic,\n} from './phase0.helpers.js';\nimport type { LayeringOptions } from './phase2.options.js';\nimport { createTopLaneResolver } from './phase2.options.js';\n\n// cspell:ignore indeg preds topo\n\nfunction topoSortByGenerationIfAcyclic(g: Graph): NodeId[] | null {\n  const indeg = buildInDegreeMap(g);\n  const adj = buildSortedSuccessorMap(g);\n  let frontier = sortedZeroInDegreeNodes(indeg);\n  const order: NodeId[] = [];\n\n  while (frontier.length > 0) {\n    const nextFrontier: NodeId[] = [];\n    for (const u of frontier) {\n      order.push(u);\n      for (const v of adj.get(u) ?? []) {\n        indeg.set(v, (indeg.get(v) ?? 0) - 1);\n        if ((indeg.get(v) ?? 0) === 0) {\n          nextFrontier.push(v);\n        }\n      }\n    }\n    frontier = nextFrontier.sort((a, b) => a.localeCompare(b));\n  }\n\n  return order.length === g.nodes.length ? order : null;\n}\n\n// Lane-aware compact layering: one node per (layer, lane); inter-lane edges can stay on same layer\nexport function assignLayers_LaneAwareCompact(gAcyclic: Graph, opts?: LayeringOptions): Layering {\n  const g = normalizeGraph(gAcyclic);\n  const order =\n    opts?.direction === 'LR'\n      ? (topoSortByGenerationIfAcyclic(g) ?? [...g.nodes].sort())\n      : (topoSortIfAcyclic(g) ?? [...g.nodes].sort());\n\n  // Determine a lane id for each node: top-level parent id, or fall back to node id if none\n  const topLaneOf = createTopLaneResolver(g);\n  const laneOf = (id: NodeId): string => topLaneOf(id) ?? id;\n\n  const rankOf: Record<NodeId, number> = Object.create(null);\n  const nextFree = new Map<string, number>();\n\n  // Helper: edge weight w(u,v) = 1 if same lane else 0, when ignoring cross-lane constraints;\n  // otherwise 1 for all edges.\n  const edgeWeight = (u: NodeId, v: NodeId): number => {\n    const ignoreCrossLane = opts?.ignoreCrossLaneEdges ?? true;\n    if (ignoreCrossLane) {\n      return laneOf(u) === laneOf(v) ? 1 : 0;\n    }\n    return 1;\n  };\n\n  for (const v of order) {\n    const node = g.nodeById.get(v) as any;\n    if (node?.isGroup) {\n      continue;\n    } // do not assign ranks/capacity to lane/group containers\n    const preds = incoming(g, v);\n    let base = 0;\n    if (preds.length > 0) {\n      for (const e of preds) {\n        const u = e.src;\n        const ru = rankOf[u] ?? 0;\n        base = Math.max(base, ru + edgeWeight(u, v));\n      }\n    }\n    const lane = laneOf(v);\n    const nf = nextFree.get(lane) ?? 0;\n    const L = Math.max(base, nf);\n    rankOf[v] = L;\n    nextFree.set(lane, L + 1);\n  }\n\n  const layers = buildLayersFromRanks(g, order, rankOf, { skipGroups: true });\n\n  return { layers, rankOf, dummy: new Set<NodeId>() };\n}\n", "import type { Graph, Layering, Node, NodeId, EdgeRef } from './helpers.js';\nimport { normalizeGraph } from './phase0.helpers.js';\n\nexport function makeProperLayering(\n  layering: Layering,\n  gAcyclic: Graph\n): { layering: Layering; graphWithDummies: Graph } {\n  const g = normalizeGraph(gAcyclic);\n  const { rankOf } = layering;\n  const layers = layering.layers.map((l) => [...l]);\n  const dummy = new Set<NodeId>(layering.dummy ? [...layering.dummy] : []);\n\n  // Helper to create a dummy node at layer L\n  let dummySeq = 0;\n  const nodeById = new Map(g.nodeById);\n  const addDummyAt = (L: number): NodeId => {\n    const id: NodeId = `placeholder-${dummySeq++}`;\n    const dn: Node = { id, isGroup: false, isDummy: true, width: 0, height: 0 } as any;\n    nodeById.set(id, dn);\n    dummy.add(id);\n    // Ensure layers[L] exists\n    while (layers.length <= L) {\n      layers.push([]);\n    }\n    layers[L].push(id);\n    (rankOf as any)[id] = L;\n    return id;\n  };\n\n  // Sort edges deterministically to stabilize dummy creation order\n  const edgesSorted = [...g.edges].sort((a, b) =>\n    a.id === b.id\n      ? a.src === b.src\n        ? a.dst.localeCompare(b.dst)\n        : a.src.localeCompare(b.src)\n      : a.id.localeCompare(b.id)\n  );\n\n  const newEdges: EdgeRef[] = [];\n  for (const e of edgesSorted) {\n    const rU = rankOf[e.src] ?? 0;\n    const rV = rankOf[e.dst] ?? 0;\n    if (rV - rU <= 1) {\n      newEdges.push(e);\n      continue;\n    }\n    // Need to insert dummies on intermediate layers rU+1..rV-1\n    let prev = e.src;\n    for (let L = rU + 1, k = 0; L < rV; L++, k++) {\n      const d = addDummyAt(L);\n      // chain prev -> d\n      newEdges.push({ id: `${e.id}#${k}`, src: prev, dst: d, weight: e.weight, ref: e.ref });\n      prev = d;\n    }\n    // last dummy (or src if no dummies) -> dst\n    const lastIndex = rV - rU - 2; // -2 because we added k from 0..(rV-rU-2)\n    newEdges.push({\n      id: `${e.id}#${Math.max(lastIndex + 1, 0)}`,\n      src: prev,\n      dst: e.dst,\n      weight: e.weight,\n      ref: e.ref,\n    });\n  }\n\n  // Build new nodes list (preserve original order, then dummies by creation order)\n  const nodes = [...g.nodes, ...[...dummy].filter((id) => !g.nodes.includes(id))];\n  const graphWithDummies: Graph = { nodes, edges: newEdges, layout: g.layout, nodeById };\n\n  return { layering: { layers, rankOf, dummy }, graphWithDummies };\n}\n", "import type { Graph, Layering, OrderedLayers, NodeId, Edge } from './helpers.js';\nimport { buildLayerIndex, countInversions } from './phase0.helpers.js';\nimport { createTopLaneResolver, resolveTopLaneOrder } from './phase2.options.js';\n\ntype SweepDirection = 'down' | 'up';\n\nfunction median(values: number[]): number {\n  const n = values.length;\n  if (n === 0) {\n    return Number.POSITIVE_INFINITY;\n  }\n  const a = [...values].sort((x, y) => x - y);\n  if (n % 2 === 1) {\n    return a[(n - 1) / 2];\n  }\n  return 0.5 * (a[n / 2 - 1] + a[n / 2]);\n}\n\nfunction barycenter(values: number[]): number {\n  if (values.length === 0) {\n    return Number.POSITIVE_INFINITY;\n  }\n  const s = values.reduce((acc, v) => acc + v, 0);\n  return s / values.length;\n}\n\nfunction neighborPositionsFor(\n  targetNodes: NodeId[],\n  fixedIndex: Map<NodeId, number>,\n  edges: Edge[],\n  direction: SweepDirection\n): Map<NodeId, number[]> {\n  const neighborPositions = new Map<NodeId, number[]>();\n  for (const v of targetNodes) {\n    neighborPositions.set(v, []);\n  }\n  for (const e of edges) {\n    if (direction === 'down') {\n      if (fixedIndex.has(e.src) && neighborPositions.has(e.dst)) {\n        neighborPositions.get(e.dst)!.push(fixedIndex.get(e.src)!);\n      }\n    } else if (fixedIndex.has(e.dst) && neighborPositions.has(e.src)) {\n      neighborPositions.get(e.src)!.push(fixedIndex.get(e.dst)!);\n    }\n  }\n  return neighborPositions;\n}\n\nfunction currentOrderTieBreak(\n  a: NodeId,\n  b: NodeId,\n  currentLayerIndex: Map<NodeId, number>\n): number {\n  const ia = currentLayerIndex.get(a) ?? 0;\n  const ib = currentLayerIndex.get(b) ?? 0;\n  return ia !== ib ? ia - ib : a.localeCompare(b);\n}\n\nfunction countCrossingsBetweenAdjacent(upper: NodeId[], lower: NodeId[], edges: Edge[]): number {\n  // Filter edges between these two layers\n  const upperSet = new Set(upper);\n  const lowerSet = new Set(lower);\n  const upperIndex = buildLayerIndex(upper);\n  const lowerIndex = buildLayerIndex(lower);\n  const pairs: { u: number; v: number }[] = [];\n  for (const e of edges) {\n    if (upperSet.has(e.src) && lowerSet.has(e.dst)) {\n      pairs.push({ u: upperIndex.get(e.src)!, v: lowerIndex.get(e.dst)! });\n    }\n  }\n  // Sort by u, count inversions in v\n  pairs.sort((a, b) => (a.u === b.u ? a.v - b.v : a.u - b.u));\n  const vs = pairs.map((p) => p.v);\n  return countInversions(vs);\n}\n\nexport function totalCrossings(layers: NodeId[][], edges: Edge[]): number {\n  let sum = 0;\n  for (let i = 0; i + 1 < layers.length; i++) {\n    sum += countCrossingsBetweenAdjacent(layers[i], layers[i + 1], edges);\n  }\n  return sum;\n}\n\n/**\n * Sort a subset of nodes by their median score relative to a fixed layer.\n * This is the core sorting logic extracted for reuse per-lane.\n */\nfunction sortByHeuristic(\n  nodes: NodeId[],\n  neighborPositions: Map<NodeId, number[]>,\n  currentLayerIndex: Map<NodeId, number>\n): NodeId[] {\n  return [...nodes].sort((a, b) => {\n    const sa = median(neighborPositions.get(a) ?? []);\n    const sb = median(neighborPositions.get(b) ?? []);\n    if (sa === sb) {\n      return currentOrderTieBreak(a, b, currentLayerIndex);\n    }\n    if (!isFinite(sa)) {\n      return 1;\n    }\n    if (!isFinite(sb)) {\n      return -1;\n    }\n    return sa - sb;\n  });\n}\n\nfunction reorderLayer(\n  fixedLayer: NodeId[],\n  targetLayer: NodeId[],\n  edges: Edge[],\n  direction: SweepDirection,\n  topLaneOf?: (id: NodeId) => string | null,\n  laneOrder?: string[]\n): NodeId[] {\n  const fixedIndex = buildLayerIndex(fixedLayer);\n  const currIndex = buildLayerIndex(targetLayer);\n  const neighborPositions = neighborPositionsFor(targetLayer, fixedIndex, edges, direction);\n\n  // If no lane info, fall back to flat reorder (original behavior)\n  if (!topLaneOf || !laneOrder || laneOrder.length === 0) {\n    return sortByHeuristic(targetLayer, neighborPositions, currIndex);\n  }\n\n  // Partition target layer nodes by lane\n  const byLane = new Map<string | null, NodeId[]>();\n  for (const id of targetLayer) {\n    const lane = topLaneOf(id);\n    const arr = byLane.get(lane) ?? [];\n    arr.push(id);\n    byLane.set(lane, arr);\n  }\n\n  // Reorder nodes within each lane independently\n  const result: NodeId[] = [];\n\n  // First, place lane-grouped nodes in lane order\n  for (const lane of laneOrder) {\n    const nodesInLane = byLane.get(lane);\n    if (!nodesInLane || nodesInLane.length === 0) {\n      continue;\n    }\n    const sorted = sortByHeuristic(nodesInLane, neighborPositions, currIndex);\n    result.push(...sorted);\n  }\n\n  // Then, handle null-lane nodes (long-edge dummies without a parent).\n  // Compute their barycenter and insert them adjacent to the lane whose\n  // center position is closest to their barycenter.\n  const nullNodes = byLane.get(null);\n  if (nullNodes && nullNodes.length > 0) {\n    // Sort null-lane nodes by their barycenter across the full layer\n    const sorted = sortByHeuristic(nullNodes, neighborPositions, currIndex);\n\n    // For each null-lane node, find the best insertion position\n    // based on its connections to nodes already in the result\n    for (const nid of sorted) {\n      // Compute the barycenter position of this node's neighbors in the fixed layer\n      const bc = barycenter(neighborPositions.get(nid) ?? []);\n\n      // Find the best insertion point: scan result and insert where the\n      // node's barycenter fits relative to its neighbors\n      let bestIdx = result.length; // default: append at end\n      if (isFinite(bc)) {\n        // Find insertion point by comparing barycenter against positions of\n        // nodes already placed. Insert before the first node whose fixed-layer\n        // neighbor position is greater than this node's barycenter.\n        for (const [i, rid] of result.entries()) {\n          const rBc = barycenter(neighborPositions.get(rid) ?? []);\n          if (bc < rBc) {\n            bestIdx = i;\n            break;\n          }\n        }\n      }\n      result.splice(bestIdx, 0, nid);\n    }\n  }\n\n  return result;\n}\n\nfunction transposeImprove(\n  upper: NodeId[],\n  current: NodeId[],\n  edges: Edge[],\n  next?: NodeId[],\n  topLaneOf?: (id: NodeId) => string | null\n): NodeId[] {\n  const best = [...current];\n  const upperSet = new Set(upper);\n  const layerSet = new Set(current);\n  const nextSet = next ? new Set(next) : null;\n\n  const edgesIn = edges.filter((e) => upperSet.has(e.src) && layerSet.has(e.dst));\n  const edgesOut = nextSet\n    ? edges.filter((e) => layerSet.has(e.src) && nextSet.has(e.dst))\n    : undefined;\n\n  const crossingScore = (order: NodeId[]): number => {\n    let score = countCrossingsBetweenAdjacent(upper, order, edgesIn);\n    if (edgesOut && next) {\n      score += countCrossingsBetweenAdjacent(order, next, edgesOut);\n    }\n    return score;\n  };\n\n  // Precompute lane membership for same-lane check\n  const laneOf = topLaneOf ? new Map<NodeId, string | null>() : null;\n  if (topLaneOf && laneOf) {\n    for (const id of current) {\n      laneOf.set(id, topLaneOf(id));\n    }\n  }\n\n  let improved = true;\n  let bestScore = crossingScore(best);\n  while (improved) {\n    improved = false;\n    for (let i = 0; i + 1 < best.length; i++) {\n      // Only swap nodes in the same lane (or both null-lane)\n      if (laneOf) {\n        const laneA = laneOf.get(best[i]);\n        const laneB = laneOf.get(best[i + 1]);\n        if (laneA !== laneB) {\n          continue; // never swap across lane boundaries\n        }\n      }\n\n      const prev = bestScore;\n      [best[i], best[i + 1]] = [best[i + 1], best[i]];\n      const nextScore = crossingScore(best);\n      if (nextScore < prev) {\n        bestScore = nextScore;\n        improved = true;\n      } else {\n        [best[i], best[i + 1]] = [best[i + 1], best[i]];\n      }\n    }\n  }\n  return best;\n}\n\n// Sugiyama phase 3: lane-aware median sweeps plus adjacent transpose improvements.\nexport interface OrderOptions {\n  laneOrder?: string[];\n}\n\nexport function orderLayers(\n  layering: Layering,\n  gWithDummies: Graph,\n  opts?: OrderOptions\n): OrderedLayers {\n  // Start with deterministic initial order per layer (preserve given order)\n  const layers = layering.layers.map((l) => [...l]);\n  const edges = gWithDummies.edges;\n\n  // Compute lane order for lane-aware crossing minimization (Siebenhaller Lemma 4.4)\n  const topLaneOf = createTopLaneResolver(gWithDummies);\n  const laneOrder = resolveTopLaneOrder(gWithDummies, opts?.laneOrder);\n\n  // Perform top-down / bottom-up sweeps\n  for (let s = 0; s < 3; s++) {\n    // Top-down: reorder layer i based on neighbors in layer i-1\n    for (let i = 1; i < layers.length; i++) {\n      layers[i] = reorderLayer(layers[i - 1], layers[i], edges, 'down', topLaneOf, laneOrder);\n      layers[i] = transposeImprove(layers[i - 1], layers[i], edges, layers[i + 1], topLaneOf);\n    }\n    // Bottom-up: reorder layer i based on neighbors in layer i+1\n    for (let i = layers.length - 2; i >= 0; i--) {\n      layers[i] = reorderLayer(layers[i + 1], layers[i], edges, 'up', topLaneOf, laneOrder);\n      layers[i] = transposeImprove(layers[i + 1], layers[i], edges, layers[i - 1], topLaneOf);\n    }\n  }\n\n  return { layers };\n}\n", "import type { Graph, OrderedLayers, Coordinates, NodeId, EdgeRef } from './helpers.js';\nimport { COORDINATES } from './config.js';\nimport { createTopLaneResolver, resolveTopLaneOrder } from './phase2.options.js';\n\nexport interface CoordOptions {\n  layerGap?: number; // vertical distance between layers\n  nodeGap?: number; // horizontal gap between siblings inside a lane\n  laneGap?: number; // horizontal gap between lanes (clusters)\n  direction?: 'TB' | 'LR' | 'BT' | 'RL'; // layout direction for proper spacing\n  laneOrder?: string[];\n}\n\nexport function assignCoordinates(\n  ordered: OrderedLayers,\n  gWithDummies: Graph,\n  opts?: CoordOptions\n): Coordinates {\n  const layerGap = opts?.layerGap ?? COORDINATES.DEFAULT_LAYER_GAP;\n  const nodeGap = opts?.nodeGap ?? COORDINATES.DEFAULT_NODE_GAP;\n  const laneGap = opts?.laneGap ?? nodeGap * 2;\n  const direction = opts?.direction ?? 'TB';\n  const isHorizontal = direction === 'LR' || direction === 'RL';\n\n  const layers = ordered.layers;\n\n  const x: Record<NodeId, number> = Object.create(null);\n  const y: Record<NodeId, number> = Object.create(null);\n\n  const getNode = (id: NodeId) => gWithDummies.nodeById.get(id) as any;\n  const getWidth = (id: NodeId) => getNode(id)?.width ?? 0;\n  const getHeight = (id: NodeId) => getNode(id)?.height ?? 0;\n  const topLaneOf = createTopLaneResolver(gWithDummies);\n  const laneOrderGlobal = resolveTopLaneOrder(gWithDummies, opts?.laneOrder);\n\n  const layerHeights: number[] = layers.map((layer) =>\n    layer.reduce((m, v) => Math.max(m, getHeight(v)), 0)\n  );\n\n  // LR/RL transforms turn width into horizontal span, so widen layer gaps up front.\n  const extraLayerGaps: number[] = [];\n  if (isHorizontal) {\n    for (let i = 0; i + 1 < layers.length; i++) {\n      const thisLayerMaxWidth = layers[i].reduce((m, v) => Math.max(m, getWidth(v)), 0);\n      const nextLayerMaxWidth = layers[i + 1].reduce((m, v) => Math.max(m, getWidth(v)), 0);\n      const thisLayerMaxHeight = layerHeights[i];\n      const nextLayerMaxHeight = layerHeights[i + 1];\n\n      const normalSpacing = thisLayerMaxHeight / 2 + nextLayerMaxHeight / 2;\n      const requiredSpacing = (thisLayerMaxWidth + nextLayerMaxWidth) / 2;\n      const extraNeeded = Math.max(0, requiredSpacing - normalSpacing - layerGap);\n      extraLayerGaps.push(extraNeeded);\n    }\n  }\n\n  const lanesUsedSet = new Set<string | null>();\n  for (const layer of layers) {\n    for (const id of layer) {\n      lanesUsedSet.add(topLaneOf(id));\n    }\n  }\n  const hasNullLane = lanesUsedSet.has(null);\n  const lanesUsed = laneOrderGlobal.filter((L) => lanesUsedSet.has(L));\n  const laneOrderColumns: (string | null)[] = [...(hasNullLane ? [null] : []), ...lanesUsed];\n\n  const laneWidth: Record<string, number> = Object.create(null);\n  for (const L of lanesUsed) {\n    laneWidth[L] = 0;\n  }\n  if (hasNullLane) {\n    (laneWidth as any).null = 0 as any;\n  }\n  for (const layer of layers) {\n    const perLane: Record<string, string[]> = Object.create(null);\n    const nullIds: string[] = [];\n    for (const id of layer) {\n      const L = topLaneOf(id);\n      if (L === null) {\n        nullIds.push(id);\n      } else {\n        (perLane[L] ||= []).push(id);\n      }\n    }\n    for (const [L, ids] of Object.entries(perLane)) {\n      const total =\n        ids.reduce((s, id) => s + getWidth(id), 0) + nodeGap * Math.max(0, ids.length - 1);\n      laneWidth[L] = Math.max(laneWidth[L] ?? 0, total);\n    }\n    if (hasNullLane && nullIds.length) {\n      const totalNull =\n        nullIds.reduce((s, id) => s + getWidth(id), 0) + nodeGap * Math.max(0, nullIds.length - 1);\n      (laneWidth as any).null = Math.max((laneWidth as any).null ?? 0, totalNull) as any;\n    }\n  }\n\n  const centerX = new Map<string | null, number>();\n  {\n    const widths = laneOrderColumns.map(\n      (L) => (L === null ? ((laneWidth as any).null as number) : laneWidth[L]) ?? 0\n    );\n    const totalW =\n      widths.reduce((a, b) => a + b, 0) + laneGap * Math.max(0, laneOrderColumns.length - 1);\n    let cursor = -totalW / 2;\n    for (let i = 0; i < laneOrderColumns.length; i++) {\n      const L = laneOrderColumns[i];\n      const w = widths[i] ?? 0;\n      const cx = cursor + w / 2;\n      centerX.set(L, cx);\n      cursor += w;\n      if (i < laneOrderColumns.length - 1) {\n        cursor += laneGap;\n      }\n    }\n  }\n\n  let yOffset = 0;\n  for (const [li, layer] of layers.entries()) {\n    const layerH = layerHeights[li] ?? 0;\n\n    const byLane = new Map<string | null, NodeId[]>();\n    for (const id of layer) {\n      const laneId = topLaneOf(id);\n      const arr = byLane.get(laneId) ?? [];\n      arr.push(id);\n      byLane.set(laneId, arr);\n    }\n\n    for (const L of laneOrderColumns) {\n      const nodesInLane = byLane.get(L) ?? [];\n      if (nodesInLane.length === 0) {\n        continue;\n      }\n      const cx = centerX.get(L)!;\n      if (nodesInLane.length === 1) {\n        const id = nodesInLane[0];\n        x[id] = cx;\n        y[id] = yOffset + layerH / 2;\n      } else {\n        // Preserve phase 3 order while spreading nodes around the lane center.\n        const widths = nodesInLane.map((id) => getWidth(id));\n        const total = widths.reduce((a, b) => a + b, 0) + nodeGap * (nodesInLane.length - 1);\n        let start = cx - total / 2;\n        for (const [i, id] of nodesInLane.entries()) {\n          const w = widths[i];\n          x[id] = start + w / 2;\n          y[id] = yOffset + layerH / 2;\n          start += w + nodeGap;\n        }\n      }\n    }\n\n    const extraGap = extraLayerGaps[li] ?? 0;\n    yOffset += layerH + layerGap + extraGap;\n  }\n\n  // Align dummy chains for each original edge: set dummy x to midpoint between src and dst.\n  const byRef = new Map<string, EdgeRef[]>();\n  for (const e of gWithDummies.edges) {\n    const rid = e.ref.id;\n    if (!byRef.has(rid)) {\n      byRef.set(rid, []);\n    }\n    byRef.get(rid)!.push(e);\n  }\n  for (const [, chainEdges] of byRef) {\n    if (chainEdges.length === 0) {\n      continue;\n    }\n    const ref = chainEdges[0].ref;\n    const src = ref.start!;\n    const dst = ref.end!;\n    if (src == null || dst == null) {\n      continue;\n    }\n    const midX = Math.round(((x[src] ?? 0) + (x[dst] ?? 0)) / 2);\n    const involved = new Set<NodeId>();\n    for (const e of chainEdges) {\n      involved.add(e.src);\n      involved.add(e.dst);\n    }\n    for (const vid of involved) {\n      if (vid === src || vid === dst) {\n        continue;\n      }\n      const node = gWithDummies.nodeById.get(vid) as any;\n      if (node?.isDummy) {\n        x[vid] = midX;\n      }\n    }\n  }\n\n  return { x, y };\n}\n", "import type { Graph } from './helpers.js';\nimport { buildTopLaneOrder, createTopLaneResolver } from './phase2.options.js';\n\nexport const AUTOMATIC_LANE_ORDERING_RESTARTS = 8;\n\nexport interface WeightedLaneEdge {\n  a: string;\n  b: string;\n  weight: number;\n}\n\ninterface CandidateOrder {\n  order: string[];\n  cost: number;\n  sourceDistance: number;\n}\n\nfunction hashString(input: string): number {\n  let hash = 2166136261;\n  for (let i = 0; i < input.length; i++) {\n    hash ^= input.charCodeAt(i);\n    hash = Math.imul(hash, 16777619);\n  }\n  return hash >>> 0;\n}\n\nfunction mulberry32(seed: number): () => number {\n  let state = seed >>> 0;\n  return () => {\n    state += 0x6d2b79f5;\n    let t = state;\n    t = Math.imul(t ^ (t >>> 15), t | 1);\n    t ^= t + Math.imul(t ^ (t >>> 7), t | 61);\n    return ((t ^ (t >>> 14)) >>> 0) / 4294967296;\n  };\n}\n\nfunction deterministicShuffle(order: string[], seed: number): string[] {\n  const shuffled = [...order];\n  const random = mulberry32(seed);\n  for (let i = shuffled.length - 1; i > 0; i--) {\n    const j = Math.floor(random() * (i + 1));\n    [shuffled[i], shuffled[j]] = [shuffled[j], shuffled[i]];\n  }\n  return shuffled;\n}\n\nfunction sourceDistance(order: string[], sourceIndex: Map<string, number>): number {\n  let distance = 0;\n  for (const [index, laneId] of order.entries()) {\n    distance += Math.abs(index - (sourceIndex.get(laneId) ?? index));\n  }\n  return distance;\n}\n\nexport function laneArrangementCost(order: string[], weights: WeightedLaneEdge[]): number {\n  const position = new Map<string, number>();\n  for (const [index, laneId] of order.entries()) {\n    position.set(laneId, index);\n  }\n\n  let cost = 0;\n  for (const { a, b, weight } of weights) {\n    const ai = position.get(a);\n    const bi = position.get(b);\n    if (ai == null || bi == null) {\n      continue;\n    }\n    cost += weight * Math.abs(ai - bi);\n  }\n  return cost;\n}\n\nexport function buildWeightedLaneEdges(g: Graph): WeightedLaneEdge[] {\n  const sourceOrder = buildTopLaneOrder(g);\n  if (sourceOrder.length < 2) {\n    return [];\n  }\n\n  const sourceIndex = new Map(sourceOrder.map((laneId, index) => [laneId, index]));\n  const topLaneOf = createTopLaneResolver(g);\n  const weights = new Map<string, WeightedLaneEdge>();\n\n  for (const edge of g.layout.edges ?? []) {\n    if ((edge as { isLayoutOnly?: boolean }).isLayoutOnly) {\n      continue;\n    }\n    const src = typeof edge.start === 'string' ? edge.start : undefined;\n    const dst = typeof edge.end === 'string' ? edge.end : undefined;\n    if (!src || !dst || !g.nodeById.has(src) || !g.nodeById.has(dst)) {\n      continue;\n    }\n\n    const laneA = topLaneOf(src);\n    const laneB = topLaneOf(dst);\n    if (!laneA || !laneB || laneA === laneB) {\n      continue;\n    }\n\n    const ia = sourceIndex.get(laneA);\n    const ib = sourceIndex.get(laneB);\n    if (ia == null || ib == null) {\n      continue;\n    }\n\n    const [a, b] = ia <= ib ? [laneA, laneB] : [laneB, laneA];\n    const key = `${a}\\0${b}`;\n    const existing = weights.get(key);\n    if (existing) {\n      existing.weight++;\n    } else {\n      weights.set(key, { a, b, weight: 1 });\n    }\n  }\n\n  return [...weights.values()];\n}\n\nfunction greedySwitch(\n  startOrder: string[],\n  weights: WeightedLaneEdge[],\n  sourceIndex: Map<string, number>\n): CandidateOrder {\n  const order = [...startOrder];\n  let cost = laneArrangementCost(order, weights);\n  let changed = true;\n  let sweeps = 0;\n  const maxSweeps = Math.max(1, order.length);\n\n  while (changed && sweeps < maxSweeps) {\n    changed = false;\n    sweeps++;\n    for (let i = 0; i + 1 < order.length; i++) {\n      [order[i], order[i + 1]] = [order[i + 1], order[i]];\n      const nextCost = laneArrangementCost(order, weights);\n      if (nextCost < cost) {\n        cost = nextCost;\n        changed = true;\n      } else {\n        [order[i], order[i + 1]] = [order[i + 1], order[i]];\n      }\n    }\n  }\n\n  return {\n    order,\n    cost,\n    sourceDistance: sourceDistance(order, sourceIndex),\n  };\n}\n\nfunction isBetterCandidate(candidate: CandidateOrder, best: CandidateOrder): boolean {\n  if (candidate.cost !== best.cost) {\n    return candidate.cost < best.cost;\n  }\n  return candidate.sourceDistance < best.sourceDistance;\n}\n\nfunction seedForRestart(\n  sourceOrder: string[],\n  weights: WeightedLaneEdge[],\n  restartIndex: number\n): number {\n  const weightSignature = [...weights]\n    .sort((a, b) => (a.a === b.a ? a.b.localeCompare(b.b) : a.a.localeCompare(b.a)))\n    .map(({ a, b, weight }) => `${a}:${b}:${weight}`)\n    .join('|');\n  return hashString(`${sourceOrder.join('|')}#${weightSignature}#${restartIndex}`);\n}\n\nexport function optimizeTopLaneOrder(g: Graph, opts: { restarts?: number } = {}): string[] {\n  const sourceOrder = buildTopLaneOrder(g);\n  if (sourceOrder.length < 2) {\n    return sourceOrder;\n  }\n\n  const weights = buildWeightedLaneEdges(g);\n  if (weights.length === 0) {\n    return sourceOrder;\n  }\n\n  const sourceIndex = new Map(sourceOrder.map((laneId, index) => [laneId, index]));\n  let best = greedySwitch(sourceOrder, weights, sourceIndex);\n  const restarts = Math.max(0, opts.restarts ?? AUTOMATIC_LANE_ORDERING_RESTARTS);\n\n  for (let i = 0; i < restarts; i++) {\n    const seed = seedForRestart(sourceOrder, weights, i);\n    const start = deterministicShuffle(sourceOrder, seed);\n    const candidate = greedySwitch(start, weights, sourceIndex);\n    if (isBetterCandidate(candidate, best)) {\n      best = candidate;\n    }\n  }\n\n  return best.order;\n}\n", "import type { Graph, Layering, OrderedLayers, Coordinates, Edge } from './helpers.js';\nimport { normalizeGraph } from './phase0.helpers.js';\nimport { removeCycles_DFS } from './phase1.cycles.js';\n\nimport { assignLayers_Gravity } from './phase2.gravity.js';\nimport { assignLayers_LaneAwareCompact } from './phase2.laneAwareCompact.js';\nimport { makeProperLayering } from './phase2.dummies.js';\nimport { orderLayers } from './phase3.ordering.js';\nimport { assignCoordinates } from './phase4.coordinates.js';\nimport { LAYERING } from './config.js';\nimport { AUTOMATIC_LANE_ORDERING_RESTARTS, optimizeTopLaneOrder } from './laneOrdering.js';\n\nexport interface LayoutOptions {\n  // Layering\n  compactSingleInput?: boolean; // default true for compact swimlanes\n  ignoreCrossLaneEdges?: boolean;\n  optimizeRanksByCrossings?: boolean;\n  automaticLaneOrdering?: boolean;\n  // Coordinates\n  layerGap?: number;\n  nodeGap?: number;\n  // Direction (for proper spacing calculation)\n  direction?: 'TB' | 'LR' | 'BT' | 'RL';\n}\n\nexport interface LayoutResult {\n  acyclic: Graph;\n  reversed: Edge[];\n  layering: Layering;\n  ordered: OrderedLayers;\n  coordinates: Coordinates;\n}\n\nexport function sugiyamaLayout(g: Graph, opts?: LayoutOptions): LayoutResult {\n  const ignoreCrossLaneEdges = opts?.ignoreCrossLaneEdges ?? true;\n  const optimizeRanksByCrossings = opts?.optimizeRanksByCrossings ?? true;\n  const g0 = normalizeGraph(g);\n  const laneOrder = opts?.automaticLaneOrdering\n    ? optimizeTopLaneOrder(g0, { restarts: AUTOMATIC_LANE_ORDERING_RESTARTS })\n    : undefined;\n\n  // Phase 1: cycle removal\n  const cycleRes = removeCycles_DFS(g0);\n  const gAcyclic = cycleRes.acyclic;\n\n  // Phase 2: layering\n  const layering = ignoreCrossLaneEdges\n    ? assignLayers_LaneAwareCompact(gAcyclic, {\n        compactSingleInput: opts?.compactSingleInput ?? LAYERING.DEFAULT_COMPACT_SINGLE_INPUT,\n        ignoreCrossLaneEdges: true,\n        direction: opts?.direction,\n      })\n    : assignLayers_Gravity(gAcyclic, {\n        compactSingleInput: opts?.compactSingleInput ?? LAYERING.DEFAULT_COMPACT_SINGLE_INPUT,\n        ignoreCrossLaneEdges: false,\n        optimizeRanksByCrossings,\n      });\n  const { layering: properLayering, graphWithDummies } = makeProperLayering(layering, gAcyclic);\n  // Phase 3: ordering\n  const ordered = orderLayers(properLayering, graphWithDummies, { laneOrder });\n\n  // Phase 4: coordinates\n  const coordinates = assignCoordinates(ordered, graphWithDummies, {\n    layerGap: opts?.layerGap,\n    nodeGap: opts?.nodeGap,\n    direction: opts?.direction,\n    laneOrder,\n  });\n\n  return {\n    acyclic: gAcyclic,\n    reversed: cycleRes.reversed,\n    layering: properLayering,\n    ordered,\n    coordinates,\n  };\n}\n", "// cspell:ignore raykov Raykov Wybrow Marriott Stuckey\n\n/**\n * Orthogonal edge router for the swimlanes layout.\n *\n * Each edge is routed as an axis-aligned (Manhattan) polyline between ports on\n * the node borders, with port distribution and nudging to reduce overlaps and\n * crossings. The approach follows the orthogonal-connector-routing literature \u2014\n * notably Wybrow, Marriott & Stuckey, \"Orthogonal Connector Routing\" (the\n * libavoid family). \"Raykov\" in the comments and tests is the informal name this\n * implementation was developed under, not an external dependency.\n */\n\nimport type { LayoutData, Node as MermaidNode } from '../../../types.js';\nimport { PRECISION } from '../config.js';\n\nconst EPS = PRECISION.EPSILON;\n\nconst NODE_PADDING = 8;\nconst HORIZONTAL_PIPE_MARGIN = 15;\nconst VERTICAL_PIPE_MARGIN = 15;\nconst ROUTING_MARGIN = 25;\nconst ANCHOR_OFFSET = 20;\nconst TRACK_SPACING = 10;\n\n// ---------------------------------------------------------------------------\n// Type Definitions for Orthogonal Router\n// ---------------------------------------------------------------------------\n\ninterface Point {\n  x: number;\n  y: number;\n}\n\ntype OrthogonalSide = 'top' | 'bottom' | 'left' | 'right';\n\ninterface LaneInfo {\n  id: string;\n}\n\ntype Orientation = 'horizontal' | 'vertical';\n\ninterface Pipe {\n  id: string;\n  orientation: Orientation;\n  coord: number; // y for horizontal, x for vertical\n  spanMin: number;\n  spanMax: number;\n  tracks: Track[];\n}\n\ninterface Track {\n  index: number;\n  coord: number; // actual x/y of this track\n  segments: SegmentRef[]; // references to segments belonging to this track\n}\n\ninterface SegmentRef {\n  edgeIndex: number;\n  segmentIndex: number;\n  from: number; // min coord along axis\n  to: number; // max coord along axis\n}\n\ninterface RoutedSegment {\n  edgeIndex: number;\n  segmentIndex: number;\n  orientation: Orientation;\n  pipe: Pipe;\n  trackIndex: number;\n  from: number;\n  to: number;\n}\n\ninterface RoutedLine {\n  orient: Orientation;\n  coord: number;\n  from: number;\n  to: number;\n}\n\nfunction chooseOrthogonalSide(\n  node: MermaidNode,\n  target: Point,\n  fallback: OrthogonalSide\n): OrthogonalSide {\n  const cx = node.x ?? 0;\n  const cy = node.y ?? 0;\n  const dx = target.x - cx;\n  const dy = target.y - cy;\n  const absDx = Math.abs(dx);\n  const absDy = Math.abs(dy);\n\n  if (absDx < EPS && absDy < EPS) {\n    return fallback;\n  }\n\n  const verticalBias = 3.0;\n  if (absDy > EPS && absDy * verticalBias >= absDx) {\n    return dy > 0 ? 'bottom' : 'top';\n  }\n  if (absDx > EPS) {\n    return dx > 0 ? 'right' : 'left';\n  }\n  return fallback;\n}\n\nfunction sharedLineEndpointCoord(line: RoutedLine, nextLine: RoutedLine): number {\n  return Math.abs(line.to - nextLine.from) < EPS || Math.abs(line.to - nextLine.to) < EPS\n    ? line.to\n    : line.from;\n}\n\nfunction pointOnLine(line: RoutedLine, along: number): Point {\n  return line.orient === 'vertical' ? { x: line.coord, y: along } : { x: along, y: line.coord };\n}\n\n// ---------------------------------------------------------------------------\n// Orthogonal Router Implementation\n// ---------------------------------------------------------------------------\n\nexport function routeEdgesOrthogonal(data: LayoutData, direction?: string): LayoutData {\n  const nodes = data.nodes ?? [];\n  const originalEdges = data.edges ?? [];\n\n  // Build a local \"routing view\" of the edge list:\n  // - Skip `isLayoutOnly` virtual edges \u2014 they exist only for Sugiyama layering\n  //   (the A\u2192label, label\u2192B pair lets Sugiyama rank through labels) and must\n  //   never be routed or rendered.\n  // - All other edges (including labelled originals) pass through unchanged.\n  //   Strategy 1 (late-insertion / diss.pdf \u00A7118): labelled edges are routed\n  //   as single unbroken A\u2192B polylines with labels invisible to routing.\n  //   Labels are then anchored post-routing onto a middle segment of the\n  //   resulting polyline via postProcessing.ts's `anchorLabelsToPolyline` pass.\n  //   No shadow-split, no L-bend bridge, no per-edge label obstacle exclusion.\n  interface InternalRoutingEdge {\n    id: string;\n    start?: string;\n    end?: string;\n    points?: Point[];\n    __originalEdge?: (typeof originalEdges)[number];\n    [key: string]: unknown;\n  }\n  const edges: InternalRoutingEdge[] = [];\n  for (const oe of originalEdges) {\n    if ((oe as { isLayoutOnly?: boolean }).isLayoutOnly) {\n      continue;\n    }\n    edges.push({\n      ...(oe as unknown as Record<string, unknown>),\n      __originalEdge: oe,\n    } as InternalRoutingEdge);\n  }\n\n  const nodeById = new Map<string, MermaidNode>();\n  const laneByNodeId = new Map<string, LaneInfo>();\n  const pipes: Pipe[] = [];\n  const isLR = direction === 'LR';\n\n  // 1. Initialize Helpers & Lookups\n  for (const n of nodes) {\n    nodeById.set(n.id, n);\n  }\n\n  // Identify Lanes (Top-level groups)\n  const topLevelGroups = nodes.filter((n) => n.isGroup && !n.parentId);\n  for (const group of topLevelGroups) {\n    const lane: LaneInfo = { id: group.id };\n\n    // Assign this lane to all descendants\n    const assignLane = (n: MermaidNode) => {\n      laneByNodeId.set(n.id, lane);\n      nodes.filter((child) => child.parentId === n.id).forEach(assignLane);\n    };\n    assignLane(group);\n  }\n  // Also build obstacle rects for non-group nodes, tracking which node each belongs to.\n  //\n  // Strategy 1 (late-insertion / diss.pdf \u00A7118): edge-label nodes are NOT\n  // obstacles during routing. Labels are placed post-routing onto an\n  // existing polyline segment via `anchorLabelsToPolyline` in postProcessing.ts.\n  // Foreign edges never route around labels, so there is no \"foreign edge\n  // routed around old label position, label later moved\" inconsistency.\n  interface ObstacleRect {\n    nodeId: string;\n    minX: number;\n    minY: number;\n    maxX: number;\n    maxY: number;\n    // For LR direction, we need to know the \"visual\" extent after transform\n    // TB x becomes LR y, so the visual Y extent should use height, not width\n    visualXHalfExtent: number;\n  }\n  const obstacles: ObstacleRect[] = nodes\n    .filter((n) => !n.isGroup && !(n as { isEdgeLabel?: boolean }).isEdgeLabel)\n    .map((n) => {\n      const w = n.width ?? 10;\n      const h = n.height ?? 10;\n      const x = n.x ?? 0;\n      const y = n.y ?? 0;\n      // Inflate by configured padding\n      const padding = NODE_PADDING;\n\n      return {\n        nodeId: n.id,\n        minX: x - w / 2 - padding,\n        maxX: x + w / 2 + padding,\n        minY: y - h / 2 - padding,\n        maxY: y + h / 2 + padding,\n        // For LR: TB x becomes LR y, so visual Y extent should be based on height\n        visualXHalfExtent: isLR ? h / 2 + padding : w / 2 + padding,\n      };\n    });\n\n  // Helper to find or create pipe\n  const getOrAddPipe = (\n    orientation: Orientation,\n    coord: number,\n    spanMin: number,\n    spanMax: number\n  ): Pipe => {\n    let pipe = pipes.find((p) => p.orientation === orientation && Math.abs(p.coord - coord) < 1);\n    if (!pipe) {\n      pipe = {\n        id: `pipe-${orientation}-${coord.toFixed(0)}`,\n        orientation,\n        coord,\n        spanMin,\n        spanMax,\n        tracks: [],\n      };\n      pipes.push(pipe);\n    }\n    // Extend span\n    pipe.spanMin = Math.min(pipe.spanMin, spanMin);\n    pipe.spanMax = Math.max(pipe.spanMax, spanMax);\n    return pipe;\n  };\n\n  // Direct port-for-side helper. Used by Step 6.2's sibling side-split\n  // reassignment so the main routing loop can honor a side that does\n  // not match `getOrthogonalPort`'s natural choice.\n  const portForSide = (node: MermaidNode, side: OrthogonalSide): Point => {\n    const w = node.width ?? 10;\n    const h = node.height ?? 10;\n    const cx = node.x ?? 0;\n    const cy = node.y ?? 0;\n    switch (side) {\n      case 'top':\n        return { x: cx, y: cy - h / 2 };\n      case 'bottom':\n        return { x: cx, y: cy + h / 2 };\n      case 'left':\n        return { x: cx - w / 2, y: cy };\n      case 'right':\n        return { x: cx + w / 2, y: cy };\n    }\n  };\n\n  /**\n   * Get orthogonal port point - returns the CENTER of a cardinal side (left/right/top/bottom).\n   * This ensures the edge starts/ends with a purely horizontal or vertical segment.\n   *\n   * @param node - The node to get the port from\n   * @param target - The target point (used to determine which side)\n   * @param isSource - Whether this is the source node (affects side selection for same-row/column cases)\n   */\n  const getOrthogonalPort = (node: MermaidNode, target: Point, isSource: boolean): Point =>\n    portForSide(node, chooseOrthogonalSide(node, target, isSource ? 'bottom' : 'top'));\n\n  // Global list of all routed segments for crossing reduction\n  const allRoutedSegments: RoutedSegment[] = [];\n  const edgeSegmentIndices: number[][] = []; // edgeIndex -> [routedSegmentIndex, ...]\n  // Centered straight-line fast-path edges should keep their pipe coord.\n  const straightIntraLaneEdges = new Set<number>();\n  const CROSSING_PENALTY = 1000;\n\n  const crossingPenalty = (edgeIdx: number, from: Point, to: Point): number => {\n    if (allRoutedSegments.length === 0) {\n      return 0;\n    }\n    const isHorizontal = Math.abs(from.y - to.y) < EPS;\n    const isVertical = Math.abs(from.x - to.x) < EPS;\n    if (!isHorizontal && !isVertical) {\n      return 0;\n    }\n\n    let penalties = 0;\n    if (isHorizontal) {\n      const y = from.y;\n      const minX = Math.min(from.x, to.x) - EPS;\n      const maxX = Math.max(from.x, to.x) + EPS;\n      if (maxX <= minX) {\n        return 0;\n      }\n      for (const seg of allRoutedSegments) {\n        if (seg.edgeIndex === edgeIdx || seg.orientation !== 'vertical') {\n          continue;\n        }\n        if (seg.pipe.coord < minX || seg.pipe.coord > maxX) {\n          continue;\n        }\n        if (seg.from - EPS <= y && seg.to + EPS >= y) {\n          penalties += CROSSING_PENALTY;\n        }\n      }\n    } else if (isVertical) {\n      const x = from.x;\n      const minY = Math.min(from.y, to.y) - EPS;\n      const maxY = Math.max(from.y, to.y) + EPS;\n      if (maxY <= minY) {\n        return 0;\n      }\n      for (const seg of allRoutedSegments) {\n        if (seg.edgeIndex === edgeIdx || seg.orientation !== 'horizontal') {\n          continue;\n        }\n        if (seg.pipe.coord < minY || seg.pipe.coord > maxY) {\n          continue;\n        }\n        if (seg.from - EPS <= x && seg.to + EPS >= x) {\n          penalties += CROSSING_PENALTY;\n        }\n      }\n    }\n    return penalties;\n  };\n\n  // -----------------------------------------------------------------------\n  // Phase 1: Initial Routing\n  // -----------------------------------------------------------------------\n  const routingOrder = edges\n    .map((edge, idx) => {\n      if (!edge.start || !edge.end) {\n        return { idx, crossLane: 0, dx: 0, dy: 0 };\n      }\n      const srcNode = nodeById.get(edge.start);\n      const dstNode = nodeById.get(edge.end);\n      const srcLane = laneByNodeId.get(edge.start);\n      const dstLane = laneByNodeId.get(edge.end);\n      const crossLane = srcLane && dstLane && srcLane.id !== dstLane.id ? 1 : 0;\n      const dx = srcNode && dstNode ? Math.abs((dstNode.x ?? 0) - (srcNode.x ?? 0)) : 0;\n      const dy = srcNode && dstNode ? Math.abs((dstNode.y ?? 0) - (srcNode.y ?? 0)) : 0;\n      return { idx, crossLane, dx, dy };\n    })\n    .sort((a, b) => {\n      // Route cross-lane edges FIRST so they claim their preferred straight\n      // path before flexible intra-lane detours can block them. Intra-lane\n      // edges then adapt via the backward-looking CROSSING_PENALTY \u2014 a\n      // cheap U-detour around an obstacle is strictly better than a\n      // sequential-A* pathology where the cross-lane edge gets forced\n      // through a crossing it can no longer avoid.\n      // Paper backing: Walk on the Wild Side (LIPIcs.GD.2025.35) \u2014 bend-\n      // minimization dominates crossing-minimization when crossings are\n      // orthogonal; Wybrow et al. Orthogonal Connector Routing \u2014 crossing\n      // penalty is only effective against already-routed edges.\n      if (a.crossLane !== b.crossLane) {\n        return b.crossLane - a.crossLane;\n      }\n      // Shorter edges first \u2014 they need less room to maneuver\n      const aDist = a.dx + a.dy;\n      const bDist = b.dx + b.dy;\n      if (Math.abs(aDist - bDist) > 1) {\n        return aDist - bDist;\n      }\n      return a.idx - b.idx;\n    })\n    .map((entry) => entry.idx);\n\n  // Helper to check if a segment is blocked by any obstacle.\n  // excludeStart and excludeEnd are node IDs to exclude from obstacle checking.\n  const isSegmentBlocked = (p1: Point, p2: Point, excludeStart?: string, excludeEnd?: string) => {\n    const segMinX = Math.min(p1.x, p2.x);\n    const segMaxX = Math.max(p1.x, p2.x);\n    const segMinY = Math.min(p1.y, p2.y);\n    const segMaxY = Math.max(p1.y, p2.y);\n\n    const blockingObs = obstacles.find((obs) => {\n      if (excludeStart && obs.nodeId === excludeStart) {\n        return false;\n      }\n      if (excludeEnd && obs.nodeId === excludeEnd) {\n        return false;\n      }\n      if (Math.abs(p1.x - p2.x) > EPS) {\n        // Horizontal segment\n        return obs.minY < p1.y && obs.maxY > p1.y && obs.maxX > segMinX && obs.minX < segMaxX;\n      } else {\n        // Vertical segment\n        return obs.minX < p1.x && obs.maxX > p1.x && obs.maxY > segMinY && obs.minY < segMaxY;\n      }\n    });\n\n    return !!blockingObs;\n  };\n\n  // ---- Step 6: Port pre-assignment ----\n  // When multiple edges connect to the same side of a node, distribute their\n  // ports across that side and order them by source/target coordinate to\n  // prevent crossings at the node boundary.\n  //\n  // Key: \"nodeId:side:role\" where side is 'top'|'bottom'|'left'|'right'\n  //   and role is 'src' (edge leaves this node) or 'dst' (edge arrives here).\n  // Value: list of { edgeIdx, oppositeCoord } sorted by oppositeCoord.\n  const portGroups = new Map<string, { edgeIdx: number; oppositeCoord: number }[]>();\n  const incidentEdgeTotals = new Map<string, number>();\n  for (const edge of edges) {\n    if (!edge.start || !edge.end || edge.start === edge.end) {\n      continue;\n    }\n    incidentEdgeTotals.set(edge.start, (incidentEdgeTotals.get(edge.start) ?? 0) + 1);\n    incidentEdgeTotals.set(edge.end, (incidentEdgeTotals.get(edge.end) ?? 0) + 1);\n  }\n\n  // First pass: determine which side each edge connects to on each node\n  const determineSide = (node: MermaidNode, target: Point): OrthogonalSide =>\n    chooseOrthogonalSide(node, target, 'bottom');\n\n  // ----- Step 6.1: compute initial sides for every edge ---------------\n  //\n  // We run determineSide up-front for both endpoints of every edge so the\n  // sibling side-splitting pass (6.2) can see the full picture before the\n  // port-group build (6.3) locks each edge into a side.\n  type SideT = 'top' | 'bottom' | 'left' | 'right';\n  interface EdgeSideInfo {\n    edgeIdx: number;\n    srcId: string;\n    dstId: string;\n    srcSide: SideT;\n    dstSide: SideT;\n    absDx: number;\n    absDy: number;\n    dxSign: number;\n    dySign: number;\n  }\n  const sideInfoByIdx = new Map<number, EdgeSideInfo>();\n  for (const [i, e] of edges.entries()) {\n    if (!e.start || !e.end || e.start === e.end) {\n      continue;\n    }\n    if (e.points && e.points.length > 0) {\n      continue;\n    }\n    const src = nodeById.get(e.start);\n    const dst = nodeById.get(e.end);\n    if (!src || !dst) {\n      continue;\n    }\n    const dx = (dst.x ?? 0) - (src.x ?? 0);\n    const dy = (dst.y ?? 0) - (src.y ?? 0);\n    sideInfoByIdx.set(i, {\n      edgeIdx: i,\n      srcId: e.start,\n      dstId: e.end,\n      srcSide: determineSide(src, { x: dst.x ?? 0, y: dst.y ?? 0 }),\n      dstSide: determineSide(dst, { x: src.x ?? 0, y: src.y ?? 0 }),\n      absDx: Math.abs(dx),\n      absDy: Math.abs(dy),\n      dxSign: Math.sign(dx),\n      dySign: Math.sign(dy),\n    });\n  }\n\n  // ----- Step 6.2: sibling side-splitting (diss.pdf \u00A76.1.2.2) ---------\n  //\n  // Paper-backed \u03B4_s load-balancing rule: when two or more edges leave a\n  // source node from the same side, reassign the ones with the *weaker*\n  // preference-strength to their secondary side, naturally distributing\n  // them across multiple sides of the node. Preference-strength combines\n  // source and destination side-load (the paper sums \u03B4_s over both\n  // endpoints). With edge-id tiebreak for determinism when 3+ edges tie.\n  //\n  // Sequencing note (critical, per Algorithm Expert review): this pass\n  // MUST run before the port-group build (6.3), anchor computation\n  // (Step 7), and any later port-sensitive post-processing. Changing a side\n  // later would corrupt E_{v,s} membership without updating downstream sort keys.\n  //\n  // \"Preference strength\" = the dy/dx ratio (for vertically-preferred\n  // edges) or dx/dy ratio (for horizontally-preferred) \u2014 higher ratio\n  // means more dominant in the current side's axis.\n  const preferenceStrength = (info: EdgeSideInfo): number => {\n    if (info.srcSide === 'top' || info.srcSide === 'bottom') {\n      return info.absDx === 0 ? Infinity : info.absDy / info.absDx;\n    }\n    return info.absDy === 0 ? Infinity : info.absDx / info.absDy;\n  };\n  const secondarySide = (info: EdgeSideInfo): SideT => {\n    if (info.srcSide === 'top' || info.srcSide === 'bottom') {\n      return info.dxSign >= 0 ? 'right' : 'left';\n    }\n    return info.dySign >= 0 ? 'bottom' : 'top';\n  };\n\n  // Group by (src, srcSide) so we can detect 2+ edges sharing a side.\n  const sourceSideGroups = new Map<string, EdgeSideInfo[]>();\n  for (const info of sideInfoByIdx.values()) {\n    const key = `${info.srcId}:${info.srcSide}`;\n    if (!sourceSideGroups.has(key)) {\n      sourceSideGroups.set(key, []);\n    }\n    sourceSideGroups.get(key)!.push(info);\n  }\n\n  // Running side-load counters for every (nodeId, side) to implement\n  // \u03B4_s. Bumped every time an edge is committed to a side as its src or\n  // dst. The paper's rule compares (\u03B4_src + \u03B4_dst) across candidate\n  // routes; we use this counter to tiebreak between primary and\n  // secondary sides when the strength-sort leaves two candidates equally\n  // attractive.\n  const sideLoad = new Map<string, number>();\n  const loadKey = (nodeId: string, side: SideT): string => `${nodeId}:${side}`;\n  for (const info of sideInfoByIdx.values()) {\n    sideLoad.set(\n      loadKey(info.srcId, info.srcSide),\n      (sideLoad.get(loadKey(info.srcId, info.srcSide)) ?? 0) + 1\n    );\n    sideLoad.set(\n      loadKey(info.dstId, info.dstSide),\n      (sideLoad.get(loadKey(info.dstId, info.dstSide)) ?? 0) + 1\n    );\n  }\n\n  for (const group of sourceSideGroups.values()) {\n    if (group.length < 2) {\n      continue;\n    }\n    // Sort by preference strength DESCENDING \u2014 strongest first.\n    // The strongest sibling keeps its preferred side; each subsequent\n    // (weaker) sibling is considered for reassignment to its secondary\n    // side. Tiebreak on edgeIdx for deterministic 3+-sibling cases.\n    //\n    // Paper-backed rationale (diss.pdf \u00A76.1.2.2): when multiple edges\n    // contend for the same side, preserving the strongest preference\n    // minimizes the aggregate cost of deviation. The \u03B4_s counter\n    // breaks ties and prevents ping-ponging when secondary sides are\n    // already loaded.\n    group.sort((a, b) => {\n      const sa = preferenceStrength(a);\n      const sb = preferenceStrength(b);\n      if (Math.abs(sa - sb) > 1e-9) {\n        return sb - sa;\n      }\n      return a.edgeIdx - b.edgeIdx;\n    });\n    // Each sibling except the first (strongest) is considered for\n    // reassignment to its secondary side, bumping \u03B4_s counters as we go.\n    for (let g = 1; g < group.length; g++) {\n      const info = group[g];\n      const secondary = secondarySide(info);\n      const primaryLoad = sideLoad.get(loadKey(info.srcId, info.srcSide)) ?? 0;\n      const secondaryLoad = sideLoad.get(loadKey(info.srcId, secondary)) ?? 0;\n      // Only move to the secondary side if it's strictly less loaded\n      // than the primary (avoids ping-ponging when both sides are\n      // equally crowded \u2014 the paper's \u03B4_s rule picks whichever sum is\n      // smaller, and equal sums default to the original assignment).\n      if (secondaryLoad >= primaryLoad) {\n        continue;\n      }\n      // Update counters and the side assignment.\n      sideLoad.set(loadKey(info.srcId, info.srcSide), primaryLoad - 1);\n      sideLoad.set(loadKey(info.srcId, secondary), secondaryLoad + 1);\n      info.srcSide = secondary;\n    }\n  }\n\n  // ----- Step 6.2b: bimodal in/out de-collision for diamond nodes -----\n  //\n  // Paper backing: the BIMODAL drawing constraint (Eiglsperger, \"Orthogonal\n  // Graph Drawing with Constraints\" \u00A73.1): a vertex's incoming and outgoing\n  // edges should occupy separate, non-intersecting intervals of its circular\n  // edge order \u2014 in practice, distinct sides. Step 6.2 only load-balances\n  // same-role siblings (multiple out-edges from one side), so an out-edge can\n  // still land on the very side an in-edge already uses. On a diamond each\n  // side collapses to a single pin at the vertex (6.3 gives diamonds only a\n  // 0.3\u00B7side port span), so an in-edge and an out-edge sharing a side resolve\n  // to the SAME pin \u2014 the detached-stub \"shared projected port\" defect\n  // (validateLayout: edge-shared-projected-port). Move the out-edge to its\n  // free secondary side to restore bimodality. Scoped to diamonds so\n  // rectangles \u2014 whose long sides hold multiple distinct pins \u2014 are untouched.\n  const isDiamondNode = (node: MermaidNode | undefined): boolean => {\n    const shape = (node as { shape?: string } | undefined)?.shape;\n    return shape === 'question' || shape === 'diamond';\n  };\n  const inSidesByNode = new Map<string, Set<SideT>>();\n  for (const info of sideInfoByIdx.values()) {\n    if (!inSidesByNode.has(info.dstId)) {\n      inSidesByNode.set(info.dstId, new Set());\n    }\n    inSidesByNode.get(info.dstId)!.add(info.dstSide);\n  }\n  for (const info of sideInfoByIdx.values()) {\n    if (!isDiamondNode(nodeById.get(info.srcId))) {\n      continue;\n    }\n    const inSides = inSidesByNode.get(info.srcId);\n    if (!inSides?.has(info.srcSide)) {\n      continue; // no in-edge shares this out-edge's side \u2192 no bimodal clash\n    }\n    const secondary = secondarySide(info);\n    // Only move to a side that no in-edge uses and that carries no committed\n    // load \u2014 keeps the change surgical and never creates a new collision.\n    if (inSides.has(secondary) || (sideLoad.get(loadKey(info.srcId, secondary)) ?? 0) > 0) {\n      continue;\n    }\n    const primaryLoad = sideLoad.get(loadKey(info.srcId, info.srcSide)) ?? 0;\n    sideLoad.set(loadKey(info.srcId, info.srcSide), Math.max(0, primaryLoad - 1));\n    sideLoad.set(loadKey(info.srcId, secondary), 1);\n    info.srcSide = secondary;\n  }\n\n  // ----- Step 6.3: port-group build (uses possibly-reassigned sides) --\n  for (const info of sideInfoByIdx.values()) {\n    const { edgeIdx: i, srcId, dstId, srcSide, dstSide } = info;\n    const src = nodeById.get(srcId)!;\n    const dst = nodeById.get(dstId)!;\n\n    const srcKey = `${srcId}:${srcSide}:src`;\n    const dstCoord = srcSide === 'top' || srcSide === 'bottom' ? (dst.x ?? 0) : (dst.y ?? 0);\n    if (!portGroups.has(srcKey)) {\n      portGroups.set(srcKey, []);\n    }\n    portGroups.get(srcKey)!.push({ edgeIdx: i, oppositeCoord: dstCoord });\n\n    const dstKey = `${dstId}:${dstSide}:dst`;\n    const srcCoord = dstSide === 'top' || dstSide === 'bottom' ? (src.x ?? 0) : (src.y ?? 0);\n    if (!portGroups.has(dstKey)) {\n      portGroups.set(dstKey, []);\n    }\n    portGroups.get(dstKey)!.push({ edgeIdx: i, oppositeCoord: srcCoord });\n  }\n\n  // Now compute port offsets for each group with 2+ edges\n  // Key: \"edgeIdx:src\" or \"edgeIdx:dst\" \u2192 port offset from center\n  const portOffsets = new Map<string, number>();\n  const MIN_PORT_SPACING = 8; // minimum pixels between adjacent ports\n\n  for (const [key, group] of portGroups) {\n    if (group.length < 2) {\n      continue;\n    }\n    // Sort by opposite coordinate (ascending)\n    group.sort((a, b) => a.oppositeCoord - b.oppositeCoord);\n\n    // Parse node ID and side from key\n    const parts = key.split(':');\n    const nodeId = parts.slice(0, -2).join(':'); // handle IDs with colons\n    const side = parts[parts.length - 2];\n    const role = parts[parts.length - 1]; // 'src' or 'dst'\n    const node = nodeById.get(nodeId);\n    if (!node) {\n      continue;\n    }\n\n    // Determine available span along the side.\n    // For diamond/rhombus shapes, the effective port area on pointy sides is\n    // much smaller than the bounding box \u2014 use a fraction of the side length.\n    const isVerticalSide = side === 'left' || side === 'right';\n    const sideLength = isVerticalSide ? (node.height ?? 10) : (node.width ?? 10);\n    const shape = (node as { shape?: string }).shape;\n    const isDiamond = shape === 'question' || shape === 'diamond';\n    const effectiveLength = isDiamond ? sideLength * 0.3 : sideLength;\n    const MAX_PORT_SPACING = 20; // cap spacing to avoid large detours\n\n    // Distribute ports evenly, clamped by MIN and MAX\n    const spacing = Math.min(\n      MAX_PORT_SPACING,\n      Math.max(MIN_PORT_SPACING, effectiveLength / (group.length + 1))\n    );\n    const totalSpan = spacing * (group.length - 1);\n    const startOffset = -totalSpan / 2;\n\n    for (const [j, element] of group.entries()) {\n      const offset = startOffset + j * spacing;\n      const offsetKey = `${element.edgeIdx}:${role}`;\n      portOffsets.set(offsetKey, offset);\n    }\n  }\n\n  const edgeHasLabelNode = (edgeIdx: number): boolean =>\n    Boolean((edges[edgeIdx] as { labelNodeId?: string } | undefined)?.labelNodeId);\n\n  const faceHasLabelNode = (nodeId: string | undefined, side: SideT): boolean => {\n    if (!nodeId) {\n      return false;\n    }\n    return (\n      (portGroups.get(`${nodeId}:${side}:src`) ?? []).some(({ edgeIdx }) =>\n        edgeHasLabelNode(edgeIdx)\n      ) ||\n      (portGroups.get(`${nodeId}:${side}:dst`) ?? []).some(({ edgeIdx }) =>\n        edgeHasLabelNode(edgeIdx)\n      )\n    );\n  };\n\n  // Helper to apply port offset to a base center port\n  const applyPortOffset = (\n    basePort: Point,\n    side: 'top' | 'bottom' | 'left' | 'right',\n    offset: number\n  ): Point => {\n    if (side === 'top' || side === 'bottom') {\n      // Offset along X axis\n      return { x: basePort.x + offset, y: basePort.y };\n    } else {\n      // Offset along Y axis\n      return { x: basePort.x, y: basePort.y + offset };\n    }\n  };\n\n  const portsForEdge = (edgeIndex: number, src: MermaidNode, dst: MermaidNode) => {\n    const sideInfo = sideInfoByIdx.get(edgeIndex);\n    const srcTarget = { x: dst.x ?? 0, y: dst.y ?? 0 };\n    const dstTarget = { x: src.x ?? 0, y: src.y ?? 0 };\n    const srcSide = sideInfo?.srcSide ?? determineSide(src, srcTarget);\n    const dstSide = sideInfo?.dstSide ?? determineSide(dst, dstTarget);\n    let pSrcPort = sideInfo\n      ? portForSide(src, sideInfo.srcSide)\n      : getOrthogonalPort(src, srcTarget, true);\n    let pDstPort = sideInfo\n      ? portForSide(dst, sideInfo.dstSide)\n      : getOrthogonalPort(dst, dstTarget, false);\n\n    const srcOffset = portOffsets.get(`${edgeIndex}:src`);\n    const dstOffset = portOffsets.get(`${edgeIndex}:dst`);\n    if (srcOffset !== undefined) {\n      pSrcPort = applyPortOffset(pSrcPort, srcSide, srcOffset);\n    }\n    if (dstOffset !== undefined) {\n      pDstPort = applyPortOffset(pDstPort, dstSide, dstOffset);\n    }\n    return { pSrcPort, pDstPort, srcSide, dstSide };\n  };\n\n  for (const i of routingOrder) {\n    const e = edges[i];\n    edgeSegmentIndices[i] = [];\n\n    if (!e.start || !e.end) {\n      continue;\n    }\n    if (e.points && e.points.length > 0) {\n      continue;\n    }\n    // Skip self-loops\n    if (e.start === e.end) {\n      continue;\n    }\n\n    const src = nodeById.get(e.start);\n    const dst = nodeById.get(e.end);\n    if (!src || !dst) {\n      continue;\n    }\n\n    // 2. Compute Ports. Use the side assignment from Step 6.2 (sibling\n    // side-split) so that a reassigned edge exits from its secondary\n    // cardinal side instead of `getOrthogonalPort`'s natural choice.\n    const {\n      pSrcPort,\n      pDstPort,\n      srcSide: srcPortSide,\n      dstSide: dstPortSide,\n    } = portsForEdge(i, src, dst);\n\n    // 3. Compute Anchors\n    const pSrcAnchor: Point = { ...pSrcPort };\n    const pDstAnchor: Point = { ...pDstPort };\n\n    // Adjust anchors based on port direction\n    // For orthogonal routing, anchors should extend in the same direction as the port\n    // (i.e., if port is on bottom, anchor should be below the port)\n\n    // Determine if ports are vertical (top/bottom) or horizontal (left/right).\n    // Prefer the side from Step 6.2 so that a reassigned sibling gets its\n    // anchor extended on the correct axis.\n    const srcPortIsVertical = srcPortSide === 'top' || srcPortSide === 'bottom';\n    const dstPortIsVertical = dstPortSide === 'top' || dstPortSide === 'bottom';\n\n    // Source Anchor - extend from port in the appropriate direction\n    if (srcPortIsVertical) {\n      // Port is on top or bottom - extend vertically\n      const isBottom = pSrcPort.y > (src.y ?? 0);\n      pSrcAnchor.y = isBottom ? pSrcPort.y + ANCHOR_OFFSET : pSrcPort.y - ANCHOR_OFFSET;\n    } else {\n      // Port is on left or right - extend horizontally\n      const isRight = pSrcPort.x > (src.x ?? 0);\n      pSrcAnchor.x = isRight ? pSrcPort.x + ANCHOR_OFFSET : pSrcPort.x - ANCHOR_OFFSET;\n    }\n\n    // Target Anchor - extend from port in the appropriate direction\n    if (dstPortIsVertical) {\n      // Port is on top or bottom - extend vertically\n      const isBottom = pDstPort.y > (dst.y ?? 0);\n      pDstAnchor.y = isBottom ? pDstPort.y + ANCHOR_OFFSET : pDstPort.y - ANCHOR_OFFSET;\n    } else {\n      // Port is on left or right - extend horizontally\n      const isRight = pDstPort.x > (dst.x ?? 0);\n      pDstAnchor.x = isRight ? pDstPort.x + ANCHOR_OFFSET : pDstPort.x - ANCHOR_OFFSET;\n    }\n\n    // Helper to check if a point is inside any obstacle (excluding src/dst nodes)\n    const isPointInObstacle = (\n      pt: Point,\n      excludeNodeIds: string[]\n    ): { inside: boolean; obstacle?: (typeof obstacles)[0] } => {\n      for (const obs of obstacles) {\n        if (excludeNodeIds.includes(obs.nodeId)) {\n          continue;\n        }\n        if (pt.x > obs.minX && pt.x < obs.maxX && pt.y > obs.minY && pt.y < obs.maxY) {\n          return { inside: true, obstacle: obs };\n        }\n      }\n      return { inside: false };\n    };\n\n    const obstacleDetour = (\n      port: Point,\n      node: MermaidNode,\n      opposite: MermaidNode,\n      obs: (typeof obstacles)[0],\n      portIsVertical: boolean\n    ): { x: number; y: number; leavesPositiveSide: boolean } => {\n      if (portIsVertical) {\n        const leavesPositiveSide = port.y > (node.y ?? 0);\n        const goRight = (opposite.x ?? 0) >= port.x;\n        return {\n          x: goRight ? obs.maxX + HORIZONTAL_PIPE_MARGIN : obs.minX - HORIZONTAL_PIPE_MARGIN,\n          y: leavesPositiveSide ? obs.maxY + VERTICAL_PIPE_MARGIN : obs.minY - VERTICAL_PIPE_MARGIN,\n          leavesPositiveSide,\n        };\n      }\n\n      const leavesPositiveSide = port.x > (node.x ?? 0);\n      const goDown = (opposite.y ?? 0) >= port.y;\n      return {\n        x: leavesPositiveSide\n          ? obs.maxX + HORIZONTAL_PIPE_MARGIN\n          : obs.minX - HORIZONTAL_PIPE_MARGIN,\n        y: goDown ? obs.maxY + VERTICAL_PIPE_MARGIN : obs.minY - VERTICAL_PIPE_MARGIN,\n        leavesPositiveSide,\n      };\n    };\n\n    // Push source anchor out if it's inside an obstacle\n    // This happens when the node below the source is too close\n    // When pushed, we also compute waypoints to route around the obstacle\n    //\n    // CRITICAL: The waypoints must be structured so that the FIRST point after the port\n    // is in the orthogonal direction (same x for vertical port, same y for horizontal port).\n    // This is because insertEdge calls tail.intersect(firstInnerPoint), and if firstInnerPoint\n    // is not aligned orthogonally, it will produce a diagonal intersection instead of the\n    // orthogonal port we computed.\n    let srcHandleWaypoints: Point[] = [];\n    const endpointIds = [e.start, e.end];\n    const srcCheck = isPointInObstacle(pSrcAnchor, endpointIds);\n    if (srcCheck.inside && srcCheck.obstacle) {\n      const obs = srcCheck.obstacle;\n      if (srcPortIsVertical) {\n        // Vertical port (top/bottom) - need to route around the obstacle horizontally\n        const detour = obstacleDetour(pSrcPort, src, dst, obs, true);\n\n        pSrcAnchor.x = detour.x;\n        pSrcAnchor.y = detour.y;\n\n        // Strategy: go sideways FIRST to clear the obstacle's x-range, then go down.\n        // But we need the FIRST point after port to be orthogonal for insertEdge.\n        //\n        // Compute a small orthogonal step in the gap between the source node and obstacle:\n        // - For bottom port going down: step to just before the obstacle's top\n        // - This creates an orthogonal segment that insertEdge will preserve\n        const gapY = detour.leavesPositiveSide\n          ? Math.min(obs.minY - 2, pSrcPort.y + ANCHOR_OFFSET) // Just before obstacle\n          : Math.max(obs.maxY + 2, pSrcPort.y - ANCHOR_OFFSET); // Just after obstacle\n\n        // Waypoints:\n        // 1. Small orthogonal step (same X, slightly toward obstacle) - for insertEdge\n        // 2. Horizontal detour to clear obstacle's X range\n        // 3. Vertical to clearance Y (past obstacle)\n        srcHandleWaypoints = [\n          { x: pSrcPort.x, y: gapY }, // Orthogonal step in the gap\n          { x: detour.x, y: gapY }, // Horizontal detour\n          { x: detour.x, y: detour.y }, // Down past obstacle\n        ];\n      } else {\n        // Horizontal port (left/right) - route around vertically\n        const detour = obstacleDetour(pSrcPort, src, dst, obs, false);\n\n        const gapX = detour.leavesPositiveSide\n          ? Math.min(obs.minX - 2, pSrcPort.x + ANCHOR_OFFSET)\n          : Math.max(obs.maxX + 2, pSrcPort.x - ANCHOR_OFFSET);\n\n        pSrcAnchor.x = detour.x;\n        pSrcAnchor.y = detour.y;\n\n        srcHandleWaypoints = [\n          { x: gapX, y: pSrcPort.y }, // Orthogonal step in the gap\n          { x: gapX, y: detour.y }, // Vertical detour\n          { x: detour.x, y: detour.y }, // Horizontal past obstacle\n        ];\n      }\n    }\n\n    // Push destination anchor out if it's inside an obstacle\n    // Same logic as source: ensure orthogonal waypoints for proper intersection\n    let dstHandleWaypoints: Point[] = [];\n    const dstCheck = isPointInObstacle(pDstAnchor, endpointIds);\n    if (dstCheck.inside && dstCheck.obstacle) {\n      const obs = dstCheck.obstacle;\n      if (dstPortIsVertical) {\n        const detour = obstacleDetour(pDstPort, dst, src, obs, true);\n\n        pDstAnchor.x = detour.x;\n        pDstAnchor.y = detour.y;\n\n        // Waypoints: from anchor -> sideways -> orthogonally to port\n        // The LAST waypoint before port MUST have same X as port for orthogonal intersection\n        dstHandleWaypoints = [\n          { x: detour.x, y: detour.y }, // From anchor position\n          { x: pDstPort.x, y: detour.y }, // Go sideways to port's X\n          // Then orthogonally to port\n        ];\n      } else {\n        const detour = obstacleDetour(pDstPort, dst, src, obs, false);\n\n        pDstAnchor.x = detour.x;\n        pDstAnchor.y = detour.y;\n\n        dstHandleWaypoints = [\n          { x: detour.x, y: detour.y }, // From anchor position\n          { x: detour.x, y: pDstPort.y }, // Go vertically to port's Y\n        ];\n      }\n    }\n\n    // ----- Centered straight-line fast path (Kandinsky \u00A72, diss.pdf 0fb2d84f) --\n    //\n    // When the two port sides face each other and the anchor-to-anchor\n    // segment is already axis-aligned (both at the same x or the same y),\n    // emit the straight port-to-port polyline directly if no foreign\n    // obstacle blocks it. This realizes the Kandinsky centered-straight-\n    // line invariant: *straight-line edges are centered at the\n    // corresponding vertex side* \u2014 the ports already sit at the face\n    // centers returned by `portForSide`, so there is nothing to compute.\n    //\n    // This generalized path captures the same optimisation for any edge\n    // whose face-center ports are aligned, regardless of label semantics.\n    //\n    // Conditions:\n    //   1. No obstacle-avoidance waypoints were injected (pSrcAnchor /\n    //      pDstAnchor stayed at their face-center extensions).\n    //   2. The anchors share one coordinate axis within the pipe margin.\n    //   3. The edge is not part of a distributed port group (port offsets\n    //      would shift the face-center port and break centering).\n    //   4. Either the endpoint faces are uncontested, or every contested\n    //      endpoint is a degree-2 chain node. The latter is allowed so a\n    //      genuinely collinear connector keeps the Kandinsky centered-\n    //      straight invariant; the rendered terminal-lane splitter can then\n    //      move the other incident lane instead of introducing a bend here.\n    //      Higher-degree nodes still fall back to normal track assignment,\n    //      because preserving one center port there can force short near-node\n    //      bands on another incident edge.\n    //   5. The port-to-port direct segment is obstacle-free.\n    //\n    // When these hold, set e.points directly and skip the rest of the\n    // routing loop body. Phase 2/3 (track assignment, point emission)\n    // both skip edges with empty `edgeSegmentIndices[i]`, so the\n    // straight polyline survives unchanged to the final output.\n    //\n    // For aligned-column back-edges (e.g. L_J_E_0 in 7-car-sales-constr\n    // where J and E share TB x=392), the transform maps the LR-straight\n    // horizontal to a TB-straight vertical, and the final endpoint clip\n    // pass in postProcessing.ts snaps each endpoint to the facing side\n    // center (J.top-center, E.bottom-center) \u2014 resolving the\n    // `edge-corner-connection` pathology where the prior 5-point U-detour\n    // landed endpoints 0.67\u20133u from a node corner.\n    if (srcHandleWaypoints.length === 0 && dstHandleWaypoints.length === 0) {\n      const hpMargin = HORIZONTAL_PIPE_MARGIN;\n      const anchorsSameX = Math.abs(pSrcAnchor.x - pDstAnchor.x) < hpMargin;\n      const anchorsSameY = Math.abs(pSrcAnchor.y - pDstAnchor.y) < hpMargin;\n      const hasPortOffset =\n        portOffsets.get(`${i}:src`) !== undefined || portOffsets.get(`${i}:dst`) !== undefined;\n      // Count total edges (any role) attaching at each facing side.\n      // >1 means the face is contested \u2014 skip the fast path so the\n      // normal track-assignment logic can spread attach points.\n      const srcFaceTotal =\n        (portGroups.get(`${e.start ?? ''}:${srcPortSide}:src`)?.length ?? 0) +\n        (portGroups.get(`${e.start ?? ''}:${srcPortSide}:dst`)?.length ?? 0);\n      const dstFaceTotal =\n        (portGroups.get(`${e.end ?? ''}:${dstPortSide}:src`)?.length ?? 0) +\n        (portGroups.get(`${e.end ?? ''}:${dstPortSide}:dst`)?.length ?? 0);\n      const faceContested = srcFaceTotal > 1 || dstFaceTotal > 1;\n      const srcIncidentTotal = incidentEdgeTotals.get(e.start ?? '') ?? 0;\n      const dstIncidentTotal = incidentEdgeTotals.get(e.end ?? '') ?? 0;\n      const contestedFaceHasLabel =\n        (srcFaceTotal > 1 && faceHasLabelNode(e.start, srcPortSide)) ||\n        (dstFaceTotal > 1 && faceHasLabelNode(e.end, dstPortSide));\n      const srcContestAllowsCenteredStraight = srcFaceTotal <= 1 || srcIncidentTotal <= 2;\n      const dstContestAllowsCenteredStraight = dstFaceTotal <= 1 || dstIncidentTotal <= 2;\n      const canPreserveSimpleContestedStraight =\n        faceContested &&\n        !contestedFaceHasLabel &&\n        srcContestAllowsCenteredStraight &&\n        dstContestAllowsCenteredStraight;\n      if (\n        (anchorsSameX || anchorsSameY) &&\n        !hasPortOffset &&\n        (!faceContested || canPreserveSimpleContestedStraight)\n      ) {\n        const directBlocked = isSegmentBlocked(pSrcPort, pDstPort, e.start, e.end);\n        if (!directBlocked) {\n          // Emit the canonical `port \u2192 anchor \u2192 anchor \u2192 port` 4-point\n          // shape. Because all four points are collinear along the\n          // shared axis, postProcessing.ts's `simplifyPolyline` collapses it\n          // to a clean 2-point straight line downstream, and the\n          // endpoint-clip pass snaps the port endpoints onto the\n          // facing node side centers. Keeping the 4-point form here\n          // preserves the long-standing raykov contract that a\n          // straight-line edge's `e.points` includes the anchor\n          // extensions, which several unit tests pin.\n          e.points = [{ ...pSrcPort }, { ...pSrcAnchor }, { ...pDstAnchor }, { ...pDstPort }];\n          straightIntraLaneEdges.add(i);\n          // Register the fast-path's full port\u2192port line as a routed\n          // segment so later A* searches can see it via crossingPenalty.\n          // Without this, iter 8's fast path is invisible to the\n          // CROSSING_PENALTY check in the A* loop and later intra-lane\n          // detours (e.g. L_D_E_0 detouring around a shared-column node)\n          // pick crossings they should be able to avoid. We intentionally\n          // do NOT add this index to edgeSegmentIndices[i] \u2014 phase 2/3\n          // track-assignment must keep skipping fast-path edges so their\n          // centered straight shape is preserved.\n          const fastPathOrientation: Orientation = anchorsSameY ? 'horizontal' : 'vertical';\n          const fastPathCoord = anchorsSameY ? pSrcPort.y : pSrcPort.x;\n          const fastPathFrom = anchorsSameY\n            ? Math.min(pSrcPort.x, pDstPort.x)\n            : Math.min(pSrcPort.y, pDstPort.y);\n          const fastPathTo = anchorsSameY\n            ? Math.max(pSrcPort.x, pDstPort.x)\n            : Math.max(pSrcPort.y, pDstPort.y);\n          const fastPathPipe: Pipe = {\n            id: `fast-path-${fastPathOrientation}-${fastPathCoord.toFixed(0)}-${i}`,\n            orientation: fastPathOrientation,\n            coord: fastPathCoord,\n            spanMin: fastPathFrom,\n            spanMax: fastPathTo,\n            tracks: [],\n          };\n          allRoutedSegments.push({\n            edgeIndex: i,\n            segmentIndex: 0,\n            orientation: fastPathOrientation,\n            pipe: fastPathPipe,\n            trackIndex: 0,\n            from: fastPathFrom,\n            to: fastPathTo,\n          });\n          continue;\n        }\n      }\n    }\n\n    // Snap anchors to nearest pipe (create lazily).\n    const srcPipe = getOrAddPipe('vertical', pSrcAnchor.x, pSrcAnchor.y, pSrcAnchor.y);\n    pSrcAnchor.x = srcPipe.coord;\n    const dstPipe = getOrAddPipe('vertical', pDstAnchor.x, pDstAnchor.y, pDstAnchor.y);\n    pDstAnchor.x = dstPipe.coord;\n\n    // 4. Build Visibility Graph & Pathfinding\n    // Bounding box - start with anchor points\n    let bbMinX = Math.min(pSrcAnchor.x, pDstAnchor.x) - 50;\n    let bbMaxX = Math.max(pSrcAnchor.x, pDstAnchor.x) + 50;\n    let bbMinY = Math.min(pSrcAnchor.y, pDstAnchor.y) - 50;\n    let bbMaxY = Math.max(pSrcAnchor.y, pDstAnchor.y) + 50;\n\n    // Expand bounding box to include detour routes around any obstacles that block the direct path\n    for (const obs of obstacles) {\n      // Check if obstacle is in the way (overlaps with the direct path corridor)\n      const pathMinX = Math.min(pSrcAnchor.x, pDstAnchor.x);\n      const pathMaxX = Math.max(pSrcAnchor.x, pDstAnchor.x);\n      const pathMinY = Math.min(pSrcAnchor.y, pDstAnchor.y);\n      const pathMaxY = Math.max(pSrcAnchor.y, pDstAnchor.y);\n\n      const obsBlocksPath =\n        obs.minX < pathMaxX && obs.maxX > pathMinX && obs.minY < pathMaxY && obs.maxY > pathMinY;\n\n      if (obsBlocksPath) {\n        // Expand bbox to include space for routing around this obstacle\n        bbMinX = Math.min(bbMinX, obs.minX - ROUTING_MARGIN);\n        bbMaxX = Math.max(bbMaxX, obs.maxX + ROUTING_MARGIN);\n        bbMinY = Math.min(bbMinY, obs.minY - ROUTING_MARGIN);\n        bbMaxY = Math.max(bbMaxY, obs.maxY + ROUTING_MARGIN);\n      }\n    }\n\n    // Add pipe grid lines around obstacles\n    for (const obs of obstacles) {\n      // Check if obstacle is relevant to this edge's bounding box\n      if (obs.maxX < bbMinX || obs.minX > bbMaxX || obs.maxY < bbMinY || obs.minY > bbMaxY) {\n        continue;\n      }\n      // Add horizontal pipes around obstacle - ONLY at safe zone positions (with margins)\n      // Do NOT create pipes at exact boundaries - that allows edges to hug nodes\n      const hMargin = HORIZONTAL_PIPE_MARGIN;\n      getOrAddPipe('horizontal', obs.minY - hMargin, bbMinX, bbMaxX); // Above obstacle (safe zone)\n      getOrAddPipe('horizontal', obs.maxY + hMargin, bbMinX, bbMaxX); // Below obstacle (safe zone)\n\n      // Add vertical pipes around obstacle - ONLY at safe zone positions (with margins)\n      const vMargin = VERTICAL_PIPE_MARGIN;\n      getOrAddPipe('vertical', obs.minX - vMargin, bbMinY, bbMaxY); // Left of obstacle (safe zone)\n      getOrAddPipe('vertical', obs.maxX + vMargin, bbMinY, bbMaxY); // Right of obstacle (safe zone)\n    }\n\n    // Ensure start/end horizontal pipes exist\n    getOrAddPipe('horizontal', pSrcAnchor.y, bbMinX, bbMaxX);\n    getOrAddPipe('horizontal', pDstAnchor.y, bbMinX, bbMaxX);\n\n    // Collect relevant pipes\n    const hPipes = pipes.filter(\n      (p) => p.orientation === 'horizontal' && p.coord >= bbMinY && p.coord <= bbMaxY\n    );\n    const vPipes = pipes.filter(\n      (p) => p.orientation === 'vertical' && p.coord >= bbMinX && p.coord <= bbMaxX\n    );\n\n    // Vertices: All intersections of hPipes and vPipes\n    // We run A* on these vertices.\n\n    const getKey = (x: number, y: number) => `${x.toFixed(1)},${y.toFixed(1)}`;\n    const startKey = getKey(pSrcAnchor.x, pSrcAnchor.y);\n    const endKey = getKey(pDstAnchor.x, pDstAnchor.y);\n\n    // A* Data Structures\n    const gScore = new Map<string, number>();\n    const cameFrom = new Map<string, Point>();\n    // Track the direction we arrived at each node from: 'h' = horizontal, 'v' = vertical, 'n' = start (none)\n    const arrivalDir = new Map<string, 'h' | 'v' | 'n'>();\n    const openSet = new Set<string>();\n    const openList: { key: string; f: number; pt: Point }[] = [];\n\n    gScore.set(startKey, 0);\n    arrivalDir.set(startKey, 'n'); // start has no arrival direction\n    openList.push({\n      key: startKey,\n      f: Math.hypot(pDstAnchor.x - pSrcAnchor.x, pDstAnchor.y - pSrcAnchor.y),\n      pt: pSrcAnchor,\n    });\n    openSet.add(startKey);\n\n    let foundPath: Point[] = [];\n\n    // Helper to check if a segment is blocked for this edge (excluding src/dst)\n    const checkSegmentBlocked = (p1: Point, p2: Point): boolean => {\n      return isSegmentBlocked(p1, p2, e.start, e.end);\n    };\n\n    // Try direct L-shaped paths first (much simpler than A*)\n    // Option 1: Go horizontal first, then vertical\n    const cornerHV: Point = { x: pDstAnchor.x, y: pSrcAnchor.y };\n    const seg1HV_blocked = checkSegmentBlocked(pSrcAnchor, cornerHV);\n    const seg2HV_blocked = checkSegmentBlocked(cornerHV, pDstAnchor);\n    const pathHV_blocked = seg1HV_blocked || seg2HV_blocked;\n\n    // Option 2: Go vertical first, then horizontal\n    const cornerVH: Point = { x: pSrcAnchor.x, y: pDstAnchor.y };\n    const seg1VH_blocked = checkSegmentBlocked(pSrcAnchor, cornerVH);\n    const seg2VH_blocked = checkSegmentBlocked(cornerVH, pDstAnchor);\n    const pathVH_blocked = seg1VH_blocked || seg2VH_blocked;\n\n    if (!pathHV_blocked) {\n      // Use horizontal-first L-path\n      if (\n        Math.abs(pSrcAnchor.y - pDstAnchor.y) < EPS ||\n        Math.abs(pSrcAnchor.x - pDstAnchor.x) < EPS\n      ) {\n        // Same Y or same X - straight line (corner would be a duplicate point)\n        foundPath = [pSrcAnchor, pDstAnchor];\n      } else {\n        foundPath = [pSrcAnchor, cornerHV, pDstAnchor];\n      }\n    } else if (!pathVH_blocked) {\n      // Use vertical-first L-path\n      if (Math.abs(pSrcAnchor.x - pDstAnchor.x) < EPS) {\n        // Same X - straight vertical line\n        foundPath = [pSrcAnchor, pDstAnchor];\n      } else {\n        foundPath = [pSrcAnchor, cornerVH, pDstAnchor];\n      }\n    }\n\n    // If no direct path found, use A* (existing logic)\n    if (foundPath.length === 0) {\n      while (openList.length > 0) {\n        openList.sort((a, b) => a.f - b.f);\n        const current = openList.shift()!;\n        openSet.delete(current.key);\n\n        if (current.key === endKey) {\n          // Reconstruct path\n          let currKey = endKey;\n          let currPt = pDstAnchor;\n          foundPath = [currPt];\n          while (cameFrom.has(currKey)) {\n            const prev = cameFrom.get(currKey)!;\n            foundPath.unshift(prev);\n            currPt = prev;\n            currKey = getKey(prev.x, prev.y);\n          }\n          break;\n        }\n\n        // Neighbors: move along current horizontal pipe or current vertical pipe\n        const cx = current.pt.x;\n        const cy = current.pt.y;\n\n        // Find adjacent vPipes to cx\n        const sortedVPipes = vPipes.sort((a, b) => a.coord - b.coord);\n        const vIdx = sortedVPipes.findIndex((p) => Math.abs(p.coord - cx) < 1);\n\n        const hPipesSorted = hPipes.sort((a, b) => a.coord - b.coord);\n        const hIdx = hPipesSorted.findIndex((p) => Math.abs(p.coord - cy) < 1);\n\n        const neighbors: Point[] = [];\n\n        // Add horizontal neighbors (along hPipe at cy)\n        if (vIdx > 0) {\n          neighbors.push({ x: sortedVPipes[vIdx - 1].coord, y: cy });\n        }\n        if (vIdx >= 0 && vIdx < sortedVPipes.length - 1) {\n          neighbors.push({ x: sortedVPipes[vIdx + 1].coord, y: cy });\n        }\n\n        // Add vertical neighbors (along vPipe at cx)\n        if (hIdx > 0) {\n          neighbors.push({ x: cx, y: hPipesSorted[hIdx - 1].coord });\n        }\n        if (hIdx >= 0 && hIdx < hPipesSorted.length - 1) {\n          neighbors.push({ x: cx, y: hPipesSorted[hIdx + 1].coord });\n        }\n\n        for (const neighbor of neighbors) {\n          // Check obstacles - exclude source and destination nodes so edge can reach them\n          const minX = Math.min(cx, neighbor.x);\n          const maxX = Math.max(cx, neighbor.x);\n          const minY = Math.min(cy, neighbor.y);\n          const maxY = Math.max(cy, neighbor.y);\n\n          const blocked = obstacles.some((obs) => {\n            // Don't block on source or destination nodes - the edge needs to reach them\n            if (obs.nodeId === e.start || obs.nodeId === e.end) {\n              return false;\n            }\n            if (minX !== maxX) {\n              // Horizontal\n              return obs.minY < cy && obs.maxY > cy && obs.maxX > minX && obs.minX < maxX;\n            } else {\n              // Vertical\n              return obs.minX < cx && obs.maxX > cx && obs.maxY > minY && obs.minY < maxY;\n            }\n          });\n\n          if (blocked) {\n            continue;\n          }\n\n          const nKey = getKey(neighbor.x, neighbor.y);\n          const dist = Math.abs(neighbor.x - cx) + Math.abs(neighbor.y - cy);\n          const penalty = crossingPenalty(i, current.pt, neighbor);\n\n          // Directional penalty: STRONGLY discourage going OPPOSITE to the destination direction\n          // This prevents paths that go UP when destination is below, etc.\n          let dirPenalty = 0;\n          const destDx = pDstAnchor.x - pSrcAnchor.x;\n          const destDy = pDstAnchor.y - pSrcAnchor.y;\n          const moveDx = neighbor.x - cx;\n          const moveDy = neighbor.y - cy;\n\n          // If destination is below (destDy > 0) and we're moving up (moveDy < 0), penalize HEAVILY\n          // If destination is above (destDy < 0) and we're moving down (moveDy > 0), penalize HEAVILY\n          // Penalty must be higher than crossing penalty (typically 1000 per crossing) to prevent\n          // A* from preferring wrong-direction paths that avoid crossings\n          if ((destDy > 10 && moveDy < -5) || (destDy < -10 && moveDy > 5)) {\n            dirPenalty = Math.abs(moveDy) * 100; // VERY strong penalty - must exceed crossing penalties\n          }\n          // Similarly for horizontal\n          if ((destDx > 10 && moveDx < -5) || (destDx < -10 && moveDx > 5)) {\n            dirPenalty += Math.abs(moveDx) * 50; // Strong penalty for going wrong horizontal direction\n          }\n\n          // Bend penalty: penalize direction changes to prefer straighter paths with fewer bends\n          // This helps produce cleaner routes that don't zig-zag unnecessarily\n          let bendPenalty = 0;\n          const currentDir = arrivalDir.get(current.key) ?? 'n';\n          const moveDir: 'h' | 'v' = Math.abs(moveDx) > EPS ? 'h' : 'v';\n          // If we're changing direction (and not at start), add a penalty\n          if (currentDir !== 'n' && currentDir !== moveDir) {\n            bendPenalty = 50; // Moderate penalty for each bend/turn\n          }\n\n          const stepCost = dist + penalty + dirPenalty + bendPenalty;\n          const tentativeG = (gScore.get(current.key) ?? Infinity) + stepCost;\n          const h = Math.abs(pDstAnchor.x - neighbor.x) + Math.abs(pDstAnchor.y - neighbor.y);\n\n          if (tentativeG < (gScore.get(nKey) ?? Infinity)) {\n            cameFrom.set(nKey, current.pt);\n            gScore.set(nKey, tentativeG);\n            arrivalDir.set(nKey, moveDir); // Track how we arrived at this node\n            if (!openSet.has(nKey)) {\n              openList.push({ key: nKey, f: tentativeG + h, pt: neighbor });\n              openSet.add(nKey);\n            } else {\n              const idx = openList.findIndex((x) => x.key === nKey);\n              if (idx !== -1) {\n                openList[idx].f = tentativeG + h;\n              }\n            }\n          }\n        }\n      }\n    } // end if (foundPath.length === 0) - A* block\n\n    if (foundPath.length === 0) {\n      foundPath = [pSrcAnchor, { x: pSrcAnchor.x, y: pDstAnchor.y }, pDstAnchor];\n    }\n\n    // Path simplification: Find the minimum x-extent and y-extent needed to route around obstacles\n    // Then reconstruct the path using only those extents\n\n    if (foundPath.length > 4) {\n      const start = foundPath[0];\n      const end = foundPath[foundPath.length - 1];\n\n      // Find the extreme x and y values in the path (excluding start/end)\n      // These represent how far we had to go to clear obstacles\n      let minX = Math.min(start.x, end.x);\n      let maxX = Math.max(start.x, end.x);\n      let minY = Math.min(start.y, end.y);\n      let maxY = Math.max(start.y, end.y);\n\n      for (const pt of foundPath) {\n        minX = Math.min(minX, pt.x);\n        maxX = Math.max(maxX, pt.x);\n        minY = Math.min(minY, pt.y);\n        maxY = Math.max(maxY, pt.y);\n      }\n\n      // Determine if we need to route left or right (or both)\n      const wentRight = maxX > Math.max(start.x, end.x);\n      const wentLeft = minX < Math.min(start.x, end.x);\n\n      // For LR direction: recalculate detour X using visual extent\n      // TB x becomes LR y after transform, so the visual extent should be based on height, not width\n      if (isLR) {\n        const margin = VERTICAL_PIPE_MARGIN;\n        // Find obstacles that block the direct vertical path (caused us to detour)\n        // An obstacle blocks the path if its x-range contains the path's x and its y-range overlaps with the path's y-range\n        if (wentRight) {\n          const pathX = Math.max(start.x, end.x);\n          const pathMinY = Math.min(start.y, end.y);\n          const pathMaxY = Math.max(start.y, end.y);\n          const detourObstacles = obstacles.filter(\n            (obs) =>\n              obs.minX < pathX &&\n              obs.maxX > pathX && // obstacle's x-range contains the path x\n              obs.minY < pathMaxY &&\n              obs.maxY > pathMinY // obstacle's y-range overlaps with path y-range\n          );\n          if (detourObstacles.length > 0) {\n            // Find the obstacle that needs the maximum detour based on visual extent\n            let visualMaxX = Math.max(start.x, end.x);\n            for (const obs of detourObstacles) {\n              const obsCenterX = (obs.minX + obs.maxX) / 2;\n              // Skip obstacles without valid visualXHalfExtent (e.g., edge labels added later)\n              if (obs.visualXHalfExtent === undefined || isNaN(obs.visualXHalfExtent)) {\n                continue;\n              }\n              const visualRight = obsCenterX + obs.visualXHalfExtent + margin;\n              visualMaxX = Math.max(visualMaxX, visualRight);\n            }\n\n            // Use visual maxX - this may be smaller than the original maxX\n            // because we want to route closer to obstacles based on their visual extent (height in LR mode)\n            if (!isNaN(visualMaxX)) {\n              maxX = visualMaxX;\n            }\n          }\n        }\n        // Find obstacles that caused the left detour\n        if (wentLeft) {\n          const detourObstacles = obstacles.filter(\n            (obs) =>\n              obs.minX < Math.min(start.x, end.x) + margin && // obstacle extends past the direct path\n              obs.minY < Math.max(start.y, end.y) &&\n              obs.maxY > Math.min(start.y, end.y) // obstacle is in Y range\n          );\n          if (detourObstacles.length > 0) {\n            // Find the obstacle that needs the minimum detour based on visual extent\n            let visualMinX = Math.min(start.x, end.x);\n            for (const obs of detourObstacles) {\n              const obsCenterX = (obs.minX + obs.maxX) / 2;\n              const visualLeft = obsCenterX - obs.visualXHalfExtent - margin;\n              visualMinX = Math.min(visualMinX, visualLeft);\n            }\n            minX = visualMinX;\n          }\n        }\n      }\n\n      // Find the best Y for the horizontal return segment (closest to obstacles, not destination)\n      // This creates cleaner routing that hugs obstacles instead of going all the way to destination\n      const findBestReturnY = (detourX: number): number => {\n        const goingDown = end.y > start.y;\n        // Find obstacles that we're routing around (between start and end, blocking direct path)\n        const relevantObs = obstacles.filter((obs) => {\n          const obsInXRange =\n            Math.min(start.x, end.x) < obs.maxX && Math.max(start.x, end.x) > obs.minX;\n          const obsInYRange =\n            Math.min(start.y, end.y) < obs.maxY && Math.max(start.y, end.y) > obs.minY;\n          return obsInXRange && obsInYRange;\n        });\n\n        // For LR we care most about obstacles that actually intersect the chosen detour\n        // column (detourX). Obstacles that are between start/end but off to the side\n        // should not force the detour to go unnecessarily deep vertically.\n        let filteredObs = relevantObs;\n        if (isLR && relevantObs.length > 0) {\n          const obsAtDetourX = relevantObs.filter(\n            (obs) => obs.minX < detourX && obs.maxX > detourX\n          );\n          if (obsAtDetourX.length > 0) {\n            filteredObs = obsAtDetourX;\n          }\n        }\n\n        if (filteredObs.length === 0) {\n          return end.y;\n        }\n\n        // Find the obstacle edge closest to destination in the direction we're going\n        const margin = HORIZONTAL_PIPE_MARGIN;\n        if (goingDown) {\n          // Going down: find the bottom of the lowest obstacle we need to clear\n          const lowestObsBottom = Math.max(...filteredObs.map((obs) => obs.maxY));\n          const bestY = lowestObsBottom + margin;\n          // Only use if it's closer than end.y and doesn't overshoot\n          if (bestY < end.y - EPS) {\n            return bestY;\n          }\n        } else {\n          // Going up: find the top of the highest obstacle we need to clear\n          const highestObsTop = Math.min(...filteredObs.map((obs) => obs.minY));\n          const bestY = highestObsTop - margin;\n          // Only use if it's closer than end.y and doesn't overshoot\n          if (bestY > end.y + EPS) {\n            return bestY;\n          }\n        }\n        return end.y;\n      };\n\n      // Try to construct a minimal path using only the extreme coordinates\n      // For a U-shaped detour going right: start -> (maxX, start.y) -> (maxX, bestY) -> (end.x, bestY) -> end\n      // For a U-shaped detour going left: start -> (minX, start.y) -> (minX, bestY) -> (end.x, bestY) -> end\n      const trySimplifyWithDetourX = (detourX: number): Point[] | null => {\n        const bestY = findBestReturnY(detourX);\n        const corner1: Point = { x: detourX, y: start.y };\n        const corner2: Point = { x: detourX, y: bestY };\n        const corner3: Point = { x: end.x, y: bestY };\n        const seg1Blocked = checkSegmentBlocked(start, corner1);\n        const seg2Blocked = checkSegmentBlocked(corner1, corner2);\n        const seg3Blocked = checkSegmentBlocked(corner2, corner3);\n        const seg4Blocked = bestY !== end.y ? checkSegmentBlocked(corner3, end) : false;\n\n        if (!seg1Blocked && !seg2Blocked && !seg3Blocked && !seg4Blocked) {\n          if (Math.abs(bestY - end.y) < EPS) {\n            return [start, corner1, corner2, end];\n          }\n          return [start, corner1, corner2, corner3, end];\n        }\n        return null;\n      };\n\n      const simplified =\n        wentRight && !wentLeft\n          ? trySimplifyWithDetourX(maxX)\n          : wentLeft && !wentRight\n            ? trySimplifyWithDetourX(minX)\n            : null;\n\n      if (simplified) {\n        foundPath = simplified;\n      }\n    }\n\n    // 5. Collapse collinear and generate segments\n    // Include handle waypoints for routing around obstacles at source/destination\n    const fullPoints = [\n      pSrcPort,\n      ...srcHandleWaypoints,\n      ...foundPath,\n      ...dstHandleWaypoints.reverse(), // Reverse because they're stored anchor->waypoint->port\n      pDstPort,\n    ];\n\n    // Post-process: Remove \"hooks\" or \"overshoots\" at the end\n    // If the path goes A -> B -> C, and A-B-C are collinear, and B is \"beyond\" C, truncate B.\n    // This happens if pDstAnchor (B) is on the node boundary but pDstPort (C) is slightly outside (margin).\n    if (fullPoints.length >= 3) {\n      const C = fullPoints[fullPoints.length - 1];\n      const B = fullPoints[fullPoints.length - 2];\n      const A = fullPoints[fullPoints.length - 3];\n\n      // Check collinearity (Horizontal or Vertical)\n      const isHoriz = Math.abs(A.y - B.y) < EPS && Math.abs(B.y - C.y) < EPS;\n      const isVert = Math.abs(A.x - B.x) < EPS && Math.abs(B.x - C.x) < EPS;\n\n      if (isHoriz) {\n        // Check if C is between A and B (i.e., B overshot C)\n        // dist(A, B) > dist(A, C) and direction is same?\n        // Or simply: B is further from A than C is, in the same direction.\n        // Signs: (B-A) and (C-A) have same sign. |B-A| > |C-A|.\n        const signAB = Math.sign(B.x - A.x);\n        const signAC = Math.sign(C.x - A.x);\n        if (signAB !== 0 && signAB === signAC && Math.abs(B.x - A.x) > Math.abs(C.x - A.x)) {\n          // B is an overshoot. Remove B.\n          // fullPoints = [..., A, C]\n          fullPoints.splice(-2, 1);\n        }\n      } else if (isVert) {\n        const signAB = Math.sign(B.y - A.y);\n        const signAC = Math.sign(C.y - A.y);\n        if (signAB !== 0 && signAB === signAC && Math.abs(B.y - A.y) > Math.abs(C.y - A.y)) {\n          fullPoints.splice(-2, 1);\n        }\n      }\n    }\n\n    const simplified: Point[] = [fullPoints[0]];\n    for (let k = 1; k < fullPoints.length - 1; k++) {\n      // Preserve the Anchor point (k=1) to satisfy strict testing requirements expecting 4 points for Z/U shapes\n      if (k === 1) {\n        simplified.push(fullPoints[k]);\n        continue;\n      }\n      const prev = simplified[simplified.length - 1];\n      const curr = fullPoints[k];\n      const next = fullPoints[k + 1];\n\n      // Check collinearity carefully - direction matters?\n      // If direction reverses, we should NOT skip.\n      // Horizontal: y is same.\n      if (Math.abs(prev.y - curr.y) < EPS && Math.abs(curr.y - next.y) < EPS) {\n        // Check direction reversal\n        const dir1 = curr.x > prev.x;\n        const dir2 = next.x > curr.x;\n        if (dir1 !== dir2) {\n          simplified.push(curr);\n          continue;\n        }\n        // Same direction, can skip\n        continue;\n      }\n      // Vertical: x is same\n      if (Math.abs(prev.x - curr.x) < EPS && Math.abs(curr.x - next.x) < EPS) {\n        const dir1 = curr.y > prev.y;\n        const dir2 = next.y > curr.y;\n        if (dir1 !== dir2) {\n          simplified.push(curr);\n          continue;\n        }\n        continue;\n      }\n\n      simplified.push(curr);\n    }\n    simplified.push(fullPoints[fullPoints.length - 1]);\n\n    // Create Segments\n    for (let k = 0; k < simplified.length - 1; k++) {\n      const p1 = simplified[k];\n      const p2 = simplified[k + 1];\n      const orientation: Orientation = Math.abs(p1.x - p2.x) < EPS ? 'vertical' : 'horizontal';\n      const coord = orientation === 'vertical' ? p1.x : p1.y;\n      const from = orientation === 'vertical' ? Math.min(p1.y, p2.y) : Math.min(p1.x, p2.x);\n      const to = orientation === 'vertical' ? Math.max(p1.y, p2.y) : Math.max(p1.x, p2.x);\n\n      const pipe = getOrAddPipe(orientation, coord, from, to);\n\n      const rSeg: RoutedSegment = {\n        edgeIndex: i,\n        segmentIndex: k,\n        orientation,\n        pipe,\n        trackIndex: 0, // Initial track\n        from,\n        to,\n      };\n\n      allRoutedSegments.push(rSeg);\n      edgeSegmentIndices[i].push(allRoutedSegments.length - 1);\n\n      if (!pipe.tracks[0]) {\n        pipe.tracks[0] = { index: 0, coord: pipe.coord, segments: [] };\n      }\n      pipe.tracks[0].segments.push({\n        edgeIndex: i,\n        segmentIndex: k,\n        from,\n        to,\n      });\n    }\n  }\n\n  // -----------------------------------------------------------------------\n  // Phase 2: Crossing Reduction\n  // -----------------------------------------------------------------------\n\n  const segmentsOverlap = (s1: { from: number; to: number }, s2: { from: number; to: number }) => {\n    // Overlap if intervals intersect.\n    // [a, b] and [c, d] overlap if a < d and c < b.\n    // from/to are sorted (min/max).\n    return s1.from < s2.to && s2.from < s1.to;\n  };\n\n  const trySwapSegmentsAcrossTracks = (\n    s1: RoutedSegment,\n    s2: RoutedSegment,\n    t1: Track,\n    t2: Track\n  ): boolean => {\n    const canS1GoT2 = !t2.segments.some(\n      (r) =>\n        (r.edgeIndex !== s2.edgeIndex || r.segmentIndex !== s2.segmentIndex) &&\n        segmentsOverlap(r, s1)\n    );\n    const canS2GoT1 = !t1.segments.some(\n      (r) =>\n        (r.edgeIndex !== s1.edgeIndex || r.segmentIndex !== s1.segmentIndex) &&\n        segmentsOverlap(r, s2)\n    );\n\n    if (canS1GoT2 && canS2GoT1) {\n      s1.trackIndex = t2.index;\n      s2.trackIndex = t1.index;\n      t1.segments = [\n        ...t1.segments.filter(\n          (r) => r.edgeIndex !== s1.edgeIndex || r.segmentIndex !== s1.segmentIndex\n        ),\n        {\n          edgeIndex: s2.edgeIndex,\n          segmentIndex: s2.segmentIndex,\n          from: s2.from,\n          to: s2.to,\n        },\n      ];\n      t2.segments = [\n        ...t2.segments.filter(\n          (r) => r.edgeIndex !== s2.edgeIndex || r.segmentIndex !== s2.segmentIndex\n        ),\n        {\n          edgeIndex: s1.edgeIndex,\n          segmentIndex: s1.segmentIndex,\n          from: s1.from,\n          to: s1.to,\n        },\n      ];\n      return true;\n    }\n    return false;\n  };\n\n  const createNewTrack = (pipe: Pipe): number => {\n    const idx = pipe.tracks.length;\n    pipe.tracks[idx] = { index: idx, coord: pipe.coord, segments: [] };\n    return idx;\n  };\n\n  const moveSegmentToTrack = (seg: RoutedSegment, trackIdx: number) => {\n    const oldTrack = seg.pipe.tracks[seg.trackIndex];\n    oldTrack.segments = oldTrack.segments.filter(\n      (r) => r.edgeIndex !== seg.edgeIndex || r.segmentIndex !== seg.segmentIndex\n    );\n    seg.trackIndex = trackIdx;\n    const newTrack = seg.pipe.tracks[trackIdx];\n    newTrack.segments.push({\n      edgeIndex: seg.edgeIndex,\n      segmentIndex: seg.segmentIndex,\n      from: seg.from,\n      to: seg.to,\n    });\n  };\n\n  const moveSegmentChainToTrack = (seg: RoutedSegment, trackIdx: number) => {\n    // Move ALL segments of this edge that are on the same pipe, not just consecutive ones\n    const indices = edgeSegmentIndices[seg.edgeIndex];\n    for (const idx of indices) {\n      const s = allRoutedSegments[idx];\n      if (s.pipe === seg.pipe) {\n        moveSegmentToTrack(s, trackIdx);\n      }\n    }\n  };\n\n  const getAdjacentSegmentsAlongEdge = (seg: RoutedSegment) => {\n    const indices = edgeSegmentIndices[seg.edgeIndex];\n    const idxInList = indices.indexOf(allRoutedSegments.indexOf(seg));\n    const adj: RoutedSegment[] = [];\n    if (idxInList > 0) {\n      adj.push(allRoutedSegments[indices[idxInList - 1]]);\n    }\n    if (idxInList < indices.length - 1) {\n      adj.push(allRoutedSegments[indices[idxInList + 1]]);\n    }\n    return adj;\n  };\n\n  const haveAnyCrossing = (segA: RoutedSegment, segB: RoutedSegment) => {\n    if (segA.orientation === segB.orientation) {\n      return false;\n    }\n    const h = segA.orientation === 'horizontal' ? segA : segB;\n    const v = segA.orientation === 'horizontal' ? segB : segA;\n    return (\n      v.pipe.coord > h.from && v.pipe.coord < h.to && h.pipe.coord > v.from && h.pipe.coord < v.to\n    );\n  };\n\n  const findAvailableTrack = (pipe: Pipe, seg: RoutedSegment): number => {\n    for (const track of pipe.tracks) {\n      const overlap = track.segments.some(\n        (r) =>\n          (r.edgeIndex !== seg.edgeIndex || r.segmentIndex !== seg.segmentIndex) &&\n          segmentsOverlap(r, seg)\n      );\n      if (!overlap) {\n        return track.index;\n      }\n    }\n    return -1;\n  };\n\n  const segmentsConflict = (s1: RoutedSegment, s2: RoutedSegment): boolean => {\n    if (s1.trackIndex === s2.trackIndex) {\n      return segmentsOverlap(s1, s2);\n    }\n\n    const adj1 = getAdjacentSegmentsAlongEdge(s1);\n    const adj2 = getAdjacentSegmentsAlongEdge(s2);\n    return adj1.some((a1) => adj2.some((a2) => haveAnyCrossing(a1, a2)));\n  };\n\n  const resolveTrackConflict = (\n    s1: RoutedSegment,\n    s2: RoutedSegment,\n    move: (seg: RoutedSegment, trackIdx: number) => void\n  ) => {\n    if (\n      trySwapSegmentsAcrossTracks(\n        s1,\n        s2,\n        s1.pipe.tracks[s1.trackIndex],\n        s2.pipe.tracks[s2.trackIndex]\n      )\n    ) {\n      return;\n    }\n\n    const avail = findAvailableTrack(s1.pipe, s2);\n    move(s2, avail !== -1 ? avail : createNewTrack(s1.pipe));\n  };\n\n  const resolveHandleConflicts = (handles: RoutedSegment[]): number => {\n    let crossings = 0;\n    for (let i = 0; i < handles.length; i++) {\n      for (let j = i + 1; j < handles.length; j++) {\n        const h1 = handles[i];\n        const h2 = handles[j];\n        if (h1.pipe !== h2.pipe) {\n          continue;\n        }\n\n        if (segmentsConflict(h1, h2)) {\n          crossings++;\n          resolveTrackConflict(h1, h2, moveSegmentChainToTrack);\n        }\n      }\n    }\n    return crossings;\n  };\n\n  interface DestInfo {\n    dest: number;\n    deviation: number;\n    base: number;\n    delta: number;\n  }\n  const destInfoCache = new Map<number, DestInfo>();\n  const getDestInfo = (edgeIdx: number): DestInfo => {\n    if (destInfoCache.has(edgeIdx)) {\n      return destInfoCache.get(edgeIdx)!;\n    }\n    const indices = edgeSegmentIndices[edgeIdx];\n    if (indices.length === 0) {\n      const info = { dest: 0, deviation: 0, base: 0, delta: 0 };\n      destInfoCache.set(edgeIdx, info);\n      return info;\n    }\n    const firstSeg = allRoutedSegments[indices[0]];\n    const base = firstSeg.pipe.coord;\n    let dest = base;\n    for (let idx = 1; idx < indices.length; idx++) {\n      const seg = allRoutedSegments[indices[idx]];\n      if (seg.orientation === 'horizontal') {\n        const candidateA = seg.from;\n        const candidateB = seg.to;\n        dest = Math.abs(candidateA - base) > Math.abs(candidateB - base) ? candidateA : candidateB;\n        break;\n      }\n    }\n    const deviation = Math.abs(dest - base);\n    const info = { dest, deviation, base, delta: dest - base };\n    destInfoCache.set(edgeIdx, info);\n    return info;\n  };\n\n  const fixSourceHandleCrossings = (): number => {\n    let crossings = 0;\n    const edgesBySource = new Map<string, number[]>();\n    for (const [i, e] of edges.entries()) {\n      if (edgeSegmentIndices[i].length === 0) {\n        continue;\n      }\n      if (!e.start) {\n        continue;\n      }\n      if (!edgesBySource.has(e.start)) {\n        edgesBySource.set(e.start, []);\n      }\n      edgesBySource.get(e.start)!.push(i);\n    }\n\n    const getEdgeDistance = (edgeIdx: number) => {\n      const edge = edges[edgeIdx];\n      if (!edge.start || !edge.end) {\n        return 0;\n      }\n      const srcNode = nodeById.get(edge.start);\n      const dstNode = nodeById.get(edge.end);\n      if (!srcNode || !dstNode) {\n        return 0;\n      }\n      const dx = (dstNode.x ?? 0) - (srcNode.x ?? 0);\n      const dy = (dstNode.y ?? 0) - (srcNode.y ?? 0);\n      return Math.abs(dx) + Math.abs(dy);\n    };\n\n    for (const grp of edgesBySource.values()) {\n      // Sort by continuity: prefer edges that continue straight from previous segment\n      grp.sort((a, b) => {\n        // 0. Destination-aware ordering: keep near-center edges on the center track.\n        const infoA = getDestInfo(a);\n        const infoB = getDestInfo(b);\n        if (Math.abs(infoA.deviation - infoB.deviation) > 1) {\n          return infoA.deviation - infoB.deviation;\n        }\n        if (Math.abs(infoA.dest - infoB.dest) > 1) {\n          return infoA.dest - infoB.dest;\n        }\n\n        // 0. Prefer longer spans (edges that travel further should keep straighter paths)\n        const distA = getEdgeDistance(a);\n        const distB = getEdgeDistance(b);\n        if (Math.abs(distA - distB) > 1) {\n          return distB - distA;\n        }\n\n        // 1. Segment Count: Prefer simpler paths (fewer segments usually means more direct)\n        const lenA = edgeSegmentIndices[a].length;\n        const lenB = edgeSegmentIndices[b].length;\n        if (lenA !== lenB) {\n          return lenA - lenB;\n        }\n\n        // 2. Length Check for single-segment edges: Prefer shorter edges to stay centered\n        if (lenA === 1) {\n          const idxA = edgeSegmentIndices[a][0];\n          const idxB = edgeSegmentIndices[b][0];\n          // Ensure indices exist\n          if (allRoutedSegments[idxA] && allRoutedSegments[idxB]) {\n            const segA = allRoutedSegments[idxA];\n            const segB = allRoutedSegments[idxB];\n            const distA = Math.abs(segA.to - segA.from);\n            const distB = Math.abs(segB.to - segB.from);\n            if (Math.abs(distA - distB) > 1) {\n              // Shorter distance (closer destination) should come first to get center track\n              return distA - distB;\n            }\n          }\n        }\n\n        return 0;\n      });\n\n      const handles = grp.map((ei) => allRoutedSegments[edgeSegmentIndices[ei][0]]);\n      crossings += resolveHandleConflicts(handles);\n    }\n    return crossings;\n  };\n\n  const fixTargetHandleCrossings = (): number => {\n    let crossings = 0;\n    const edgesByTarget = new Map<string, number[]>();\n    for (const [i, e] of edges.entries()) {\n      const indices = edgeSegmentIndices[i];\n      if (indices.length === 0) {\n        continue;\n      }\n      if (!e.end) {\n        continue;\n      }\n      if (!edgesByTarget.has(e.end)) {\n        edgesByTarget.set(e.end, []);\n      }\n      edgesByTarget.get(e.end)!.push(i);\n    }\n\n    for (const grp of edgesByTarget.values()) {\n      // Sort by continuity: prefer edges that align with their previous segment\n      grp.sort((a, b) => {\n        const getDist = (edgeIdx: number) => {\n          const indices = edgeSegmentIndices[edgeIdx];\n          if (indices.length < 2) {\n            return 0;\n          }\n          // Shorter perpendicular connector means better target-handle alignment.\n          const prev = allRoutedSegments[indices[indices.length - 2]];\n          return Math.abs(prev.to - prev.from);\n        };\n\n        const scoreA = getDist(a);\n        const scoreB = getDist(b);\n        if (Math.abs(scoreA - scoreB) > 0.1) {\n          return scoreA - scoreB; // Ascending length (shorter first)\n        }\n        return a - b; // Stable fallback\n      });\n\n      const handles = grp.map(\n        (ei) => allRoutedSegments[edgeSegmentIndices[ei][edgeSegmentIndices[ei].length - 1]]\n      );\n      crossings += resolveHandleConflicts(handles);\n    }\n    return crossings;\n  };\n\n  const fixPipeCrossings = (): number => {\n    let crossings = 0;\n    for (const pipe of pipes) {\n      // Collect all segments in pipe\n      const pipeSegments: RoutedSegment[] = [];\n      for (const t of pipe.tracks) {\n        for (const ref of t.segments) {\n          // Find the actual RoutedSegment object\n          const idx = edgeSegmentIndices[ref.edgeIndex].find(\n            (ix) => allRoutedSegments[ix].segmentIndex === ref.segmentIndex\n          );\n          if (idx !== undefined) {\n            pipeSegments.push(allRoutedSegments[idx]);\n          }\n        }\n      }\n\n      // if (pipeSegments.length > 0 && pipe.orientation === 'vertical' && Math.abs(pipe.coord - (-19.5)) < 0.1) {}\n\n      pipeSegments.sort((a, b) => a.edgeIndex - b.edgeIndex || a.segmentIndex - b.segmentIndex);\n\n      for (let i = 0; i < pipeSegments.length; i++) {\n        for (let j = i + 1; j < pipeSegments.length; j++) {\n          const s1 = pipeSegments[i];\n          const s2 = pipeSegments[j];\n\n          if (segmentsConflict(s1, s2)) {\n            crossings++;\n            resolveTrackConflict(s1, s2, moveSegmentToTrack);\n          }\n        }\n      }\n    }\n    return crossings;\n  };\n\n  // Main Reduction Loop\n  let iterations = 0;\n  const MAX_ITER = 10;\n  while (iterations < MAX_ITER) {\n    let changed = 0;\n    changed += fixSourceHandleCrossings();\n    changed += fixTargetHandleCrossings();\n    changed += fixPipeCrossings();\n    if (changed === 0) {\n      break;\n    }\n    iterations++;\n  }\n\n  // -----------------------------------------------------------------------\n  // Phase 3: Rebuild Geometry\n  // -----------------------------------------------------------------------\n  const segmentCoords = new Map<string, number>(); // `${edgeIndex}-${segmentIndex}` -> coord\n\n  for (const pipe of pipes) {\n    // Identify clusters of connected segments (interval graph)\n    interface SegmentInfo {\n      edgeIndex: number;\n      segmentIndex: number;\n      trackIndex: number;\n      from: number;\n      to: number;\n    }\n\n    const segments: SegmentInfo[] = [];\n    pipe.tracks.forEach((t) => {\n      t.segments.forEach((s) => {\n        segments.push({\n          edgeIndex: s.edgeIndex,\n          segmentIndex: s.segmentIndex,\n          trackIndex: t.index,\n          from: s.from,\n          to: s.to,\n        });\n      });\n    });\n\n    segments.sort((a, b) => a.from - b.from);\n\n    const clusters: SegmentInfo[][] = [];\n    if (segments.length > 0) {\n      let currentCluster: SegmentInfo[] = [segments[0]];\n      let clusterEnd = segments[0].to;\n\n      for (let k = 1; k < segments.length; k++) {\n        const s = segments[k];\n        if (s.from < clusterEnd) {\n          currentCluster.push(s);\n          clusterEnd = Math.max(clusterEnd, s.to);\n        } else {\n          clusters.push(currentCluster);\n          currentCluster = [s];\n          clusterEnd = s.to;\n        }\n      }\n      clusters.push(currentCluster);\n    }\n\n    // Assign local coordinates for each cluster\n    for (const cluster of clusters) {\n      const usedTracks = new Set<number>();\n      cluster.forEach((s) => usedTracks.add(s.trackIndex));\n      const trackScores = new Map<number, number>();\n      cluster.forEach((s) => {\n        const info = getDestInfo(s.edgeIndex);\n        trackScores.set(s.trackIndex, (trackScores.get(s.trackIndex) ?? 0) + info.delta);\n      });\n\n      const leftTracks = [...usedTracks].filter((t) => (trackScores.get(t) ?? 0) < -1);\n      const rightTracks = [...usedTracks].filter((t) => (trackScores.get(t) ?? 0) > 1);\n      const neutralTracks = [...usedTracks].filter((t) => Math.abs(trackScores.get(t) ?? 0) <= 1);\n\n      leftTracks.sort((a, b) => (trackScores.get(b) ?? 0) - (trackScores.get(a) ?? 0));\n      rightTracks.sort((a, b) => (trackScores.get(a) ?? 0) - (trackScores.get(b) ?? 0));\n\n      const assignCoord = (trackIndex: number, coord: number) => {\n        cluster\n          .filter((s) => s.trackIndex === trackIndex)\n          .forEach((s) => {\n            // Straight intra-lane edges keep pipe coord \u2014 don't spread them\n            const effectiveCoord = straightIntraLaneEdges.has(s.edgeIndex) ? pipe.coord : coord;\n            segmentCoords.set(`${s.edgeIndex}-${s.segmentIndex}`, effectiveCoord);\n          });\n      };\n\n      let leftCount = 0;\n      for (const trackIndex of leftTracks) {\n        leftCount++;\n        assignCoord(trackIndex, pipe.coord - leftCount * TRACK_SPACING);\n      }\n\n      if (neutralTracks.length === 0 && usedTracks.size > 0) {\n        // If no neutral track, make the closest-to-center track neutral\n        const bestTrack = [...usedTracks].sort(\n          (a, b) => Math.abs(trackScores.get(a) ?? 0) - Math.abs(trackScores.get(b) ?? 0)\n        )[0];\n        const leftIdx = leftTracks.indexOf(bestTrack);\n        if (leftIdx !== -1) {\n          leftTracks.splice(leftIdx, 1);\n        }\n        const rightIdx = rightTracks.indexOf(bestTrack);\n        if (rightIdx !== -1) {\n          rightTracks.splice(rightIdx, 1);\n        }\n        neutralTracks.push(bestTrack);\n      }\n\n      let neutralAssigned = 0;\n      for (const trackIndex of neutralTracks) {\n        if (neutralAssigned === 0) {\n          assignCoord(trackIndex, pipe.coord);\n        } else {\n          const dir = neutralAssigned % 2 === 1 ? 1 : -1;\n          const magnitude = Math.ceil(neutralAssigned / 2);\n          assignCoord(trackIndex, pipe.coord + dir * magnitude * TRACK_SPACING * 0.5);\n        }\n        neutralAssigned++;\n      }\n\n      let rightCount = 0;\n      for (const trackIndex of rightTracks) {\n        rightCount++;\n        assignCoord(trackIndex, pipe.coord + rightCount * TRACK_SPACING);\n      }\n    }\n  }\n\n  // Strategy 1: no sibling to-label fan-out nudge is needed because\n  // `-to-label` synthetic edges no longer exist; labelled originals route\n  // as single A\u2192B edges and share track assignment with every other edge.\n\n  for (const [i, e] of edges.entries()) {\n    const indices = edgeSegmentIndices[i] ?? [];\n    if (indices.length === 0) {\n      continue;\n    }\n\n    const newPoints: Point[] = [];\n\n    // Recompute ports, honoring Step 6.2's side assignment.\n    const src = nodeById.get(e.start!)!;\n    const dst = nodeById.get(e.end!)!;\n    const { pSrcPort, pDstPort } = portsForEdge(i, src, dst);\n\n    const lines: RoutedLine[] = indices.map((idx) => {\n      const s = allRoutedSegments[idx];\n      // const track = s.pipe.tracks[s.trackIndex];\n      const coord = segmentCoords.get(`${s.edgeIndex}-${s.segmentIndex}`) ?? s.pipe.coord;\n      return {\n        orient: s.orientation,\n        coord: coord,\n        from: s.from,\n        to: s.to,\n      };\n    });\n\n    newPoints.push(pSrcPort);\n\n    for (let k = 0; k < lines.length; k++) {\n      const line = lines[k];\n      const prevPt = newPoints[newPoints.length - 1];\n      const prevAlong = line.orient === 'vertical' ? prevPt.y : prevPt.x;\n      const prevTrackCoord = line.orient === 'vertical' ? prevPt.x : prevPt.y;\n      const nextLine = lines[k + 1];\n      const hasNextLine = k < lines.length - 1;\n\n      if (Math.abs(prevTrackCoord - line.coord) > EPS) {\n        newPoints.push(pointOnLine(line, prevAlong));\n      }\n\n      if (hasNextLine && nextLine.orient === line.orient) {\n        if (Math.abs(line.coord - nextLine.coord) > EPS) {\n          const junction =\n            line.orient === 'vertical'\n              ? (prevAlong + nextLine.from) / 2\n              : sharedLineEndpointCoord(line, nextLine);\n          newPoints.push(pointOnLine(line, junction), pointOnLine(nextLine, junction));\n        } else if (k === 0 || k === lines.length - 2) {\n          newPoints.push(pointOnLine(line, sharedLineEndpointCoord(line, nextLine)));\n        }\n      } else if (hasNextLine) {\n        newPoints.push(pointOnLine(line, nextLine.coord));\n      } else {\n        const endAlong =\n          Math.abs(line.from - prevAlong) < Math.abs(line.to - prevAlong) ? line.to : line.from;\n        newPoints.push(pointOnLine(line, endAlong));\n      }\n    }\n\n    // Ensure we end at pDstPort to protect the last anchor from being eaten by the renderer's intersection logic\n    const last = newPoints[newPoints.length - 1];\n    if (Math.abs(last.x - pDstPort.x) > EPS || Math.abs(last.y - pDstPort.y) > EPS) {\n      newPoints.push(pDstPort);\n    }\n\n    const filtered: Point[] = [];\n    if (newPoints.length > 0) {\n      filtered.push(newPoints[0]);\n    }\n    for (let k = 1; k < newPoints.length; k++) {\n      const p = newPoints[k];\n      const prev = filtered[filtered.length - 1];\n      if (Math.abs(p.x - prev.x) > EPS || Math.abs(p.y - prev.y) > EPS) {\n        filtered.push(p);\n      }\n    }\n\n    e.points = filtered;\n  }\n\n  // Strategy 1: no shadow concatenation / L-bend bridge. Each labelled\n  // original now routes as a single unbroken A\u2192B polyline, so we simply\n  // copy the routing view's polyline back onto the original edge.\n  for (const re of edges) {\n    const orig = re.__originalEdge as { points?: Point[] } | undefined;\n    if (orig && re.points) {\n      orig.points = re.points;\n    }\n  }\n\n  // Strip `isLayoutOnly` virtual edges from the layout. They have served their\n  // purpose by giving Sugiyama layering constraints through label nodes and\n  // must not reach rendering, validation, or scoring.\n  data.edges = (data.edges ?? []).filter((e) => !(e as { isLayoutOnly?: boolean }).isLayoutOnly);\n\n  // Snap edge endpoints onto the rectangular boundary of their src / dst\n  // nodes. Raykov's internal port-and-anchor logic leaves the polyline\n  // terminating near the anchor offset (inside the node body); the renderer\n  // normally clips to the node boundary via `tail.intersect()`, but the\n  // validator sees the raw polyline points. Snapping here guarantees the\n  // first and last points sit on the boundary regardless of downstream\n  // rendering, and preserves the last/first segment's orientation.\n  const nodeBoundaryClamp = (p: Point, node: MermaidNode): Point => {\n    const cx = node.x ?? 0;\n    const cy = node.y ?? 0;\n    const w = node.width ?? 0;\n    const h = node.height ?? 0;\n    if (w <= 0 || h <= 0) {\n      return p;\n    }\n    const left = cx - w / 2;\n    const right = cx + w / 2;\n    const top = cy - h / 2;\n    const bottom = cy + h / 2;\n    // Already outside the rect: leave alone.\n    if (p.x < left || p.x > right || p.y < top || p.y > bottom) {\n      return p;\n    }\n    // Inside (or on) the rect: project onto the nearest edge. Ties pick the\n    // side closest to the node center in the orthogonal axis, which keeps\n    // the snap consistent across similarly-positioned edges.\n    const dLeft = p.x - left;\n    const dRight = right - p.x;\n    const dTop = p.y - top;\n    const dBottom = bottom - p.y;\n    const minD = Math.min(dLeft, dRight, dTop, dBottom);\n    if (minD === dLeft) {\n      return { x: left, y: p.y };\n    }\n    if (minD === dRight) {\n      return { x: right, y: p.y };\n    }\n    if (minD === dTop) {\n      return { x: p.x, y: top };\n    }\n    return { x: p.x, y: bottom };\n  };\n\n  for (const edge of data.edges) {\n    const pts = (edge as { points?: Point[] }).points;\n    if (!pts || pts.length < 2) {\n      continue;\n    }\n    const srcId = (edge as { start?: string }).start;\n    const dstId = (edge as { end?: string }).end;\n    const src = srcId ? nodeById.get(srcId) : undefined;\n    const dst = dstId ? nodeById.get(dstId) : undefined;\n    if (src) {\n      pts[0] = nodeBoundaryClamp(pts[0], src);\n    }\n    if (dst) {\n      pts[pts.length - 1] = nodeBoundaryClamp(pts[pts.length - 1], dst);\n    }\n  }\n\n  return data;\n}\n", "import type { LayoutData } from '../../types.js';\nimport { postProcessSwimlaneLayout, validateSwimlanesLayout } from './postProcessing.js';\nimport { toGraphView, writeBackToLayoutData } from './helpers.js';\nimport { sugiyamaLayout } from './pipeline.js';\nimport { routeEdgesOrthogonal } from './orthogonalRouter/router.js';\n\nexport type SwimlaneDirection = 'TB' | 'LR' | 'BT' | 'RL';\n\nfunction getSwimlaneDirection(data4Layout: LayoutData): SwimlaneDirection {\n  return ((data4Layout as LayoutData & { direction?: string }).direction ??\n    'TB') as SwimlaneDirection;\n}\n\n/**\n * Pure swimlane layout core shared by browser rendering and DDLT.\n *\n * The browser measures DOM nodes before this runs; DDLT injects captured sizes\n * before calling the same function.\n */\nexport function runSwimlaneLayoutCore(data4Layout: LayoutData): SwimlaneDirection {\n  const g = toGraphView(data4Layout);\n  const nodeGap = data4Layout.config.flowchart?.nodeSpacing ?? 40;\n  const layerGap = data4Layout.config.flowchart?.rankSpacing ?? 100;\n  const ignoreCrossLaneEdges = data4Layout.config.swimlane?.ignoreCrossLaneEdges ?? true;\n  const optimizeRanksByCrossings = data4Layout.config.swimlane?.optimizeRanksByCrossings ?? true;\n  const automaticLaneOrdering = data4Layout.config.swimlane?.automaticLaneOrdering ?? false;\n  const direction = getSwimlaneDirection(data4Layout);\n\n  const { ordered, coordinates } = sugiyamaLayout(g, {\n    nodeGap,\n    layerGap,\n    ignoreCrossLaneEdges,\n    optimizeRanksByCrossings,\n    automaticLaneOrdering,\n    direction,\n  });\n  writeBackToLayoutData(g, ordered, coordinates, { nodeGap, layerGap });\n\n  // The layout phases above position nodes only; they do not emit edge routing.\n  // Reset any edge points carried on the input so routeEdgesOrthogonal below is\n  // the single source of truth for swimlane edge geometry.\n  for (const edge of data4Layout.edges ?? []) {\n    delete edge.points;\n  }\n  routeEdgesOrthogonal(data4Layout, direction);\n\n  for (const edge of data4Layout.edges ?? []) {\n    if (!edge.curve || edge.curve === 'basis') {\n      edge.curve = 'rounded';\n    }\n  }\n\n  postProcessSwimlaneLayout(data4Layout, direction);\n\n  validateSwimlanesLayout(data4Layout);\n\n  return direction;\n}\n", "import type { SVG } from '../../../mermaid.js';\nimport type { D3Selection } from '../../../types.js';\nimport { createGraphWithElements } from '../../createGraph.js';\nimport insertMarkers from '../../rendering-elements/markers.js';\nimport { clear as clearGraphlib } from '../dagre/mermaid-graphlib.js';\nimport { clear as clearNodes } from '../../rendering-elements/nodes.js';\nimport { clear as clearClusters } from '../../rendering-elements/clusters.js';\nimport { clear as clearEdges } from '../../rendering-elements/edges.js';\nimport type { LayoutData } from '../../types.js';\nimport { adjustLayout } from './adjustLayout.js';\nimport { prepareLayoutForSwimlanes } from './helpers.js';\nimport { createEdgeLabelNodes } from './edgeLabelNodes.js';\nimport { runSwimlaneLayoutCore } from './layoutCore.js';\n\nexport async function render(data4Layout: LayoutData, svg: SVG) {\n  const element = svg.select('g') as unknown as D3Selection<SVGElement>;\n  insertMarkers(element, data4Layout.markers, data4Layout.type, data4Layout.diagramId);\n  clearNodes();\n  clearEdges();\n  clearClusters();\n  clearGraphlib();\n\n  prepareLayoutForSwimlanes(data4Layout);\n\n  const transformedData = createEdgeLabelNodes(data4Layout);\n  data4Layout.nodes = transformedData.nodes;\n  data4Layout.edges = transformedData.edges;\n\n  const { groups } = await createGraphWithElements(element, data4Layout);\n\n  runSwimlaneLayoutCore(data4Layout);\n\n  await adjustLayout(data4Layout, groups);\n}\n"],
  "mappings": "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",
  "names": ["createGraphWithElements", "element", "data4Layout", "graph", "Graph", "edgesToProcess", "config", "getConfig", "rootGroups", "clusters", "edgePaths", "edgeLabels", "nodesGroup", "nodeElements", "hasDom", "node", "childNodeEl", "insertNode", "boundingBox", "edge", "existingEdge", "captureNodeSizes", "__name", "ROUNDED_CORNER_RADIUS", "CORNER_EPSILON", "ENDPOINT_EPSILON", "buildSegmentList", "points", "segments", "i", "__name", "segmentIntersection", "a1", "a2", "b1", "b2", "dxA", "dyA", "dxB", "dyB", "denom", "dx", "dy", "tA", "tB", "isHorizontalSeg", "seg", "findEdgeIntersections", "edges", "crossings", "edgeA", "segmentsA", "j", "edgeB", "segmentsB", "si", "segA", "sj", "segB", "hit", "aHoriz", "bHoriz", "fmt", "n", "rounded", "pointToString", "p", "getArcSweepFlag", "MIN_JUMP_RADIUS", "applyMarkerOffsets", "edge", "out", "startOff", "markerOffsets", "a", "b", "ang", "endOff", "emitJump", "jump", "ux", "uy", "sweep", "style", "cx", "cy", "pre", "post", "computeRoundedCorner", "prev", "curr", "next", "radius", "dx1", "dy1", "dx2", "dy2", "len1", "len2", "nx1", "ny1", "nx2", "ny2", "dot", "clamped", "angle", "cutLen", "rewriteEdgePath", "jumps", "config", "rawPoints", "bySeg", "segLen", "list", "parts", "segStartConsumed", "corner", "segEndStop", "upcomingCorner", "segJumps", "k", "gap", "half", "isStraightPath", "d", "__name", "curveSupportsLineHops", "curve", "decodeDataPoints", "raw", "json", "parsed", "pts", "p", "applyLineJumpsToSvg", "edgePathsGroup", "edges", "config", "groupNode", "edgeMeta", "e", "renderedEdges", "pathById", "escapedId", "pathEl", "points", "crossings", "findEdgeIntersections", "jumpsByEdge", "c", "list", "renderedEdge", "jumps", "curveHint", "currentD", "originalStyle", "dasharrayMatch", "preservedOValueS", "preservedOValueE", "newD", "rewriteEdgePath", "newLen", "onLen", "newDasharray", "cleaned", "adjustLayout", "data4Layout", "groups", "node", "insertCluster", "positionNode", "nodeById", "edge", "startNode", "endNode", "paths", "insertEdge", "insertEdgeLabel", "positionEdgeLabel", "lineHopsConfig", "jumpStyle", "edgeGeometries", "e", "applyLineJumpsToSvg", "__name", "path", "siteConfig", "getConfig", "subGraphTitleTotalMargin", "getSubGraphTitleMargins", "el", "edgeLabels", "x", "y", "pos", "utils_default", "log", "terminalLabels", "DEFAULT_SWIMLANE_ID", "topLaneHorizontalPadding", "lane", "__name", "assignTopLaneTitleRect", "x", "y", "width", "height", "contentTop", "top", "headerBottom", "titleHeight", "bottom", "prepareLayoutForSwimlanes", "layout", "direction", "nodes", "node", "looseNodes", "defaultLane", "DEFAULT_SWIMLANE_ID", "toGraphView", "nodeById", "n", "edges", "e", "src", "dst", "allNodes", "groupNodes", "nonGroupNodes", "writeBackToLayoutData", "g", "ordered", "coords", "opts", "nodeMap", "layerGap", "nodeGap", "layerIndex", "layer", "orderIndex", "id", "groupBounds", "topLevelGroups", "group", "children", "minX", "maxX", "minY", "maxY", "child", "cx", "cy", "cw", "ch", "pad", "horizontalPad", "verticalPad", "w", "h", "globalMinY", "globalMaxY", "maxPad", "b", "contentHeight", "verticalMargin", "laneHeight", "centerY", "sortedLanes", "a", "ax", "bx", "laneIds", "centers", "baseWidths", "contentWidth", "count", "laneWidths", "d", "i", "u", "lowerBound", "upperBound", "baseW", "finalWidth", "EDGE_LABEL_LOG_PREFIX", "createEdgeLabelNodes", "data", "nodesToAdd", "layoutOnlyEdges", "nodeById", "node", "edge", "sourceNode", "targetNode", "log", "labelNodeId", "labelLane", "labelNode", "toLabelVirtual", "fromLabelVirtual", "newNodes", "newEdges", "__name", "measuredNodeRect", "node", "cx", "cy", "width", "height", "rectFromCenterSize", "__name", "nodeBoundsInfoFor", "measured", "samePoint", "a", "b", "epsilon", "sameX", "sameY", "isHorizontalSegment", "isVerticalSegment", "overlapLength", "a1", "a2", "b1", "b2", "sameAxisSegmentOverlapLength", "orthogonalSegmentsForPoints", "points", "result", "i", "horizontal", "vertical", "countOrthogonalBends", "segments", "bends", "dedupeConsecutivePoints", "point", "last", "classifyThreeSegmentRoute", "p0", "p1", "p2", "p3", "segmentBoundsOverlapRect", "rect", "buffer", "segMinX", "segMaxX", "segMinY", "segMaxY", "pointInsideRect", "rectContainsRect", "outer", "inner", "rectsOverlap", "inflateRect", "margin", "rectOfNodeBounds", "portForRectSide", "side", "buildOrthogonalPortPath", "src", "srcSide", "dst", "dstSide", "anchor", "srcH", "dstH", "midX", "intX", "intY", "midY", "sameDirSrc", "sameDirDst", "buildSameSideTrackPath", "track", "collectRealNodeBounds", "nodes", "nodeInfoById", "realNodeRects", "info", "collectNodeRectEntries", "labelNodeRects", "entry", "collectLayoutNodeRects", "includeEdgeLabels", "getNodePairGeometry", "edge", "srcId", "dstId", "srcInfo", "dstInfo", "segmentHitsAnyRect", "rects", "excludeIds", "shrink", "orthogonalSegmentsCross", "endpointTolerance", "s1H", "s1V", "s2H", "s2V", "horiz", "vert", "hY", "hX1", "hX2", "vX", "vY1", "vY2", "matchesHorizEndpoint", "matchesVertEndpoint", "sameAxisSegmentsOverlap", "segmentConflictsWithAnyEdge", "edges", "excludeEdge", "skipDegenerateOther", "other", "oa", "ob", "orthogonalSegmentsStrictlyCross", "aHoriz", "aVert", "bHoriz", "bVert", "hXmin", "hXmax", "vYmin", "vYmax", "strictlyBetween", "value", "lo", "hi", "isCollinearIntermediate", "prev", "cur", "next", "simplifyPolylineOnce", "changed", "out", "orthogonalizePolyline", "pts", "cleaned", "curr", "prevPrev", "corner", "deduped", "p", "simplifyPolyline", "work", "guard", "EPS", "INSIDE_EPS", "CORNER_CLEARANCE", "endpointContextFor", "edge", "nodeByIdMap", "minPoints", "candidate", "src", "dst", "rectOfNodeBounds", "__name", "segmentEnterPoint", "outside", "inside", "r", "sameY", "sameX", "y", "clipEndpoint", "points", "rect", "atStart", "step", "outsideIndex", "pointInsideRect", "insideIndex", "entry", "clipEdgeEndpointsToNodeBoundaries", "edges", "context", "next", "simplifyPolyline", "orthogonalizePolyline", "clearStraightEndpointCornerConnections", "snapEndpointToBoundary", "inner", "endpoint", "useApproachSide", "toTop", "firstDistinctAdjacent", "endpointIndex", "index", "samePoint", "cornerClearanceRange", "min", "max", "lo", "hi", "clampToCornerClearance", "value", "intersectRanges", "ranges", "range", "clearanceRangeForSide", "side", "terminalSideForSegment", "adjacent", "yWithin", "xWithin", "isHorizontalSide", "straightClearanceRange", "start", "end", "srcRect", "dstRect", "horizontal", "srcSide", "dstSide", "clearStraightEndpointCornerAxis", "current", "cornerClearedEndpoint", "moveCollinearEndpointRun", "adjusted", "horizontalTerminal", "point", "clearEndpointCornerConnection", "borderSideForSegment", "a", "b", "leavesOutward", "from", "to", "collapseOwnBorderStub", "last", "snapAndCollapseEndpoints", "snapped", "straightCleared", "prepareEdgeEndpointsForRenderer", "input", "dedupeConsecutivePoints", "newPts", "duplicated", "buildNodeMap", "nodes", "node", "__name", "resolveTopLevelGroupId", "nodeById", "parentId", "topLevelGroupId", "parent", "groupDepth", "group", "depth", "boundsForChildren", "children", "minX", "maxX", "minY", "maxY", "child", "cx", "cy", "w", "h", "applyGroupBounds", "bounds", "pad", "recomputeNestedGroupBounds", "groupsByDepth", "a", "b", "mirrorAxis", "layout", "axis", "edges", "contentNodes", "min", "max", "value", "mirror", "titleRect", "edge", "point", "applyBtDirectionTransform", "applyLrDirectionTransform", "direction", "n", "x0", "y0", "titleBandSize", "totalWidth", "totalHeight", "avgWidth", "avgHeight", "horizontalScaleFactor", "newX", "newY", "e", "p", "laneNodes", "childrenByLane", "laneId", "bucket", "maxPad", "lane", "laneBounds", "globalMinXChild", "globalMaxXChild", "fullContentWidth", "horizontalMargin", "bodyWidth", "laneWidth", "laneLeft", "centerX", "verticalMargin", "i", "curr", "laneTop", "laneBottom", "next", "laneHeight", "centerY", "EPS", "MIN_PORT_SPACING", "PORT_SHIFT", "TRY_DELTAS", "portSwapToLShape", "edges", "nodes", "nodeInfoById", "realNodeRects", "collectRealNodeBounds", "edge", "pts", "route", "classifyThreeSegmentRoute", "dedupeConsecutivePoints", "p3", "isHVH", "nodePair", "getNodePairGeometry", "srcId", "dstId", "srcInfo", "dstInfo", "collinearX", "collinearY", "newPts", "srcRect", "delta", "np0", "np1", "np2", "newSrcY", "newSrcX", "firstSegDegenerate", "samePoint", "secondSegDegenerate", "segmentHitsAnyRect", "firstSegConflicts", "segmentConflictsWithAnyEdge", "secondSegConflicts", "__name", "collapseShortTerminalStub", "edges", "nodeByIdMap", "realNodeRects", "labelRects", "collectNodeRectEntries", "edge", "rawPts", "pts", "dedupeConsecutivePoints", "nLast", "endPt", "penultPt", "prevPt", "lastDx", "lastDy", "lastLen", "penultDx", "penultDy", "lastIsHoriz", "isHorizontalSegment", "lastIsVert", "isVerticalSegment", "penultIsHoriz", "penultIsVert", "dstId", "srcId", "dst", "dstCx", "dstCy", "dstRect", "rectOfNodeBounds", "newPrev", "newEnd", "approachFromBelow", "approachFromLeft", "segmentHitsAnyRect", "src", "srcRect", "pointInsideRect", "ownSegmentKey", "__name", "a", "b", "selfSegments", "i", "segmentCrossesOtherEdge", "from", "to", "other", "oPts", "orthogonalSegmentsStrictlyCross", "beforePrev", "endpointIds", "id", "newPts", "labelId", "labelNode", "lw", "lh", "bestMidX", "bestMidY", "bestLen", "segLen", "isHoriz", "sameY", "isVert", "sameX", "EPS_LOCAL", "MIN_SHARED", "segmentsFor", "orthogonalSegmentsForPoints", "orthogonallyAligned", "__name", "a", "b", "sameX", "sameY", "separateSharedRenderedTerminalLanes", "edges", "nodeByIdMap", "rectIntersect", "node", "point", "x", "y", "dx", "dy", "w", "h", "terminalLaneFor", "edge", "atStart", "points", "dedupeConsecutivePoints", "nodeId", "rect", "rectOfNodeBounds", "endpoint", "adjacent", "boundary", "railEnd", "projectedOverlapLength", "sameTerminalFace", "exactTerminalLaneConflict", "nearTerminalLaneConflict", "shared", "faceSpan", "shiftedCandidate", "lane", "shift", "shiftedBoundary", "shiftedRailEnd", "railEndIsAdjacent", "samePoint", "rest", "next", "before", "previous", "laneIsStraightCollinearConnector", "startId", "endId", "start", "end", "startX", "startY", "endX", "endY", "shifts", "iteration", "lanes", "fixed", "i", "j", "first", "second", "fixingNearConflict", "candidates", "aPreservesStraight", "bPreservesStraight", "candidate", "nextLane", "other", "collapseRedundantRectangularDoglegs", "realNodeRects", "labelRects", "collectNodeRectEntries", "candidateIsSafe", "sourceId", "targetId", "candidateSegments", "endpointIds", "id", "segment", "segmentHitsAnyRect", "otherPoints", "candidateSegment", "otherSegment", "sameAxisSegmentOverlapLength", "orthogonalSegmentsStrictlyCross", "withoutDogleg", "p0", "p1", "p2", "p3", "p4", "terminalVerticalDogleg", "isHorizontalSegment", "isVerticalSegment", "terminalHorizontalDogleg", "p5", "verticalDogleg", "horizontalDogleg", "liftObstacleHuggingSameSideRails", "visibleEdges", "pointsFor", "replacementEdge", "replacement", "strictCrossingCount", "count", "firstSegments", "secondSegments", "firstSegment", "secondSegment", "middleRail", "segments", "middle", "blockingRectsFor", "rail", "entry", "overlapLength", "candidateByMovingRail", "coord", "simplified", "simplifyPolyline", "currentCrossings", "blockers", "coords", "liftTopLaneTitleBandsAboveRails", "validTitleRect", "topLaneTitleFor", "rawDirection", "direction", "height", "titleWidth", "titleHeight", "horizontalSegmentIntersectsTitle", "topDelta", "shiftLeftLaneTitleBandsLeftOfRails", "leftLaneTitleFor", "width", "verticalSegmentIntersectsTitle", "leftDelta", "segmentLeft", "swapDestinationTerminalTailsToReduceCrossings", "replacementPointsFor", "replacements", "crossingCount", "totalBends", "sum", "countOrthogonalBends", "terminalTailFor", "tailStart", "terminal", "candidateWithDestinationTail", "tail", "firstTurn", "connector", "pathHasNodeHit", "path", "pathHasSharedTrack", "edgesByDestination", "result", "dstId", "bucket", "currentBends", "bestReplacements", "bestCrossings", "bestBends", "destinationEdges", "firstTail", "secondTail", "firstCandidate", "secondCandidate", "candidateCrossings", "candidateBends", "reassignCrossingExternalRailChannels", "endpointRectsFor", "srcId", "srcNode", "dstNode", "src", "dst", "externalRailForSegment", "endpointRects", "leftBound", "rightBound", "side", "topBound", "bottomBound", "collectExternalRails", "rails", "railsInteract", "connectedComponents", "seen", "queue", "component", "current", "uniqueCoordsFor", "min", "max", "coordinateAssignmentsFor", "assignments", "used", "visit", "index", "assignment", "replacementsForAssignment", "draftByEdge", "firstChanged", "bestDisplacement", "candidateDisplacement", "shortcutRedundantOrthogonalJogs", "pathLength", "segmentRunsAlongRectBorder", "rects", "shortcutCandidatesAt", "isHVH", "isVHV", "corners", "rawCandidates", "corner", "key", "bestEdge", "bestPath", "bestLength", "currentPoints", "currentLength", "candidateLength", "resolveRenderedOrthogonalCrossings", "realNodes", "cx", "cy", "nodeInfoById", "sides", "outsideTracks", "edgeIndex", "outwardTracksForSide", "outward", "tracks", "channel", "crossingCountBetweenSegments", "crossingCountBetweenPaths", "crossingSnapshot", "pairs", "edgeSet", "edgeOrder", "addEdge", "firstPoints", "pairCount", "crossingCountWithReplacements", "changed", "currentAffected", "pair", "replacementAffected", "crossingComponents", "snapshot", "neighbors", "firstNeighbors", "secondNeighbors", "components", "endpointIdsFor", "pairSearchGroups", "groups", "componentSet", "componentEndpointIds", "group", "crossingCountWithSingleReplacement", "currentCrossingsByEdge", "totalLength", "pathHasSegmentConflict", "pathSegments", "pathHitsNode", "pushOrthogonalCandidate", "sideIsHorizontal", "localTrackForSameSide", "addSameSideCandidates", "srcSide", "trackSeeds", "seed", "buildSameSideTrackPath", "addHorizontalToVerticalCandidates", "dstSide", "xTrack", "yTrack", "addVerticalToHorizontalCandidates", "addHorizontalPairCandidates", "yTracks", "srcTrack", "dstTrack", "addVerticalPairCandidates", "xTracks", "dedupeCandidatePaths", "buildCandidatesForSides", "base", "buildOrthogonalPortPath", "srcHorizontal", "dstHorizontal", "addVerticalDepartureOuterTrackCandidates", "departure", "externalXTracks", "externalYTracks", "portForRectSide", "targetYTracks", "track", "targetTrack", "addHorizontalDepartureOuterTrackCandidates", "targetXTracks", "terminalPreservingOuterTrackCandidates", "candidatePathsFor", "srcPort", "currentSegmentsByEdge", "sharedTrackConflictsFor", "baseSegments", "conflicts", "otherSegments", "pairCandidatesFor", "crossingCountByEdge", "crossings", "pairCrossingCount", "firstEdge", "secondEdge", "conflictsOnlyWith", "conflict", "candidatesShareTrack", "pairCandidatesAreCompatible", "scorePairReplacement", "context", "pairScoreIsBetter", "best", "bestScoreForOptionPair", "pairBest", "score", "bestPairedReplacement", "baseBendsByEdge", "baseLengthByEdge", "optionsByEdge", "scoringContext", "crossingEdgeSet", "options", "option", "currentEdgeBends", "candidateHitsNode", "candidateHasSegmentConflict", "pairedReplacement", "EPS", "MIN_SHARED", "simplifyDetouredEdges", "edges", "nodes", "nodeInfoById", "realNodeRects", "collectRealNodeBounds", "sides", "ANCHOR", "outsideTracks", "node", "buildOrthogonalPathCandidates", "__name", "src", "srcSide", "dst", "dstSide", "paths", "base", "buildOrthogonalPortPath", "buildSameSideTrackPath", "pathHitsNode", "pts", "excludeIds", "i", "a", "b", "segmentHitsAnyRect", "pathConflictCount", "path", "currentEdge", "includeIncidentEdges", "conflicts", "pathSegments", "orthogonalSegmentsForPoints", "currentStart", "currentEnd", "other", "otherStart", "otherEnd", "otherPts", "pathSegment", "otherSegment", "orthogonalSegmentsCross", "sameAxisSegmentOverlapLength", "BEND_THRESHOLD", "nearestSideOfRect", "pt", "info", "dTop", "dBottom", "dLeft", "dRight", "best", "bestDist", "faceClaims", "addFaceClaim", "nodeId", "side", "edgeId", "claims", "e", "eId", "startId", "endId", "faceIsClaimed", "ignoreEdgeId", "c", "edge", "currentBends", "countOrthogonalBends", "srcId", "dstId", "srcInfo", "dstInfo", "currentCrossingConflicts", "currentNonIncidentConflicts", "bestPath", "bestCrossingConflicts", "bestBends", "srcPort", "portForRectSide", "dstPort", "pathBends", "pathCrossingConflicts", "refreshSrc", "refreshDst", "EPS", "MARKER_CLEARANCE_LENGTH", "MARKER_CLEARANCE_HALF_WIDTH", "markerClearanceRectFor", "pts", "atStart", "terminalIndex", "step", "tip", "inner", "dx", "dy", "x2", "y2", "__name", "normalizeRect", "rect", "labelOverlapsOwnMarker", "visiblePts", "dedupeConsecutivePoints", "startMarker", "endMarker", "marker", "rectsOverlap", "anchorLabelsToPolyline", "edges", "nodeByIdMap", "allEdgeSegments", "other", "i", "foreignNodeRects", "laneGroups", "n", "isGroup", "parentId", "rectOfNodeBounds", "LABEL_PLACEMENT_BUFFER", "LABEL_LANE_MARGIN", "LABEL_ENDPOINT_CLEARANCE", "labelOverlapsForeignNode", "labelId", "buffered", "inflateRect", "nodeId", "nr", "labelOverlapsForeignEdge", "edgeId", "s", "segmentBoundsOverlapRect", "labelOverlapsAnything", "placedLabelRects", "findContainingLane", "id", "laneRect", "rectContainsRect", "overlapsPlacedLabel", "placed", "edge", "labelNode", "lw", "lh", "segments", "a", "b", "middleSegments", "poolBase", "labelLongAxis", "rankSegments", "pool", "aLongAxis", "bLongAxis", "aFits", "bFits", "firstVisibleSegment", "lastVisibleSegment", "ALONG_SEGMENT_TS", "anchorAtT", "seg", "t", "clamp", "value", "min", "max", "pointInsideRectInclusive", "point", "placementForAnchor", "anchor", "centeredRect", "rectFromCenterSize", "centeredLane", "containingLane", "minX", "maxX", "minY", "maxY", "clampedAnchor", "clampedRect", "distanceAlongSegment", "endpoint", "labelClearsTerminalEndpoints", "requiredDistance", "start", "end", "tryPool", "rankedPool", "placement", "findLaneContainingFallback", "requireEndpointClearance", "allowForeignEdgeOverlap", "chosen", "chosenRect", "priorIdx", "EPS", "MIN_PORT_SPACING", "PORT_SHIFT", "LABEL_CLEARANCE_BUFFER", "pairKey", "a", "b", "__name", "straightenCollinearSiblingDetours", "edges", "nodes", "nodeInfoById", "realNodeRects", "collectRealNodeBounds", "labelDimById", "n", "id", "labelClearanceFor", "thisEdge", "thisSrcId", "thisDstId", "axis", "targetPair", "maxHalf", "consider", "labelId", "dim", "half", "other", "oSrc", "oDst", "edge", "pts", "classifyThreeSegmentRoute", "nodePair", "getNodePairGeometry", "srcId", "dstId", "srcInfo", "dstInfo", "collinearX", "collinearY", "targetSrc", "targetDst", "dstBelow", "dstEast", "segmentHitsAnyRect", "labelShift", "effectiveShift", "deltas", "delta", "shiftedSrc", "shiftedDst", "segmentConflictsWithAnyEdge", "nudgeSharedInteriorSubpaths", "edges", "nodeByIdMap", "realNodeRects", "labelRects", "collectNodeRectEntries", "segmentsFor", "__name", "edge", "points", "orthogonalSegmentsForPoints", "segment", "allSegments", "result", "dedupeConsecutivePoints", "hasCrowdedParallelTrack", "a", "b", "overlapLength", "candidateIsSafe", "candidate", "sourceId", "targetId", "candidateSegments", "endpointIds", "id", "ownLabelIds", "segmentHitsAnyRect", "other", "otherPoints", "candidateSegment", "otherSegment", "orthogonalSegmentsStrictlyCross", "shiftedCandidate", "shift", "p", "nodeCenter", "node", "rect", "sourceDetourContextFor", "sourceNode", "targetNode", "sourceRect", "rectOfNodeBounds", "targetRect", "tail", "verticalSourceDetour", "sourceCenter", "targetCenter", "targetBelow", "sourcePortY", "stubY", "railX", "horizontalSourceDetour", "targetRight", "sourcePortX", "stubX", "railY", "sourceDetourCandidate", "context", "shifts", "iteration", "segments", "fixed", "i", "j", "first", "second", "candidates", "direct", "detoured", "segmentsIntersect", "p1", "p2", "p3", "p4", "d1x", "d1y", "d2x", "d2y", "cross", "dx", "dy", "t", "u", "eps", "__name", "validateSwimlanesLayout", "layout", "nodes", "edges", "issues", "nodeRects", "collectLayoutNodeRects", "epsilon", "edgeSegments", "edge", "points", "edgeStart", "edgeEnd", "ownLabelId", "edgeId", "rect", "i", "segmentBoundsOverlapRect", "crossingPairs", "j", "a", "b", "pairKey", "overlaps", "crossings", "log", "issue", "postProcessSwimlaneLayout", "layout", "direction", "nodes", "edges", "contentNodes", "n", "applyLrDirectionTransform", "applyBtDirectionTransform", "edge", "pts", "simplifyPolyline", "orthogonalizePolyline", "simplifyDetouredEdges", "straightenCollinearSiblingDetours", "portSwapToLShape", "nodeByIdMap", "anchorLabelsToPolyline", "clipEdgeEndpointsToNodeBoundaries", "collapseShortTerminalStub", "nudgeSharedInteriorSubpaths", "separateSharedRenderedTerminalLanes", "collapseRedundantRectangularDoglegs", "liftObstacleHuggingSameSideRails", "swapDestinationTerminalTailsToReduceCrossings", "finalizeRenderedEdges", "__name", "resolveRenderedOrthogonalCrossings", "reassignCrossingExternalRailChannels", "shortcutRedundantOrthogonalJogs", "prepareEdgeEndpointsForRenderer", "liftTopLaneTitleBandsAboveRails", "shiftLeftLaneTitleBandsLeftOfRails", "normalizeGraph", "g", "nodeById", "seen", "edges", "e", "key", "__name", "incoming", "v", "buildSuccessorMap", "g", "succs", "v", "e", "__name", "buildSortedSuccessorMap", "successors", "a", "b", "buildInDegreeMap", "indeg", "sortedZeroInDegreeNodes", "degree", "id", "buildPredecessorSuccessorMaps", "includeEdge", "preds", "buildLayersFromRanks", "order", "rankOf", "opts", "maxRank", "layers", "topoSortIfAcyclic", "g", "indeg", "buildInDegreeMap", "queue", "sortedZeroInDegreeNodes", "order", "adj", "buildSortedSuccessorMap", "u", "v", "i", "__name", "buildLayerIndex", "layer", "m", "index", "id", "countInversions", "values", "tmp", "count", "left", "right", "mid", "inversions", "j", "k", "t", "removeCycles_DFS", "g", "gn", "normalizeGraph", "adj", "v", "e", "arr", "a", "b", "color", "reversed", "dfs", "__name", "u", "nodesSorted", "toReverse", "acycEdges", "buildTopLaneMap", "g", "cache", "resolve", "__name", "id", "node", "parentId", "lane", "createTopLaneResolver", "topLaneMap", "buildTopLaneOrder", "lanes", "resolveTopLaneOrder", "preferredOrder", "sourceOrder", "sourceLaneIds", "seen", "resolved", "laneId", "PRECISION", "LAYERING", "COORDINATES", "buildDrivingTree", "graph", "opts", "g", "normalizeGraph", "laneOf", "rankHint", "preds", "buildPredecessorSuccessorMaps", "arr", "a", "b", "topoOrder", "topoSortIfAcyclic", "topoIndex", "idx", "id", "parent", "children", "node", "candidates", "p", "chosen", "chooseParent", "rootSet", "roots", "ta", "tb", "adjacency", "buildAdjacency", "adjacencyList", "set", "componentOf", "assignComponents", "blocks", "computeBlocks", "nodeBlocks", "block", "list", "preorder", "postorder", "seen", "walk", "__name", "child", "root", "ctx", "laneNode", "laneA", "laneB", "sameLaneA", "sameLaneB", "rankA", "rankB", "idxA", "idxB", "e", "componentId", "stack", "cur", "next", "discovery", "low", "edgeStack", "time", "visit", "popBlock", "u", "v", "edges", "nodes", "edge", "computeSubtreeCrossCounts", "g", "rankOf", "tree", "nodes", "indexOf", "i", "node", "n", "parentIdx", "depth", "queue", "seen", "parentId", "idx", "current", "currentIdx", "childList", "child", "childIdx", "maxLog", "up", "k", "prev", "lcaIndex", "__name", "aIdx", "bIdx", "diff", "upA", "upB", "ownCounts", "edge", "src", "dst", "ru", "rv", "upperIdx", "lowerIdx", "lca", "bucket", "layer", "crossCounts", "mergeInto", "target", "source", "value", "visited", "dfs", "base", "accumulator", "childMap", "parentLayer", "map", "childLayer", "root", "annotateMinimumLayers", "nodes", "children", "rankOf", "minLayer", "annotate", "__name", "node", "minL", "childList", "compareByRankThenId", "child", "childMin", "a", "b", "ra", "rb", "emitNodesInTreeOrder", "roots", "allNodes", "orderChildren", "maxRank", "r", "layers", "emitted", "emit", "layer", "root", "deduplicateLayers", "result", "seen", "deduped", "id", "createChildOrderer", "children", "rankOf", "crossCounts", "minLayer", "node", "raw", "layer", "future", "present", "crossMap", "child", "minL", "a", "b", "ca", "cb", "ma", "mb", "item", "__name", "buildMultitreeLayerOrder", "g", "laneOf", "tree", "buildDrivingTree", "roots", "computeSubtreeCrossCounts", "rootsSorted", "compareByRankThenId", "annotateMinimumLayers", "orderChildren", "layers", "emitNodesInTreeOrder", "deduplicateLayers", "countCrossingsBetweenAdjacent", "upper", "lower", "edges", "upperSet", "lowerSet", "li", "buildLayerIndex", "vs", "e", "countInversions", "__name", "totalCrossings", "layers", "rankOf", "expanded", "ru", "rv", "rUpper", "rLower", "L", "sum", "i", "optimizeRanksByCrossings", "g", "initialRank", "preds", "buildPredecessorSuccessorMaps", "laneOf", "createTopLaneResolver", "buildMultitreeLayerOrder", "best", "maxPasses", "LAYERING", "pass", "changed", "nodesByRank", "a", "b", "v", "r", "lb", "u", "old", "trialLayers", "score", "adjustCrossLaneSources", "g", "rankOf", "topLaneOf", "createTopLaneResolver", "nodesByRank", "a", "b", "v", "laneV", "outEdges", "e", "hasSameLaneSucc", "crossLaneCount", "laneDst", "crossLaneIncoming", "hasSameLanePred", "laneSrc", "current", "target", "lb", "newRank", "__name", "assignLayers_LongestPath", "gAcyclic", "opts", "g", "normalizeGraph", "order", "topoSortIfAcyclic", "compact", "topLaneOf", "createTopLaneResolver", "rankOf", "v", "incAll", "incoming", "inc", "e", "laneSrc", "laneDst", "u", "laneU", "laneV", "mx", "optimizeRanksByCrossings", "adjustCrossLaneSources", "buildMultitreeLayerOrder", "__name", "assignLayers_Gravity", "gAcyclic", "opts", "g", "normalizeGraph", "rankOf", "assignLayers_LongestPath", "topLaneOf", "createTopLaneResolver", "preds", "succs", "buildPredecessorSuccessorMaps", "e", "laneSrc", "laneDst", "order", "topoSortIfAcyclic", "revOrder", "clampFeasible", "__name", "v", "desired", "lb", "u", "ub", "s", "w", "iters", "LAYERING", "relaxOrder", "nodeOrder", "changed", "ps", "ss", "predAvg", "a", "succAvg", "clamped", "it", "forwardChanged", "backwardChanged", "buildLayersFromRanks", "topoSortByGenerationIfAcyclic", "g", "indeg", "buildInDegreeMap", "adj", "buildSortedSuccessorMap", "frontier", "sortedZeroInDegreeNodes", "order", "nextFrontier", "u", "v", "a", "b", "__name", "assignLayers_LaneAwareCompact", "gAcyclic", "opts", "normalizeGraph", "topoSortIfAcyclic", "topLaneOf", "createTopLaneResolver", "laneOf", "id", "rankOf", "nextFree", "edgeWeight", "preds", "incoming", "base", "e", "ru", "lane", "nf", "L", "buildLayersFromRanks", "makeProperLayering", "layering", "gAcyclic", "g", "normalizeGraph", "rankOf", "layers", "l", "dummy", "dummySeq", "nodeById", "addDummyAt", "__name", "L", "id", "dn", "edgesSorted", "a", "b", "newEdges", "e", "rU", "rV", "prev", "k", "d", "lastIndex", "graphWithDummies", "median", "values", "n", "a", "x", "y", "__name", "barycenter", "acc", "v", "neighborPositionsFor", "targetNodes", "fixedIndex", "edges", "direction", "neighborPositions", "e", "currentOrderTieBreak", "b", "currentLayerIndex", "ia", "ib", "countCrossingsBetweenAdjacent", "upper", "lower", "upperSet", "lowerSet", "upperIndex", "buildLayerIndex", "lowerIndex", "pairs", "vs", "p", "countInversions", "sortByHeuristic", "nodes", "neighborPositions", "currentLayerIndex", "a", "b", "sa", "median", "sb", "currentOrderTieBreak", "__name", "reorderLayer", "fixedLayer", "targetLayer", "edges", "direction", "topLaneOf", "laneOrder", "fixedIndex", "buildLayerIndex", "currIndex", "neighborPositionsFor", "byLane", "id", "lane", "arr", "result", "nodesInLane", "sorted", "nullNodes", "nid", "bc", "barycenter", "bestIdx", "i", "rid", "rBc", "transposeImprove", "upper", "current", "next", "best", "upperSet", "layerSet", "nextSet", "edgesIn", "e", "edgesOut", "crossingScore", "order", "score", "countCrossingsBetweenAdjacent", "laneOf", "improved", "bestScore", "laneA", "laneB", "prev", "nextScore", "orderLayers", "layering", "gWithDummies", "opts", "layers", "l", "createTopLaneResolver", "resolveTopLaneOrder", "s", "assignCoordinates", "ordered", "gWithDummies", "opts", "layerGap", "COORDINATES", "nodeGap", "laneGap", "direction", "isHorizontal", "layers", "x", "y", "getNode", "__name", "id", "getWidth", "getHeight", "topLaneOf", "createTopLaneResolver", "laneOrderGlobal", "resolveTopLaneOrder", "layerHeights", "layer", "m", "v", "extraLayerGaps", "i", "thisLayerMaxWidth", "nextLayerMaxWidth", "thisLayerMaxHeight", "nextLayerMaxHeight", "normalSpacing", "requiredSpacing", "extraNeeded", "lanesUsedSet", "hasNullLane", "lanesUsed", "L", "laneOrderColumns", "laneWidth", "perLane", "nullIds", "ids", "total", "s", "totalNull", "centerX", "widths", "cursor", "a", "b", "w", "cx", "yOffset", "li", "layerH", "byLane", "laneId", "arr", "nodesInLane", "start", "extraGap", "byRef", "e", "rid", "chainEdges", "ref", "src", "dst", "midX", "involved", "vid", "AUTOMATIC_LANE_ORDERING_RESTARTS", "hashString", "input", "hash", "i", "__name", "mulberry32", "seed", "state", "t", "deterministicShuffle", "order", "shuffled", "random", "j", "sourceDistance", "sourceIndex", "distance", "index", "laneId", "laneArrangementCost", "weights", "position", "cost", "a", "b", "weight", "ai", "bi", "buildWeightedLaneEdges", "g", "sourceOrder", "buildTopLaneOrder", "topLaneOf", "createTopLaneResolver", "edge", "src", "dst", "laneA", "laneB", "ia", "ib", "key", "existing", "greedySwitch", "startOrder", "changed", "sweeps", "maxSweeps", "nextCost", "isBetterCandidate", "candidate", "best", "seedForRestart", "restartIndex", "weightSignature", "optimizeTopLaneOrder", "opts", "restarts", "start", "sugiyamaLayout", "g", "opts", "ignoreCrossLaneEdges", "optimizeRanksByCrossings", "g0", "normalizeGraph", "laneOrder", "optimizeTopLaneOrder", "AUTOMATIC_LANE_ORDERING_RESTARTS", "cycleRes", "removeCycles_DFS", "gAcyclic", "layering", "assignLayers_LaneAwareCompact", "LAYERING", "assignLayers_Gravity", "properLayering", "graphWithDummies", "makeProperLayering", "ordered", "orderLayers", "coordinates", "assignCoordinates", "__name", "EPS", "PRECISION", "NODE_PADDING", "HORIZONTAL_PIPE_MARGIN", "VERTICAL_PIPE_MARGIN", "ROUTING_MARGIN", "ANCHOR_OFFSET", "TRACK_SPACING", "chooseOrthogonalSide", "node", "target", "fallback", "cx", "cy", "dx", "dy", "absDx", "absDy", "__name", "sharedLineEndpointCoord", "line", "nextLine", "pointOnLine", "along", "routeEdgesOrthogonal", "data", "direction", "nodes", "originalEdges", "edges", "oe", "nodeById", "laneByNodeId", "pipes", "isLR", "n", "topLevelGroups", "group", "lane", "assignLane", "child", "obstacles", "w", "h", "x", "y", "padding", "getOrAddPipe", "orientation", "coord", "spanMin", "spanMax", "pipe", "p", "portForSide", "side", "getOrthogonalPort", "isSource", "allRoutedSegments", "edgeSegmentIndices", "straightIntraLaneEdges", "CROSSING_PENALTY", "crossingPenalty", "edgeIdx", "from", "to", "isHorizontal", "isVertical", "penalties", "minX", "maxX", "seg", "minY", "maxY", "routingOrder", "edge", "idx", "srcNode", "dstNode", "srcLane", "dstLane", "crossLane", "a", "b", "aDist", "bDist", "entry", "isSegmentBlocked", "p1", "p2", "excludeStart", "excludeEnd", "segMinX", "segMaxX", "segMinY", "segMaxY", "obs", "portGroups", "incidentEdgeTotals", "determineSide", "sideInfoByIdx", "i", "e", "src", "dst", "preferenceStrength", "info", "secondarySide", "sourceSideGroups", "key", "sideLoad", "loadKey", "nodeId", "sa", "sb", "g", "secondary", "primaryLoad", "secondaryLoad", "isDiamondNode", "shape", "inSidesByNode", "inSides", "srcId", "dstId", "srcSide", "dstSide", "srcKey", "dstCoord", "dstKey", "srcCoord", "portOffsets", "MIN_PORT_SPACING", "parts", "role", "sideLength", "effectiveLength", "spacing", "startOffset", "j", "element", "offset", "offsetKey", "edgeHasLabelNode", "faceHasLabelNode", "applyPortOffset", "basePort", "portsForEdge", "edgeIndex", "sideInfo", "srcTarget", "dstTarget", "pSrcPort", "pDstPort", "srcOffset", "dstOffset", "srcPortSide", "dstPortSide", "pSrcAnchor", "pDstAnchor", "srcPortIsVertical", "dstPortIsVertical", "isBottom", "isRight", "isPointInObstacle", "pt", "excludeNodeIds", "obstacleDetour", "port", "opposite", "portIsVertical", "leavesPositiveSide", "goDown", "srcHandleWaypoints", "endpointIds", "srcCheck", "detour", "gapY", "gapX", "dstHandleWaypoints", "dstCheck", "hpMargin", "anchorsSameX", "anchorsSameY", "hasPortOffset", "srcFaceTotal", "dstFaceTotal", "faceContested", "srcIncidentTotal", "dstIncidentTotal", "contestedFaceHasLabel", "srcContestAllowsCenteredStraight", "dstContestAllowsCenteredStraight", "fastPathOrientation", "fastPathCoord", "fastPathFrom", "fastPathTo", "fastPathPipe", "srcPipe", "dstPipe", "bbMinX", "bbMaxX", "bbMinY", "bbMaxY", "pathMinX", "pathMaxX", "pathMinY", "pathMaxY", "hMargin", "vMargin", "hPipes", "vPipes", "getKey", "startKey", "endKey", "gScore", "cameFrom", "arrivalDir", "openSet", "openList", "foundPath", "checkSegmentBlocked", "cornerHV", "seg1HV_blocked", "seg2HV_blocked", "pathHV_blocked", "cornerVH", "seg1VH_blocked", "seg2VH_blocked", "current", "currKey", "currPt", "prev", "sortedVPipes", "vIdx", "hPipesSorted", "hIdx", "neighbors", "neighbor", "nKey", "dist", "penalty", "dirPenalty", "destDx", "destDy", "moveDx", "moveDy", "bendPenalty", "currentDir", "moveDir", "stepCost", "tentativeG", "start", "end", "wentRight", "wentLeft", "margin", "pathX", "detourObstacles", "visualMaxX", "obsCenterX", "visualRight", "visualMinX", "visualLeft", "findBestReturnY", "detourX", "goingDown", "relevantObs", "obsInXRange", "obsInYRange", "filteredObs", "obsAtDetourX", "bestY", "trySimplifyWithDetourX", "corner1", "corner2", "corner3", "seg1Blocked", "seg2Blocked", "seg3Blocked", "seg4Blocked", "simplified", "fullPoints", "C", "B", "A", "isHoriz", "isVert", "signAB", "signAC", "k", "curr", "next", "dir1", "dir2", "rSeg", "segmentsOverlap", "s1", "s2", "trySwapSegmentsAcrossTracks", "t1", "t2", "canS1GoT2", "r", "canS2GoT1", "createNewTrack", "moveSegmentToTrack", "trackIdx", "oldTrack", "moveSegmentChainToTrack", "indices", "s", "getAdjacentSegmentsAlongEdge", "idxInList", "adj", "haveAnyCrossing", "segA", "segB", "v", "findAvailableTrack", "track", "segmentsConflict", "adj1", "adj2", "a1", "a2", "resolveTrackConflict", "move", "avail", "resolveHandleConflicts", "handles", "crossings", "h1", "h2", "destInfoCache", "getDestInfo", "base", "dest", "candidateA", "candidateB", "deviation", "fixSourceHandleCrossings", "edgesBySource", "getEdgeDistance", "grp", "infoA", "infoB", "distA", "distB", "lenA", "lenB", "idxA", "idxB", "ei", "fixTargetHandleCrossings", "edgesByTarget", "getDist", "scoreA", "scoreB", "fixPipeCrossings", "pipeSegments", "t", "ref", "ix", "iterations", "MAX_ITER", "changed", "segmentCoords", "segments", "clusters", "currentCluster", "clusterEnd", "cluster", "usedTracks", "trackScores", "leftTracks", "rightTracks", "neutralTracks", "assignCoord", "trackIndex", "effectiveCoord", "leftCount", "bestTrack", "leftIdx", "rightIdx", "neutralAssigned", "dir", "magnitude", "rightCount", "newPoints", "lines", "prevPt", "prevAlong", "prevTrackCoord", "hasNextLine", "junction", "endAlong", "last", "filtered", "re", "orig", "nodeBoundaryClamp", "left", "right", "top", "bottom", "dLeft", "dRight", "dTop", "dBottom", "minD", "pts", "getSwimlaneDirection", "data4Layout", "__name", "runSwimlaneLayoutCore", "g", "toGraphView", "nodeGap", "layerGap", "ignoreCrossLaneEdges", "optimizeRanksByCrossings", "automaticLaneOrdering", "direction", "ordered", "coordinates", "sugiyamaLayout", "writeBackToLayoutData", "edge", "routeEdgesOrthogonal", "postProcessSwimlaneLayout", "validateSwimlanesLayout", "render", "data4Layout", "svg", "element", "markers_default", "clear", "prepareLayoutForSwimlanes", "transformedData", "createEdgeLabelNodes", "groups", "createGraphWithElements", "runSwimlaneLayoutCore", "adjustLayout", "__name"]
}
