@diagrammo/dgmo 0.31.0 → 0.32.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (72) hide show
  1. package/.cursorrules +4 -1
  2. package/.github/copilot-instructions.md +4 -1
  3. package/.windsurfrules +4 -1
  4. package/SKILL.md +4 -1
  5. package/dist/advanced.cjs +1297 -358
  6. package/dist/advanced.d.cts +117 -15
  7. package/dist/advanced.d.ts +117 -15
  8. package/dist/advanced.js +1291 -358
  9. package/dist/auto.cjs +1087 -316
  10. package/dist/auto.js +98 -98
  11. package/dist/auto.mjs +1087 -316
  12. package/dist/cli.cjs +140 -140
  13. package/dist/index.cjs +1090 -397
  14. package/dist/index.js +1090 -397
  15. package/docs/ai-integration.md +4 -1
  16. package/docs/language-reference.md +282 -27
  17. package/gallery/fixtures/boxes-and-lines.dgmo +2 -2
  18. package/gallery/fixtures/c4-full.dgmo +4 -5
  19. package/gallery/fixtures/c4.dgmo +2 -3
  20. package/package.json +7 -1
  21. package/src/advanced.ts +7 -0
  22. package/src/boxes-and-lines/focus.ts +257 -0
  23. package/src/boxes-and-lines/layout-search.ts +131 -65
  24. package/src/boxes-and-lines/layout.ts +7 -1
  25. package/src/boxes-and-lines/parser.ts +19 -4
  26. package/src/boxes-and-lines/renderer.ts +54 -3
  27. package/src/c4/parser.ts +8 -7
  28. package/src/chart-type-registry.ts +129 -4
  29. package/src/chart-types.ts +4 -4
  30. package/src/chart.ts +18 -1
  31. package/src/colors.ts +225 -2
  32. package/src/cycle/parser.ts +2 -7
  33. package/src/d3.ts +67 -54
  34. package/src/diagnostics.ts +17 -0
  35. package/src/dimensions.ts +9 -13
  36. package/src/echarts.ts +42 -14
  37. package/src/er/parser.ts +6 -1
  38. package/src/gantt/parser.ts +44 -7
  39. package/src/graph/flowchart-parser.ts +77 -3
  40. package/src/graph/state-renderer.ts +2 -2
  41. package/src/infra/parser.ts +80 -0
  42. package/src/journey-map/parser.ts +8 -7
  43. package/src/kanban/parser.ts +8 -7
  44. package/src/map/context-labels.ts +134 -27
  45. package/src/map/geo.ts +10 -2
  46. package/src/map/layout.ts +259 -4
  47. package/src/map/parser.ts +2 -0
  48. package/src/map/renderer.ts +22 -11
  49. package/src/map/resolver.ts +68 -19
  50. package/src/mindmap/parser.ts +15 -7
  51. package/src/mindmap/renderer.ts +50 -12
  52. package/src/org/parser.ts +8 -7
  53. package/src/org/renderer.ts +22 -7
  54. package/src/palettes/color-utils.ts +12 -2
  55. package/src/palettes/index.ts +1 -0
  56. package/src/pert/renderer.ts +2 -2
  57. package/src/pyramid/parser.ts +2 -7
  58. package/src/quadrant/renderer.ts +2 -2
  59. package/src/raci/parser.ts +2 -7
  60. package/src/raci/renderer.ts +4 -4
  61. package/src/ring/parser.ts +2 -7
  62. package/src/sequence/parser.ts +18 -7
  63. package/src/sequence/renderer.ts +4 -4
  64. package/src/sitemap/parser.ts +8 -7
  65. package/src/sitemap/renderer.ts +2 -2
  66. package/src/tech-radar/parser.ts +2 -7
  67. package/src/timeline/renderer.ts +15 -5
  68. package/src/utils/parsing.ts +13 -1
  69. package/src/utils/scaling.ts +38 -81
  70. package/src/utils/tag-groups.ts +38 -0
  71. package/src/visualizations/parse.ts +6 -1
  72. package/src/wireframe/parser.ts +6 -1
package/dist/advanced.cjs CHANGED
@@ -40,6 +40,14 @@ function makeDgmoError(line11, message, severity = "error", code) {
40
40
  function formatDgmoError(err) {
41
41
  return err.line > 0 ? `Line ${err.line}: ${err.message}` : err.message;
42
42
  }
43
+ function makeFail(result) {
44
+ return (line11, message) => {
45
+ const diag = makeDgmoError(line11, message);
46
+ result.diagnostics.push(diag);
47
+ result.error = formatDgmoError(diag);
48
+ return result;
49
+ };
50
+ }
43
51
  function levenshtein(a, b) {
44
52
  const m = a.length;
45
53
  const n = b.length;
@@ -403,21 +411,99 @@ function resolveColor(color, palette) {
403
411
  }
404
412
  return colorNames[lower] ?? null;
405
413
  }
414
+ function nearestNamedColor(input) {
415
+ const cssHex = INVALID_CSS_COLOR_HEX[input.trim().toLowerCase()];
416
+ if (cssHex) input = cssHex;
417
+ const m = /^#([0-9a-f]{3}|[0-9a-f]{6})$/i.exec(input.trim());
418
+ if (!m) return null;
419
+ let h = m[1].toLowerCase();
420
+ if (h.length === 3)
421
+ h = h.split("").map((c) => c + c).join("");
422
+ const r = parseInt(h.slice(0, 2), 16) / 255;
423
+ const g = parseInt(h.slice(2, 4), 16) / 255;
424
+ const b = parseInt(h.slice(4, 6), 16) / 255;
425
+ const max = Math.max(r, g, b);
426
+ const min = Math.min(r, g, b);
427
+ const delta = max - min;
428
+ const l = (max + min) / 2;
429
+ const s = delta === 0 ? 0 : delta / (1 - Math.abs(2 * l - 1));
430
+ if (s < 0.15) {
431
+ if (l < 0.2) return "black";
432
+ if (l > 0.85) return "white";
433
+ return "gray";
434
+ }
435
+ let hue;
436
+ if (max === r) hue = 60 * ((g - b) / delta % 6);
437
+ else if (max === g) hue = 60 * ((b - r) / delta + 2);
438
+ else hue = 60 * ((r - g) / delta + 4);
439
+ if (hue < 0) hue += 360;
440
+ const anchors = [
441
+ ["red", 0],
442
+ ["orange", 30],
443
+ ["yellow", 55],
444
+ ["green", 120],
445
+ ["teal", 170],
446
+ ["cyan", 190],
447
+ ["blue", 225],
448
+ ["purple", 285],
449
+ ["red", 360]
450
+ ];
451
+ let best = "red";
452
+ let bestD = Infinity;
453
+ for (const [name, deg] of anchors) {
454
+ const d = Math.abs(hue - deg);
455
+ if (d < bestD) {
456
+ bestD = d;
457
+ best = name;
458
+ }
459
+ }
460
+ return best;
461
+ }
462
+ function isInvalidColorToken(token) {
463
+ if (/^(#|rgba?\(|hsla?\()/i.test(token)) return true;
464
+ const lower = token.toLowerCase();
465
+ return INVALID_CSS_COLOR_HEX[lower] !== void 0 && !isRecognizedColorName(lower);
466
+ }
467
+ function invalidColorDiagnostic(token, line11) {
468
+ if (!isInvalidColorToken(token)) return null;
469
+ const nearest = nearestNamedColor(token);
470
+ const near = nearest ? ` Nearest: ${nearest}.` : "";
471
+ return makeDgmoError(
472
+ line11,
473
+ `Color "${token}" is not a valid DGMO color \u2014 DGMO accepts only these 11 named colors: ${RECOGNIZED_COLOR_NAMES.join(", ")} (no hex, no CSS color names).${near}`,
474
+ "warning",
475
+ INVALID_COLOR_CODE
476
+ );
477
+ }
406
478
  function resolveColorWithDiagnostic(color, line11, diagnostics, palette) {
407
479
  const resolved = resolveColor(color, palette);
408
480
  if (resolved !== null) return resolved;
481
+ if (/^(#|rgba?\(|hsla?\()/i.test(color)) {
482
+ const nearest = nearestNamedColor(color);
483
+ const near = nearest ? ` Nearest: ${nearest}.` : "";
484
+ diagnostics.push(
485
+ makeDgmoError(
486
+ line11,
487
+ `Color "${color}" is not supported \u2014 DGMO does not accept hex or CSS color values. Use a named palette color: ${RECOGNIZED_COLOR_NAMES.join(", ")}.${near}`,
488
+ "error",
489
+ INVALID_COLOR_CODE
490
+ )
491
+ );
492
+ return void 0;
493
+ }
409
494
  const hint = suggest(color, RECOGNIZED_COLOR_NAMES);
410
495
  const suggestion = hint ? ` ${hint}` : "";
411
496
  diagnostics.push(
412
497
  makeDgmoError(
413
498
  line11,
414
- `Unknown color "${color}". Allowed: ${RECOGNIZED_COLOR_NAMES.join(", ")}.${suggestion}`,
415
- "warning"
499
+ `Unknown color "${color}". DGMO accepts only these 11 named colors: ${RECOGNIZED_COLOR_NAMES.join(", ")} (no hex, no CSS color names).${suggestion}`,
500
+ "warning",
501
+ INVALID_COLOR_CODE
416
502
  )
417
503
  );
418
504
  return void 0;
419
505
  }
420
- var nord, colorNames, RECOGNIZED_COLOR_NAMES, CATEGORICAL_COLOR_ORDER, seriesColors;
506
+ var nord, colorNames, RECOGNIZED_COLOR_NAMES, CATEGORICAL_COLOR_ORDER, INVALID_COLOR_CODE, INVALID_CSS_COLOR_HEX, seriesColors;
421
507
  var init_colors = __esm({
422
508
  "src/colors.ts"() {
423
509
  "use strict";
@@ -485,6 +571,92 @@ var init_colors = __esm({
485
571
  "orange",
486
572
  "cyan"
487
573
  ]);
574
+ INVALID_COLOR_CODE = "E_INVALID_COLOR";
575
+ INVALID_CSS_COLOR_HEX = Object.freeze({
576
+ pink: "#ffc0cb",
577
+ hotpink: "#ff69b4",
578
+ deeppink: "#ff1493",
579
+ lightpink: "#ffb6c1",
580
+ palevioletred: "#db7093",
581
+ crimson: "#dc143c",
582
+ scarlet: "#ff2400",
583
+ firebrick: "#b22222",
584
+ darkred: "#8b0000",
585
+ maroon: "#800000",
586
+ salmon: "#fa8072",
587
+ lightsalmon: "#ffa07a",
588
+ darksalmon: "#e9967a",
589
+ coral: "#ff7f50",
590
+ lightcoral: "#f08080",
591
+ tomato: "#ff6347",
592
+ orangered: "#ff4500",
593
+ darkorange: "#ff8c00",
594
+ gold: "#ffd700",
595
+ goldenrod: "#daa520",
596
+ darkgoldenrod: "#b8860b",
597
+ khaki: "#f0e68c",
598
+ darkkhaki: "#bdb76b",
599
+ amber: "#ffbf00",
600
+ lavender: "#e6e6fa",
601
+ violet: "#ee82ee",
602
+ magenta: "#ff00ff",
603
+ fuchsia: "#ff00ff",
604
+ orchid: "#da70d6",
605
+ plum: "#dda0dd",
606
+ indigo: "#4b0082",
607
+ navy: "#000080",
608
+ midnightblue: "#191970",
609
+ darkblue: "#00008b",
610
+ mediumblue: "#0000cd",
611
+ royalblue: "#4169e1",
612
+ cornflowerblue: "#6495ed",
613
+ dodgerblue: "#1e90ff",
614
+ deepskyblue: "#00bfff",
615
+ skyblue: "#87ceeb",
616
+ lightskyblue: "#87cefa",
617
+ lightblue: "#add8e6",
618
+ powderblue: "#b0e0e6",
619
+ steelblue: "#4682b4",
620
+ slateblue: "#6a5acd",
621
+ cadetblue: "#5f9ea0",
622
+ turquoise: "#40e0d0",
623
+ aqua: "#00ffff",
624
+ aquamarine: "#7fffd4",
625
+ lime: "#00ff00",
626
+ limegreen: "#32cd32",
627
+ lightgreen: "#90ee90",
628
+ palegreen: "#98fb98",
629
+ seagreen: "#2e8b57",
630
+ mediumseagreen: "#3cb371",
631
+ forestgreen: "#228b22",
632
+ darkgreen: "#006400",
633
+ olive: "#808000",
634
+ olivedrab: "#6b8e23",
635
+ darkolivegreen: "#556b2f",
636
+ chartreuse: "#7fff00",
637
+ lawngreen: "#7cfc00",
638
+ springgreen: "#00ff7f",
639
+ greenyellow: "#adff2f",
640
+ brown: "#a52a2a",
641
+ sienna: "#a0522d",
642
+ chocolate: "#d2691e",
643
+ peru: "#cd853f",
644
+ tan: "#d2b48c",
645
+ beige: "#f5f5dc",
646
+ wheat: "#f5deb3",
647
+ ivory: "#fffff0",
648
+ silver: "#c0c0c0",
649
+ lightgray: "#d3d3d3",
650
+ lightgrey: "#d3d3d3",
651
+ darkgray: "#a9a9a9",
652
+ darkgrey: "#a9a9a9",
653
+ dimgray: "#696969",
654
+ dimgrey: "#696969",
655
+ slategray: "#708090",
656
+ slategrey: "#708090",
657
+ gainsboro: "#dcdcdc",
658
+ grey: "#808080"
659
+ });
488
660
  seriesColors = [
489
661
  nord.nord10,
490
662
  // blue
@@ -659,7 +831,13 @@ function extractColor(label, palette, diagnostics, line11) {
659
831
  );
660
832
  if (lastSpaceIdx < 0) return { label };
661
833
  const trailing = label.substring(lastSpaceIdx + 1);
662
- if (!RECOGNIZED_COLOR_SET.has(trailing)) return { label };
834
+ if (!RECOGNIZED_COLOR_SET.has(trailing)) {
835
+ if (diagnostics && line11 !== void 0) {
836
+ const diag = invalidColorDiagnostic(trailing, line11);
837
+ if (diag) diagnostics.push(diag);
838
+ }
839
+ return { label };
840
+ }
663
841
  let color;
664
842
  if (diagnostics && line11 !== void 0) {
665
843
  color = resolveColorWithDiagnostic(trailing, line11, diagnostics, palette);
@@ -1283,6 +1461,23 @@ function validateTagGroupNames(tagGroups, pushWarning, pushError) {
1283
1461
  }
1284
1462
  }
1285
1463
  }
1464
+ function cascadeTagMetadata(roots, tagGroups) {
1465
+ const keys = tagGroups.map((g) => g.name.toLowerCase());
1466
+ if (keys.length === 0) return;
1467
+ const walk = (node, inherited) => {
1468
+ const childInherited = { ...inherited };
1469
+ for (const key of keys) {
1470
+ const own = node.metadata[key];
1471
+ if (own) {
1472
+ childInherited[key] = own;
1473
+ } else if (inherited[key]) {
1474
+ node.metadata[key] = inherited[key];
1475
+ }
1476
+ }
1477
+ for (const child of node.children) walk(child, childInherited);
1478
+ };
1479
+ for (const root of roots) walk(root, {});
1480
+ }
1286
1481
  function injectDefaultTagMetadata(entities, tagGroups, skip) {
1287
1482
  const defaults = [];
1288
1483
  for (const group of tagGroups) {
@@ -1821,7 +2016,12 @@ function parseVisualizationFull(content, palette) {
1821
2016
  }
1822
2017
  if (currentTimelineTagGroup && indent > 0) {
1823
2018
  const { text: entryText, isDefault } = stripDefaultModifier(line11);
1824
- const { label, color } = extractColor(entryText, palette);
2019
+ const { label, color } = extractColor(
2020
+ entryText,
2021
+ palette,
2022
+ result.diagnostics,
2023
+ lineNumber
2024
+ );
1825
2025
  if (color) {
1826
2026
  if (isDefault) {
1827
2027
  currentTimelineTagGroup.defaultValue = label;
@@ -3122,9 +3322,12 @@ function contrastText(bg, lightText, darkText) {
3122
3322
  }
3123
3323
  return lightText;
3124
3324
  }
3325
+ function themeBaseBg(palette, isDark) {
3326
+ return isDark ? palette.surface : palette.bg;
3327
+ }
3125
3328
  function shapeFill(palette, intent, isDark, opts) {
3126
3329
  if (opts?.solid) return intent;
3127
- return mix(intent, isDark ? palette.surface : palette.bg, 25);
3330
+ return mix(intent, themeBaseBg(palette, isDark), 25);
3128
3331
  }
3129
3332
  function getSeriesColors(palette) {
3130
3333
  const c = palette.colors;
@@ -3155,7 +3358,7 @@ function getSegmentColors(palette, count) {
3155
3358
  }
3156
3359
  function politicalTints(palette, count, isDark) {
3157
3360
  if (count <= 0) return [];
3158
- const base = isDark ? palette.surface : palette.bg;
3361
+ const base = themeBaseBg(palette, isDark);
3159
3362
  const c = palette.colors;
3160
3363
  const swatches = [
3161
3364
  .../* @__PURE__ */ new Set([
@@ -3965,6 +4168,7 @@ __export(palettes_exports, {
3965
4168
  shade: () => shade,
3966
4169
  shapeFill: () => shapeFill,
3967
4170
  slatePalette: () => slatePalette,
4171
+ themeBaseBg: () => themeBaseBg,
3968
4172
  tidewaterPalette: () => tidewaterPalette,
3969
4173
  tint: () => tint,
3970
4174
  tokyoNightPalette: () => tokyoNightPalette
@@ -4198,6 +4402,30 @@ var init_scaling = __esm({
4198
4402
  const clamped = Math.max(Math.min(raw, 1), minScaleFactor);
4199
4403
  return new _ScaleContext(clamped, minScaleFactor);
4200
4404
  }
4405
+ /**
4406
+ * Fit content into a bounding box, scaling by whichever dimension is more
4407
+ * constraining (the smaller of the width- and height-fit ratios) so the
4408
+ * diagram never overflows the canvas in either axis. Like {@link from}, the
4409
+ * factor is clamped to `[minScaleFactor, 1]` (content is never enlarged, and
4410
+ * never shrunk past the readability floor).
4411
+ */
4412
+ static fromBox(containerWidth, idealWidth, containerHeight, idealHeight, minScaleFactor = DEFAULT_MIN_SCALE_FACTOR) {
4413
+ const wRaw = idealWidth > 0 ? containerWidth / idealWidth : 1;
4414
+ const hRaw = idealHeight > 0 ? containerHeight / idealHeight : 1;
4415
+ const raw = Math.min(wRaw, hRaw);
4416
+ const clamped = Math.max(Math.min(raw, 1), minScaleFactor);
4417
+ return new _ScaleContext(clamped, minScaleFactor);
4418
+ }
4419
+ /**
4420
+ * Build a context from an explicit raw factor (clamped to
4421
+ * `[minScaleFactor, 1]`). Used to refine a fit iteratively: layout scaling is
4422
+ * non-linear (gaps shrink faster than floored text), so the first-pass factor
4423
+ * can still overflow — re-measure the laid-out result and tighten.
4424
+ */
4425
+ static fromFactor(rawFactor, minScaleFactor = DEFAULT_MIN_SCALE_FACTOR) {
4426
+ const clamped = Math.max(Math.min(rawFactor, 1), minScaleFactor);
4427
+ return new _ScaleContext(clamped, minScaleFactor);
4428
+ }
4201
4429
  static identity() {
4202
4430
  return new _ScaleContext(1, DEFAULT_MIN_SCALE_FACTOR);
4203
4431
  }
@@ -5837,12 +6065,7 @@ function parseSequenceDgmo(content, palette) {
5837
6065
  const trimmed = token.trim();
5838
6066
  return nameAliasMap.get(trimmed) ?? trimmed;
5839
6067
  };
5840
- const fail = (line11, message) => {
5841
- const diag = makeDgmoError(line11, message);
5842
- result.diagnostics.push(diag);
5843
- result.error = formatDgmoError(diag);
5844
- return result;
5845
- };
6068
+ const fail = makeFail(result);
5846
6069
  const pushError = (line11, message) => {
5847
6070
  const diag = makeDgmoError(line11, message);
5848
6071
  result.diagnostics.push(diag);
@@ -5857,6 +6080,7 @@ function parseSequenceDgmo(content, palette) {
5857
6080
  const lines = content.split("\n");
5858
6081
  let hasExplicitChart = false;
5859
6082
  let contentStarted = false;
6083
+ let bodyStarted = false;
5860
6084
  let firstLineIndex = -1;
5861
6085
  for (let fi = 0; fi < lines.length; fi++) {
5862
6086
  const fl = lines[fi].trim();
@@ -6168,6 +6392,7 @@ function parseSequenceDgmo(content, palette) {
6168
6392
  );
6169
6393
  }
6170
6394
  contentStarted = true;
6395
+ bodyStarted = true;
6171
6396
  const section = {
6172
6397
  kind: "section",
6173
6398
  // Capture group 1 guaranteed present after successful match.
@@ -6383,7 +6608,7 @@ function parseSequenceDgmo(content, palette) {
6383
6608
  alias: bareAlias
6384
6609
  } = splitPipe(trimmed, lineNumber);
6385
6610
  const inGroup = activeGroup && measureIndent(raw) > 0;
6386
- if (/^\S+$/.test(bareCore) && !ARROW_PATTERN.test(bareCore) && (inGroup || !contentStarted || bareMeta)) {
6611
+ if (/^\S+$/.test(bareCore) && !ARROW_PATTERN.test(bareCore) && (inGroup || !bodyStarted || bareMeta)) {
6387
6612
  contentStarted = true;
6388
6613
  const id = bareCore;
6389
6614
  if (bareAlias !== void 0) nameAliasMap.set(bareAlias, id);
@@ -6430,6 +6655,7 @@ function parseSequenceDgmo(content, palette) {
6430
6655
  }
6431
6656
  if (labeledArrow) {
6432
6657
  contentStarted = true;
6658
+ bodyStarted = true;
6433
6659
  const { from, to, label: rawLabel, async: isAsync } = labeledArrow;
6434
6660
  const fromKey = addParticipant(resolveAlias(from), lineNumber);
6435
6661
  const toKey = addParticipant(resolveAlias(to), lineNumber);
@@ -6494,6 +6720,7 @@ function parseSequenceDgmo(content, palette) {
6494
6720
  const bareCall = bareCallSync || bareCallAsync;
6495
6721
  if (bareCall) {
6496
6722
  contentStarted = true;
6723
+ bodyStarted = true;
6497
6724
  const from = bareCall[1];
6498
6725
  const to = bareCall[2];
6499
6726
  const fromKey = addParticipant(resolveAlias(from), lineNumber);
@@ -6515,6 +6742,7 @@ function parseSequenceDgmo(content, palette) {
6515
6742
  const ifMatch = trimmed.match(/^if\s+(.+)$/i);
6516
6743
  if (ifMatch) {
6517
6744
  contentStarted = true;
6745
+ bodyStarted = true;
6518
6746
  const block = {
6519
6747
  kind: "block",
6520
6748
  type: "if",
@@ -6531,6 +6759,7 @@ function parseSequenceDgmo(content, palette) {
6531
6759
  const loopMatch = trimmed.match(/^loop\s+(.+)$/i);
6532
6760
  if (loopMatch) {
6533
6761
  contentStarted = true;
6762
+ bodyStarted = true;
6534
6763
  const block = {
6535
6764
  kind: "block",
6536
6765
  type: "loop",
@@ -6547,6 +6776,7 @@ function parseSequenceDgmo(content, palette) {
6547
6776
  const parallelMatch = trimmed.match(/^parallel(?:\s+(.+))?$/i);
6548
6777
  if (parallelMatch) {
6549
6778
  contentStarted = true;
6779
+ bodyStarted = true;
6550
6780
  const block = {
6551
6781
  kind: "block",
6552
6782
  type: "parallel",
@@ -6643,6 +6873,7 @@ function parseSequenceDgmo(content, palette) {
6643
6873
  lineNumber,
6644
6874
  endLineNumber: lineNumber
6645
6875
  };
6876
+ bodyStarted = true;
6646
6877
  currentContainer().push(note);
6647
6878
  continue;
6648
6879
  }
@@ -6667,6 +6898,7 @@ function parseSequenceDgmo(content, palette) {
6667
6898
  endLineNumber: i + 1
6668
6899
  // i has advanced past the body lines (1-based)
6669
6900
  };
6901
+ bodyStarted = true;
6670
6902
  currentContainer().push(note);
6671
6903
  continue;
6672
6904
  }
@@ -7511,6 +7743,15 @@ function parseNodeRef(text) {
7511
7743
  }
7512
7744
  return null;
7513
7745
  }
7746
+ function parseNodeRefLoose(text) {
7747
+ const t = text.trim();
7748
+ const shapeRe = /^(\[\[.+?\]\]|\[.+?~\]|\[.+?\]|\(.+?\)|<.+?>|\/.+?\/)\s+(\S.*)$/;
7749
+ const m = t.match(shapeRe);
7750
+ if (!m) return null;
7751
+ const ref = parseNodeRef(m[1]);
7752
+ if (!ref) return null;
7753
+ return { ref, trailing: m[2].trim() };
7754
+ }
7514
7755
  function splitArrows(line11) {
7515
7756
  const segments = [];
7516
7757
  const arrowPositions = [];
@@ -7606,6 +7847,7 @@ function parseFlowchart(content, palette) {
7606
7847
  const notes = [];
7607
7848
  let contentStarted = false;
7608
7849
  let firstLineParsed = false;
7850
+ let prevLineLastNodeId = null;
7609
7851
  const nameAliasMap = /* @__PURE__ */ new Map();
7610
7852
  function peelAlias2(seg) {
7611
7853
  const trimmed = seg.trim();
@@ -7613,6 +7855,19 @@ function parseFlowchart(content, palette) {
7613
7855
  if (!m) return { seg: trimmed };
7614
7856
  return { seg: m[1].trim(), alias: m[2] };
7615
7857
  }
7858
+ const suffixWarnedLines = /* @__PURE__ */ new Set();
7859
+ function warnUnsupportedSuffix(lineNumber, trailing) {
7860
+ if (suffixWarnedLines.has(lineNumber)) return;
7861
+ suffixWarnedLines.add(lineNumber);
7862
+ result.diagnostics.push(
7863
+ makeDgmoError(
7864
+ lineNumber,
7865
+ `Ignored unsupported text after a node shape: "${trailing}". Flowcharts have no tag groups or node metadata; node colors are assigned automatically by shape (e.g. terminals green/red, decisions yellow). Remove the suffix.`,
7866
+ "warning",
7867
+ "W_FLOWCHART_NODE_SUFFIX"
7868
+ )
7869
+ );
7870
+ }
7616
7871
  function getOrCreateNode(ref, lineNumber) {
7617
7872
  const key = ref.id;
7618
7873
  const existing = nodeMap.get(key);
@@ -7671,6 +7926,8 @@ function parseFlowchart(content, palette) {
7671
7926
  indentStack[indentStack.length - 1].nodeId
7672
7927
  ) : null;
7673
7928
  const segments = splitArrows(trimmed);
7929
+ const startsWithArrow = segments.length >= 2 && segments[0].trim() === "";
7930
+ const effectiveSource = implicitSourceId ?? (startsWithArrow ? prevLineLastNodeId : null);
7674
7931
  if (segments.length === 1) {
7675
7932
  const peeled = peelAlias2(segments[0]);
7676
7933
  const ref = parseNodeRef(peeled.seg);
@@ -7680,6 +7937,13 @@ function parseFlowchart(content, palette) {
7680
7937
  indentStack.push({ nodeId: node.id, indent });
7681
7938
  return node.id;
7682
7939
  }
7940
+ const loose = parseNodeRefLoose(peeled.seg);
7941
+ if (loose) {
7942
+ warnUnsupportedSuffix(lineNumber, loose.trailing);
7943
+ const node = getOrCreateNode(loose.ref, lineNumber);
7944
+ indentStack.push({ nodeId: node.id, indent });
7945
+ return node.id;
7946
+ }
7683
7947
  const aliasResolved = nameAliasMap.get(peeled.seg.trim());
7684
7948
  if (aliasResolved !== void 0) {
7685
7949
  indentStack.push({ nodeId: aliasResolved, indent });
@@ -7715,16 +7979,23 @@ function parseFlowchart(content, palette) {
7715
7979
  }
7716
7980
  }
7717
7981
  }
7982
+ if (!ref) {
7983
+ const loose = parseNodeRefLoose(peeled.seg);
7984
+ if (loose) {
7985
+ warnUnsupportedSuffix(lineNumber, loose.trailing);
7986
+ ref = loose.ref;
7987
+ }
7988
+ }
7718
7989
  if (!ref) continue;
7719
7990
  const node = getOrCreateNode(ref, lineNumber);
7720
7991
  if (peeled.alias) nameAliasMap.set(peeled.alias, node.id);
7721
7992
  if (pendingArrow !== null) {
7722
- const sourceId = lastNodeId ?? implicitSourceId;
7993
+ const sourceId = lastNodeId ?? effectiveSource;
7723
7994
  if (sourceId) {
7724
7995
  addEdge(sourceId, node.id, lineNumber, pendingArrow.label);
7725
7996
  }
7726
7997
  pendingArrow = null;
7727
- } else if (lastNodeId === null && implicitSourceId === null) {
7998
+ } else if (lastNodeId === null && effectiveSource === null) {
7728
7999
  }
7729
8000
  lastNodeId = node.id;
7730
8001
  }
@@ -7806,7 +8077,8 @@ function parseFlowchart(content, palette) {
7806
8077
  continue;
7807
8078
  }
7808
8079
  }
7809
- processContentLine(trimmed, lineNumber, indent);
8080
+ const lastId = processContentLine(trimmed, lineNumber, indent);
8081
+ if (lastId) prevLineLastNodeId = lastId;
7810
8082
  }
7811
8083
  if (result.nodes.length === 0 && !result.error) {
7812
8084
  const diag = makeDgmoError(
@@ -8889,7 +9161,12 @@ function parseERDiagram(content, palette) {
8889
9161
  }
8890
9162
  if (currentTagGroup && !contentStarted && indent > 0) {
8891
9163
  const { text: cleanEntry, isDefault } = stripDefaultModifier(trimmed);
8892
- const { label, color } = extractColor(cleanEntry, palette);
9164
+ const { label, color } = extractColor(
9165
+ cleanEntry,
9166
+ palette,
9167
+ result.diagnostics,
9168
+ lineNumber
9169
+ );
8893
9170
  if (isDefault) {
8894
9171
  currentTagGroup.defaultValue = label;
8895
9172
  } else if (currentTagGroup.entries.length === 0) {
@@ -9207,12 +9484,7 @@ function parseOrg(content, palette) {
9207
9484
  diagnostics: [],
9208
9485
  error: null
9209
9486
  };
9210
- const fail = (line11, message) => {
9211
- const diag = makeDgmoError(line11, message);
9212
- result.diagnostics.push(diag);
9213
- result.error = formatDgmoError(diag);
9214
- return result;
9215
- };
9487
+ const fail = makeFail(result);
9216
9488
  const pushError = (line11, message) => {
9217
9489
  const diag = makeDgmoError(line11, message);
9218
9490
  result.diagnostics.push(diag);
@@ -9321,7 +9593,12 @@ function parseOrg(content, palette) {
9321
9593
  const indent2 = measureIndent(line11);
9322
9594
  if (indent2 > 0) {
9323
9595
  const { text: cleanEntry, isDefault } = stripDefaultModifier(trimmed);
9324
- const { label, color } = extractColor(cleanEntry, palette);
9596
+ const { label, color } = extractColor(
9597
+ cleanEntry,
9598
+ palette,
9599
+ result.diagnostics,
9600
+ lineNumber
9601
+ );
9325
9602
  if (isDefault) {
9326
9603
  currentTagGroup.defaultValue = label;
9327
9604
  } else if (currentTagGroup.entries.length === 0) {
@@ -9607,12 +9884,7 @@ function parseSitemap(content, palette) {
9607
9884
  diagnostics: [],
9608
9885
  error: null
9609
9886
  };
9610
- const fail = (line11, message) => {
9611
- const diag = makeDgmoError(line11, message);
9612
- result.diagnostics.push(diag);
9613
- result.error = formatDgmoError(diag);
9614
- return result;
9615
- };
9887
+ const fail = makeFail(result);
9616
9888
  const pushError = (line11, message) => {
9617
9889
  const diag = makeDgmoError(line11, message);
9618
9890
  result.diagnostics.push(diag);
@@ -9713,7 +9985,12 @@ function parseSitemap(content, palette) {
9713
9985
  const indent2 = measureIndent(line11);
9714
9986
  if (indent2 > 0) {
9715
9987
  const { text: cleanEntry, isDefault } = stripDefaultModifier(trimmed);
9716
- const { label, color } = extractColor(cleanEntry, palette);
9988
+ const { label, color } = extractColor(
9989
+ cleanEntry,
9990
+ palette,
9991
+ result.diagnostics,
9992
+ lineNumber
9993
+ );
9717
9994
  currentTagGroup.entries.push({
9718
9995
  value: label,
9719
9996
  color: color ?? AUTO_TAG_COLOR_SENTINEL,
@@ -11428,7 +11705,7 @@ var init_chart_types = __esm({
11428
11705
  },
11429
11706
  {
11430
11707
  id: "sequence",
11431
- description: "Message / interaction flows",
11708
+ description: "Message request and response interaction flows",
11432
11709
  fallback: true
11433
11710
  },
11434
11711
  {
@@ -11502,7 +11779,7 @@ var init_chart_types = __esm({
11502
11779
  },
11503
11780
  {
11504
11781
  id: "map",
11505
- description: "Geographic map: a value or count per country, state, or region (choropleth); points of interest; routes. Use when categories are real-world places."
11782
+ description: "Geographic concept map: highlight/score regions, drop points of interest, connect with routes or edges"
11506
11783
  },
11507
11784
  // ── Tier 3 — Specialized analytical charts ────────────────
11508
11785
  {
@@ -11519,7 +11796,7 @@ var init_chart_types = __esm({
11519
11796
  },
11520
11797
  {
11521
11798
  id: "slope",
11522
- description: "Change for multiple things between exactly two periods"
11799
+ description: "Change between 2 time periods"
11523
11800
  },
11524
11801
  {
11525
11802
  id: "sankey",
@@ -11548,7 +11825,7 @@ var init_chart_types = __esm({
11548
11825
  // ── Tier 4 — General-purpose data charts ──────────────────
11549
11826
  {
11550
11827
  id: "bar",
11551
- description: "Categorical comparisons",
11828
+ description: "Categorical comparisons for 3 - 5 figures",
11552
11829
  fallback: true
11553
11830
  },
11554
11831
  {
@@ -11810,7 +12087,9 @@ function parseChart(content, palette) {
11810
12087
  if (dataValues) {
11811
12088
  const { label: rawLabel, color: pointColor } = extractColor(
11812
12089
  dataValues.label,
11813
- palette
12090
+ palette,
12091
+ result.diagnostics,
12092
+ lineNumber
11814
12093
  );
11815
12094
  const [first, ...rest] = dataValues.values;
11816
12095
  result.data.push({
@@ -11875,6 +12154,12 @@ function parseChart(content, palette) {
11875
12154
  'Chart type "bar-stacked" requires multiple series names. Use: series Name1, Name2, Name3'
11876
12155
  );
11877
12156
  }
12157
+ if (!result.error && result.type === "bar" && (result.seriesNames?.length ?? 0) > 1) {
12158
+ warn(
12159
+ result.seriesLineNumber ?? 1,
12160
+ `Plain "bar" shows only the first series ("${result.seriesNames[0]}"); the other ${result.seriesNames.length - 1} are dropped at render. Use "bar-stacked" for stacked bars or "multi-line" to plot every series.`
12161
+ );
12162
+ }
11878
12163
  if (!result.error && result.seriesNames) {
11879
12164
  const expectedCount = result.seriesNames.length;
11880
12165
  for (const dp of result.data) {
@@ -12136,7 +12421,9 @@ function parseScatterRow(line11, palette, currentCategory, lineNumber, diagnosti
12136
12421
  if (!dataRow || dataRow.values.length < 2) return null;
12137
12422
  const { label: rawLabel, color: pointColor } = extractColor(
12138
12423
  dataRow.label,
12139
- palette
12424
+ palette,
12425
+ diagnostics,
12426
+ lineNumber
12140
12427
  );
12141
12428
  return {
12142
12429
  name: rawLabel,
@@ -12274,11 +12561,15 @@ function parseExtendedChartFull(content, palette) {
12274
12561
  const targetResolved = resolveSlot(rawTarget);
12275
12562
  const { label: source, color: sourceColor } = extractColor(
12276
12563
  sourceResolved,
12277
- palette
12564
+ palette,
12565
+ result.diagnostics,
12566
+ lineNumber
12278
12567
  );
12279
12568
  const { label: target, color: targetColor } = extractColor(
12280
12569
  targetResolved,
12281
- palette
12570
+ palette,
12571
+ result.diagnostics,
12572
+ lineNumber
12282
12573
  );
12283
12574
  if (sourceColor || targetColor) {
12284
12575
  if (!result.nodeColors) result.nodeColors = {};
@@ -12330,7 +12621,9 @@ function parseExtendedChartFull(content, palette) {
12330
12621
  const targetResolved = resolveSlot(dataRow2.label);
12331
12622
  const { label: target, color: targetColor } = extractColor(
12332
12623
  targetResolved,
12333
- palette
12624
+ palette,
12625
+ result.diagnostics,
12626
+ lineNumber
12334
12627
  );
12335
12628
  if (targetColor) {
12336
12629
  if (!result.nodeColors) result.nodeColors = {};
@@ -12363,7 +12656,9 @@ function parseExtendedChartFull(content, palette) {
12363
12656
  const trimmedResolved = resolveSlot(trimmed);
12364
12657
  const { label: nodeName, color: nodeColor2 } = extractColor(
12365
12658
  trimmedResolved,
12366
- palette
12659
+ palette,
12660
+ result.diagnostics,
12661
+ lineNumber
12367
12662
  );
12368
12663
  if (nodeColor2) {
12369
12664
  if (!result.nodeColors) result.nodeColors = {};
@@ -12453,8 +12748,11 @@ function parseExtendedChartFull(content, palette) {
12453
12748
  min: parseFloat(rangeMatch[1]),
12454
12749
  max: parseFloat(rangeMatch[2])
12455
12750
  };
12751
+ continue;
12752
+ }
12753
+ if (!(result.type === "function" && trimmed.includes(":"))) {
12754
+ continue;
12456
12755
  }
12457
- continue;
12458
12756
  }
12459
12757
  }
12460
12758
  if (firstToken === "no-name") {
@@ -12514,7 +12812,9 @@ function parseExtendedChartFull(content, palette) {
12514
12812
  if (colonIndex >= 0) {
12515
12813
  const { label: fnName, color: fnColor } = extractColor(
12516
12814
  trimmed.substring(0, colonIndex).trim(),
12517
- palette
12815
+ palette,
12816
+ result.diagnostics,
12817
+ lineNumber
12518
12818
  );
12519
12819
  const fnValue = trimmed.substring(colonIndex + 1).trim();
12520
12820
  if (!result.functions) result.functions = [];
@@ -12562,7 +12862,9 @@ function parseExtendedChartFull(content, palette) {
12562
12862
  if (dataRow?.values.length === 1) {
12563
12863
  const { label: rawLabel, color: pointColor } = extractColor(
12564
12864
  dataRow.label,
12565
- palette
12865
+ palette,
12866
+ result.diagnostics,
12867
+ lineNumber
12566
12868
  );
12567
12869
  result.data.push({
12568
12870
  label: rawLabel,
@@ -12661,11 +12963,11 @@ function buildExtendedChartOption(parsed, palette, isDark, ctx) {
12661
12963
  const sc = ctx ?? ScaleContext.identity();
12662
12964
  const { textColor, axisLineColor, gridOpacity, colors, titleConfig } = buildChartCommons(parsed, palette, isDark, sc);
12663
12965
  if (parsed.type === "sankey") {
12664
- const bg = isDark ? palette.surface : palette.bg;
12966
+ const bg = themeBaseBg(palette, isDark);
12665
12967
  return buildSankeyOption(parsed, textColor, colors, bg, titleConfig, sc);
12666
12968
  }
12667
12969
  if (parsed.type === "chord") {
12668
- const bg = isDark ? palette.surface : palette.bg;
12970
+ const bg = themeBaseBg(palette, isDark);
12669
12971
  return buildChordOption(
12670
12972
  parsed,
12671
12973
  palette,
@@ -12706,7 +13008,7 @@ function buildExtendedChartOption(parsed, palette, isDark, ctx) {
12706
13008
  );
12707
13009
  }
12708
13010
  if (parsed.type === "funnel") {
12709
- const bg = isDark ? palette.surface : palette.bg;
13011
+ const bg = themeBaseBg(palette, isDark);
12710
13012
  return buildFunnelOption(
12711
13013
  parsed,
12712
13014
  palette,
@@ -13302,7 +13604,8 @@ function buildScatterOption(parsed, palette, isDark, textColor, axisLineColor, g
13302
13604
  const gridLeft = parsed.ylabel ? 12 : 3;
13303
13605
  const gridRight = 4;
13304
13606
  const gridBottom = hasCategories ? 15 : parsed.xlabel ? 10 : 3;
13305
- const gridTop = parsed.title && !parsed.noTitle ? 15 : 5;
13607
+ const hasTitle = !!(parsed.title && !parsed.noTitle);
13608
+ const gridTop = hasTitle ? hasCategories ? 22 : 15 : hasCategories ? 12 : 5;
13306
13609
  let graphic;
13307
13610
  if (showLabels && points.length > 0) {
13308
13611
  const labelPoints = [];
@@ -13442,7 +13745,7 @@ function buildScatterOption(parsed, palette, isDark, textColor, axisLineColor, g
13442
13745
  }
13443
13746
  function buildHeatmapOption(parsed, palette, isDark, textColor, axisLineColor, titleConfig, ctx) {
13444
13747
  const sc = ctx ?? ScaleContext.identity();
13445
- const bg = isDark ? palette.surface : palette.bg;
13748
+ const bg = themeBaseBg(palette, isDark);
13446
13749
  const heatmapRows = parsed.heatmapRows ?? [];
13447
13750
  const columns = parsed.columns ?? [];
13448
13751
  const rowLabels = heatmapRows.map((r) => r.label);
@@ -13761,7 +14064,7 @@ function buildSimpleChartOption(parsed, palette, isDark, chartWidth, ctx) {
13761
14064
  colors,
13762
14065
  titleConfig
13763
14066
  } = buildChartCommons(parsed, palette, isDark, sc);
13764
- const bg = isDark ? palette.surface : palette.bg;
14067
+ const bg = themeBaseBg(palette, isDark);
13765
14068
  switch (parsed.type) {
13766
14069
  case "bar":
13767
14070
  return buildBarOption(
@@ -14713,12 +15016,7 @@ function parseKanban(content, palette) {
14713
15016
  diagnostics: [],
14714
15017
  error: null
14715
15018
  };
14716
- const fail = (line11, message) => {
14717
- const diag = makeDgmoError(line11, message);
14718
- result.diagnostics.push(diag);
14719
- result.error = formatDgmoError(diag);
14720
- return result;
14721
- };
15019
+ const fail = makeFail(result);
14722
15020
  const warn = (line11, message) => {
14723
15021
  result.diagnostics.push(makeDgmoError(line11, message, "warning"));
14724
15022
  };
@@ -14821,7 +15119,12 @@ function parseKanban(content, palette) {
14821
15119
  const indent2 = measureIndent(line11);
14822
15120
  if (indent2 > 0) {
14823
15121
  const { text: cleanEntry, isDefault } = stripDefaultModifier(trimmed);
14824
- const { label, color } = extractColor(cleanEntry, palette);
15122
+ const { label, color } = extractColor(
15123
+ cleanEntry,
15124
+ palette,
15125
+ result.diagnostics,
15126
+ lineNumber
15127
+ );
14825
15128
  if (isDefault) {
14826
15129
  currentTagGroup.defaultValue = label;
14827
15130
  } else if (currentTagGroup.entries.length === 0) {
@@ -14989,11 +15292,11 @@ function parseKanban(content, palette) {
14989
15292
  for (const col of result.columns) {
14990
15293
  for (const card of col.cards) {
14991
15294
  for (const [tagKey, tagValue] of Object.entries(card.tags)) {
14992
- const groupKey = metaAliasMap.get(tagKey.toLowerCase()) ?? tagKey.toLowerCase();
14993
- const validValues = tagValueSets.get(groupKey);
15295
+ const groupKey2 = metaAliasMap.get(tagKey.toLowerCase()) ?? tagKey.toLowerCase();
15296
+ const validValues = tagValueSets.get(groupKey2);
14994
15297
  if (validValues && !validValues.has(tagValue.toLowerCase())) {
14995
- const entries = result.tagGroups.find((g) => g.name.toLowerCase() === groupKey)?.entries.map((e) => e.value);
14996
- let msg = `Unknown tag value "${tagValue}" for group "${groupKey}"`;
15298
+ const entries = result.tagGroups.find((g) => g.name.toLowerCase() === groupKey2)?.entries.map((e) => e.value);
15299
+ let msg = `Unknown tag value "${tagValue}" for group "${groupKey2}"`;
14997
15300
  if (entries) {
14998
15301
  const hint = suggest(tagValue, entries);
14999
15302
  if (hint) msg += `. ${hint}`;
@@ -15165,12 +15468,7 @@ function parseC4(content, palette) {
15165
15468
  if (!result.error && severity === "error")
15166
15469
  result.error = formatDgmoError(diag);
15167
15470
  };
15168
- const fail = (line11, message) => {
15169
- const diag = makeDgmoError(line11, message);
15170
- result.diagnostics.push(diag);
15171
- result.error = formatDgmoError(diag);
15172
- return result;
15173
- };
15471
+ const fail = makeFail(result);
15174
15472
  if (!content?.trim()) {
15175
15473
  return fail(0, "No content provided");
15176
15474
  }
@@ -15271,7 +15569,12 @@ function parseC4(content, palette) {
15271
15569
  const indent2 = measureIndent(line11);
15272
15570
  if (indent2 > 0) {
15273
15571
  const { text: cleanEntry, isDefault } = stripDefaultModifier(trimmed);
15274
- const { label, color } = extractColor(cleanEntry, palette);
15572
+ const { label, color } = extractColor(
15573
+ cleanEntry,
15574
+ palette,
15575
+ result.diagnostics,
15576
+ lineNumber
15577
+ );
15275
15578
  if (isDefault) {
15276
15579
  currentTagGroup.defaultValue = label;
15277
15580
  } else if (currentTagGroup.entries.length === 0) {
@@ -16936,8 +17239,66 @@ function parseInfra(content) {
16936
17239
  }
16937
17240
  }
16938
17241
  validateTagGroupNames(result.tagGroups, warn, setError);
17242
+ checkReachability(result);
16939
17243
  return result;
16940
17244
  }
17245
+ function checkReachability(result) {
17246
+ if (result.nodes.length === 0) return;
17247
+ const entries = result.nodes.filter((n) => n.isEdge);
17248
+ if (entries.length === 0) {
17249
+ const line11 = result.titleLineNumber ?? result.nodes[0]?.lineNumber ?? 1;
17250
+ result.diagnostics.push(
17251
+ makeDgmoError(
17252
+ line11,
17253
+ `Infra diagram has no 'internet' or 'edge' entry point \u2014 an infra diagram traces request traffic from an entry inward, so without one nothing carries traffic. Add an 'internet' or 'edge' node and route from it.`,
17254
+ "warning",
17255
+ "W_INFRA_NO_ENTRY"
17256
+ )
17257
+ );
17258
+ return;
17259
+ }
17260
+ const groupChildMap = /* @__PURE__ */ new Map();
17261
+ for (const node of result.nodes) {
17262
+ if (node.groupId) {
17263
+ const list = groupChildMap.get(node.groupId) ?? [];
17264
+ list.push(node.id);
17265
+ groupChildMap.set(node.groupId, list);
17266
+ }
17267
+ }
17268
+ const outbound = /* @__PURE__ */ new Map();
17269
+ for (const edge of result.edges) {
17270
+ const targets = groupChildMap.get(edge.targetId) ?? [edge.targetId];
17271
+ const list = outbound.get(edge.sourceId) ?? [];
17272
+ list.push(...targets);
17273
+ outbound.set(edge.sourceId, list);
17274
+ }
17275
+ const reachable = /* @__PURE__ */ new Set();
17276
+ const queue = [];
17277
+ for (const entry of entries) {
17278
+ reachable.add(entry.id);
17279
+ queue.push(entry.id);
17280
+ }
17281
+ while (queue.length > 0) {
17282
+ const current = queue.shift();
17283
+ for (const next of outbound.get(current) ?? []) {
17284
+ if (!reachable.has(next)) {
17285
+ reachable.add(next);
17286
+ queue.push(next);
17287
+ }
17288
+ }
17289
+ }
17290
+ for (const node of result.nodes) {
17291
+ if (node.isEdge || reachable.has(node.id)) continue;
17292
+ result.diagnostics.push(
17293
+ makeDgmoError(
17294
+ node.lineNumber,
17295
+ `'${node.label}' is unreachable from an 'internet'/'edge' entry \u2014 no request traffic flows to it, so it's dead on an infra diagram. Connect it downstream of an entry, or remove it.`,
17296
+ "warning",
17297
+ "W_INFRA_UNREACHABLE"
17298
+ )
17299
+ );
17300
+ }
17301
+ }
16941
17302
  function stripNodeDecorations(name) {
16942
17303
  let s = name.trim();
16943
17304
  const aliasMatch = s.match(/^(.*?)\s+as\s+[A-Za-z][A-Za-z0-9_]{0,11}\s*$/);
@@ -17227,7 +17588,12 @@ function parseGantt(content, palette) {
17227
17588
  const eraEntryMatch = line11.match(ERA_ENTRY_RE);
17228
17589
  if (eraEntryMatch) {
17229
17590
  const eraLabelRaw = eraEntryMatch[3].trim();
17230
- const eraExtracted = extractColor(eraLabelRaw, palette);
17591
+ const eraExtracted = extractColor(
17592
+ eraLabelRaw,
17593
+ palette,
17594
+ diagnostics,
17595
+ lineNumber
17596
+ );
17231
17597
  result.eras.push({
17232
17598
  startDate: eraEntryMatch[1],
17233
17599
  endDate: eraEntryMatch[2],
@@ -17249,7 +17615,12 @@ function parseGantt(content, palette) {
17249
17615
  const markerEntryMatch = line11.match(MARKER_ENTRY_RE);
17250
17616
  if (markerEntryMatch) {
17251
17617
  const markerLabelRaw = markerEntryMatch[2].trim();
17252
- const markerExtracted = extractColor(markerLabelRaw, palette);
17618
+ const markerExtracted = extractColor(
17619
+ markerLabelRaw,
17620
+ palette,
17621
+ diagnostics,
17622
+ lineNumber
17623
+ );
17253
17624
  result.markers.push({
17254
17625
  date: markerEntryMatch[1],
17255
17626
  label: markerExtracted.label,
@@ -17270,7 +17641,12 @@ function parseGantt(content, palette) {
17270
17641
  } else {
17271
17642
  if (COMMENT_RE.test(line11)) continue;
17272
17643
  const { text: cleanEntry, isDefault } = stripDefaultModifier(line11);
17273
- const extracted = extractColor(cleanEntry, palette);
17644
+ const extracted = extractColor(
17645
+ cleanEntry,
17646
+ palette,
17647
+ diagnostics,
17648
+ lineNumber
17649
+ );
17274
17650
  const color = extracted.color || seriesColors2[currentTagGroup.entries.length % seriesColors2.length] || "#888888";
17275
17651
  const isFirstEntry = currentTagGroup.entries.length === 0;
17276
17652
  currentTagGroup.entries.push({
@@ -17465,7 +17841,12 @@ function parseGantt(content, palette) {
17465
17841
  const startOff = parseOffsetPrefix("+" + eraOffsetMatch[1]);
17466
17842
  const endOff = parseOffsetPrefix("+" + eraOffsetMatch[2]);
17467
17843
  const eraLabelRaw = eraOffsetMatch[3].trim();
17468
- const eraExtracted = extractColor(eraLabelRaw, palette);
17844
+ const eraExtracted = extractColor(
17845
+ eraLabelRaw,
17846
+ palette,
17847
+ diagnostics,
17848
+ lineNumber
17849
+ );
17469
17850
  result.eras.push({
17470
17851
  startDate: "",
17471
17852
  endDate: "",
@@ -17481,7 +17862,12 @@ function parseGantt(content, palette) {
17481
17862
  if (markerOffsetMatch) {
17482
17863
  const dateOff = parseOffsetPrefix("+" + markerOffsetMatch[1]);
17483
17864
  const markerLabelRaw = markerOffsetMatch[2].trim();
17484
- const markerExtracted = extractColor(markerLabelRaw, palette);
17865
+ const markerExtracted = extractColor(
17866
+ markerLabelRaw,
17867
+ palette,
17868
+ diagnostics,
17869
+ lineNumber
17870
+ );
17485
17871
  result.markers.push({
17486
17872
  date: "",
17487
17873
  label: markerExtracted.label,
@@ -17555,7 +17941,12 @@ function parseGantt(content, palette) {
17555
17941
  const eraMatch = line11.match(ERA_RE);
17556
17942
  if (eraMatch) {
17557
17943
  const eraLabelRaw = eraMatch[3].trim();
17558
- const eraExtracted = extractColor(eraLabelRaw, palette);
17944
+ const eraExtracted = extractColor(
17945
+ eraLabelRaw,
17946
+ palette,
17947
+ diagnostics,
17948
+ lineNumber
17949
+ );
17559
17950
  result.eras.push({
17560
17951
  startDate: eraMatch[1],
17561
17952
  endDate: eraMatch[2],
@@ -17573,7 +17964,12 @@ function parseGantt(content, palette) {
17573
17964
  const markerMatch = line11.match(MARKER_RE);
17574
17965
  if (markerMatch) {
17575
17966
  const markerLabelRaw = markerMatch[2].trim();
17576
- const markerExtracted = extractColor(markerLabelRaw, palette);
17967
+ const markerExtracted = extractColor(
17968
+ markerLabelRaw,
17969
+ palette,
17970
+ diagnostics,
17971
+ lineNumber
17972
+ );
17577
17973
  result.markers.push({
17578
17974
  date: markerMatch[1],
17579
17975
  label: markerExtracted.label,
@@ -19045,7 +19441,7 @@ function parseBoxesAndLines(content, palette) {
19045
19441
  const trimmed = raw.trim();
19046
19442
  const indent = measureIndent2(raw);
19047
19443
  if (!trimmed || trimmed.startsWith("//")) continue;
19048
- if (trimmed.includes("|") && !/-\S*\|\S*->/.test(trimmed) && !/~\S*\|\S*~>/.test(trimmed)) {
19444
+ if (trimmed.includes("|") && !ARROW_LABEL_PIPE_DIRECTED_RE.test(trimmed) && !ARROW_LABEL_PIPE_UNDIRECTED_RE.test(trimmed)) {
19049
19445
  result.diagnostics.push(
19050
19446
  makeDgmoError(
19051
19447
  lineNum,
@@ -19084,13 +19480,13 @@ function parseBoxesAndLines(content, palette) {
19084
19480
  for (const pair of pairs) {
19085
19481
  const colonIdx = pair.indexOf(":");
19086
19482
  if (colonIdx > 0) {
19087
- const groupKey = pair.substring(0, colonIdx).trim().toLowerCase();
19483
+ const groupKey2 = pair.substring(0, colonIdx).trim().toLowerCase();
19088
19484
  const value = pair.substring(colonIdx + 1).trim().toLowerCase();
19089
- if (groupKey && value) {
19090
- if (!initialHiddenTagValues.has(groupKey)) {
19091
- initialHiddenTagValues.set(groupKey, /* @__PURE__ */ new Set());
19485
+ if (groupKey2 && value) {
19486
+ if (!initialHiddenTagValues.has(groupKey2)) {
19487
+ initialHiddenTagValues.set(groupKey2, /* @__PURE__ */ new Set());
19092
19488
  }
19093
- initialHiddenTagValues.get(groupKey).add(value);
19489
+ initialHiddenTagValues.get(groupKey2).add(value);
19094
19490
  }
19095
19491
  }
19096
19492
  }
@@ -19174,7 +19570,12 @@ function parseBoxesAndLines(content, palette) {
19174
19570
  if (tagBlockMatch.inlineValues) {
19175
19571
  for (const rawVal of tagBlockMatch.inlineValues) {
19176
19572
  const { text: cleanVal, isDefault } = stripDefaultModifier(rawVal);
19177
- const { label, color } = extractColor(cleanVal);
19573
+ const { label, color } = extractColor(
19574
+ cleanVal,
19575
+ palette,
19576
+ result.diagnostics,
19577
+ lineNum
19578
+ );
19178
19579
  newTagGroup.entries.push({
19179
19580
  value: label,
19180
19581
  color: color ?? AUTO_TAG_COLOR_SENTINEL,
@@ -19191,7 +19592,12 @@ function parseBoxesAndLines(content, palette) {
19191
19592
  }
19192
19593
  if (currentTagGroup && !contentStarted && indent > 0) {
19193
19594
  const { text: cleanEntry, isDefault } = stripDefaultModifier(trimmed);
19194
- const { label, color } = extractColor(cleanEntry);
19595
+ const { label, color } = extractColor(
19596
+ cleanEntry,
19597
+ palette,
19598
+ result.diagnostics,
19599
+ lineNum
19600
+ );
19195
19601
  currentTagGroup.entries.push({
19196
19602
  value: label,
19197
19603
  color: color ?? AUTO_TAG_COLOR_SENTINEL,
@@ -19789,7 +20195,7 @@ function parseEdgeLine(trimmed, lineNum, metaAliasMap, diagnostics, nameAliasMap
19789
20195
  metadata
19790
20196
  };
19791
20197
  }
19792
- var MAX_GROUP_DEPTH;
20198
+ var MAX_GROUP_DEPTH, ARROW_LABEL_PIPE_DIRECTED_RE, ARROW_LABEL_PIPE_UNDIRECTED_RE;
19793
20199
  var init_parser18 = __esm({
19794
20200
  "src/boxes-and-lines/parser.ts"() {
19795
20201
  "use strict";
@@ -19801,6 +20207,8 @@ var init_parser18 = __esm({
19801
20207
  init_reserved_key_registry();
19802
20208
  init_notes();
19803
20209
  MAX_GROUP_DEPTH = 2;
20210
+ ARROW_LABEL_PIPE_DIRECTED_RE = /-\S*\|\S*->/;
20211
+ ARROW_LABEL_PIPE_UNDIRECTED_RE = /~\S*\|\S*~>/;
19804
20212
  }
19805
20213
  });
19806
20214
 
@@ -19820,12 +20228,7 @@ function parseMindmap(content, palette) {
19820
20228
  diagnostics: [],
19821
20229
  error: null
19822
20230
  };
19823
- const fail = (line11, message) => {
19824
- const diag = makeDgmoError(line11, message);
19825
- result.diagnostics.push(diag);
19826
- result.error = formatDgmoError(diag);
19827
- return result;
19828
- };
20231
+ const fail = makeFail(result);
19829
20232
  const pushError = (line11, message) => {
19830
20233
  const diag = makeDgmoError(line11, message);
19831
20234
  result.diagnostics.push(diag);
@@ -19938,7 +20341,12 @@ function parseMindmap(content, palette) {
19938
20341
  const indent2 = measureIndent(line11);
19939
20342
  if (indent2 > 0) {
19940
20343
  const { text: cleanEntry, isDefault } = stripDefaultModifier(trimmed);
19941
- const { label, color } = extractColor(cleanEntry, palette);
20344
+ const { label, color } = extractColor(
20345
+ cleanEntry,
20346
+ palette,
20347
+ result.diagnostics,
20348
+ lineNumber
20349
+ );
19942
20350
  if (isDefault) {
19943
20351
  currentTagGroup.defaultValue = label;
19944
20352
  } else if (currentTagGroup.entries.length === 0) {
@@ -20015,6 +20423,7 @@ function parseMindmap(content, palette) {
20015
20423
  collectAll(result.roots);
20016
20424
  validateTagValues(allNodes, result.tagGroups, pushWarning, suggest);
20017
20425
  validateTagGroupNames(result.tagGroups, pushWarning);
20426
+ cascadeTagMetadata(result.roots, result.tagGroups);
20018
20427
  }
20019
20428
  if (result.roots.length === 0 && !result.error) {
20020
20429
  const diag = makeDgmoError(1, "No nodes found in mindmap");
@@ -20621,7 +21030,12 @@ function parseWireframe(content) {
20621
21030
  }
20622
21031
  if (indent > 0 && currentTagGroup) {
20623
21032
  const { text: cleanEntry, isDefault } = stripDefaultModifier(trimmed);
20624
- const { label, color } = extractColor(cleanEntry);
21033
+ const { label, color } = extractColor(
21034
+ cleanEntry,
21035
+ void 0,
21036
+ diagnostics,
21037
+ lineNumber
21038
+ );
20625
21039
  currentTagGroup.entries.push({
20626
21040
  value: label,
20627
21041
  color: color ?? AUTO_TAG_COLOR_SENTINEL,
@@ -20869,12 +21283,7 @@ function parseTechRadar(content) {
20869
21283
  diagnostics: [],
20870
21284
  error: null
20871
21285
  };
20872
- const fail = (line11, message) => {
20873
- const diag = makeDgmoError(line11, message);
20874
- result.diagnostics.push(diag);
20875
- result.error = formatDgmoError(diag);
20876
- return result;
20877
- };
21286
+ const fail = makeFail(result);
20878
21287
  const warn = (line11, message) => {
20879
21288
  result.diagnostics.push(makeDgmoError(line11, message, "warning"));
20880
21289
  };
@@ -21242,12 +21651,7 @@ function parseCycle(content) {
21242
21651
  let state = "top";
21243
21652
  let currentNode = null;
21244
21653
  let currentEdge = null;
21245
- const fail = (line11, message) => {
21246
- const diag = makeDgmoError(line11, message);
21247
- result.diagnostics.push(diag);
21248
- result.error = formatDgmoError(diag);
21249
- return result;
21250
- };
21654
+ const fail = makeFail(result);
21251
21655
  const warn = (line11, message, severity = "warning") => {
21252
21656
  result.diagnostics.push(makeDgmoError(line11, message, severity));
21253
21657
  };
@@ -21524,12 +21928,7 @@ function parseJourneyMap(content, palette) {
21524
21928
  diagnostics: [],
21525
21929
  error: null
21526
21930
  };
21527
- const fail = (line11, message) => {
21528
- const diag = makeDgmoError(line11, message);
21529
- result.diagnostics.push(diag);
21530
- result.error = formatDgmoError(diag);
21531
- return result;
21532
- };
21931
+ const fail = makeFail(result);
21533
21932
  const warn = (line11, message) => {
21534
21933
  result.diagnostics.push(makeDgmoError(line11, message, "warning"));
21535
21934
  };
@@ -21678,7 +22077,12 @@ function parseJourneyMap(content, palette) {
21678
22077
  if (currentTagGroup && !contentStarted) {
21679
22078
  if (indent > 0) {
21680
22079
  const { text: cleanEntry, isDefault } = stripDefaultModifier(trimmed);
21681
- const { label, color } = extractColor(cleanEntry, palette);
22080
+ const { label, color } = extractColor(
22081
+ cleanEntry,
22082
+ palette,
22083
+ result.diagnostics,
22084
+ lineNumber
22085
+ );
21682
22086
  if (isDefault) {
21683
22087
  currentTagGroup.defaultValue = label;
21684
22088
  } else if (currentTagGroup.entries.length === 0) {
@@ -21813,11 +22217,11 @@ function parseJourneyMap(content, palette) {
21813
22217
  const allSteps = hasPhases ? result.phases.flatMap((p) => p.steps) : result.steps;
21814
22218
  for (const step of allSteps) {
21815
22219
  for (const [tagKey, tagValue] of Object.entries(step.tags)) {
21816
- const groupKey = aliasMap.get(tagKey.toLowerCase()) ?? tagKey.toLowerCase();
21817
- const validValues = tagValueSets.get(groupKey);
22220
+ const groupKey2 = aliasMap.get(tagKey.toLowerCase()) ?? tagKey.toLowerCase();
22221
+ const validValues = tagValueSets.get(groupKey2);
21818
22222
  if (validValues && !validValues.has(tagValue.toLowerCase())) {
21819
- const entries = result.tagGroups.find((g) => g.name.toLowerCase() === groupKey)?.entries.map((e) => e.value);
21820
- let msg = `Unknown tag value "${tagValue}" for group "${groupKey}"`;
22223
+ const entries = result.tagGroups.find((g) => g.name.toLowerCase() === groupKey2)?.entries.map((e) => e.value);
22224
+ let msg = `Unknown tag value "${tagValue}" for group "${groupKey2}"`;
21821
22225
  if (entries) {
21822
22226
  const hint = suggest(tagValue, entries);
21823
22227
  if (hint) msg += `. ${hint}`;
@@ -22050,12 +22454,7 @@ function parsePyramid(content) {
22050
22454
  const lines = content.split("\n");
22051
22455
  let headerParsed = false;
22052
22456
  let currentLayer = null;
22053
- const fail = (line11, message) => {
22054
- const diag = makeDgmoError(line11, message);
22055
- result.diagnostics.push(diag);
22056
- result.error = formatDgmoError(diag);
22057
- return result;
22058
- };
22457
+ const fail = makeFail(result);
22059
22458
  const warn = (line11, message, severity = "warning") => {
22060
22459
  result.diagnostics.push(makeDgmoError(line11, message, severity));
22061
22460
  };
@@ -22202,12 +22601,7 @@ function parseRing(content) {
22202
22601
  const lines = content.split("\n");
22203
22602
  let headerParsed = false;
22204
22603
  let currentLayer = null;
22205
- const fail = (line11, message) => {
22206
- const diag = makeDgmoError(line11, message);
22207
- result.diagnostics.push(diag);
22208
- result.error = formatDgmoError(diag);
22209
- return result;
22210
- };
22604
+ const fail = makeFail(result);
22211
22605
  const warn = (line11, message, severity = "warning") => {
22212
22606
  result.diagnostics.push(makeDgmoError(line11, message, severity));
22213
22607
  };
@@ -22671,12 +23065,7 @@ function parseRaci(content, palette) {
22671
23065
  diagnostics: [],
22672
23066
  error: null
22673
23067
  };
22674
- const fail = (line11, message) => {
22675
- const diag = makeDgmoError(line11, message);
22676
- result.diagnostics.push(diag);
22677
- result.error = formatDgmoError(diag);
22678
- return result;
22679
- };
23068
+ const fail = makeFail(result);
22680
23069
  const warn = (line11, message, code) => {
22681
23070
  result.diagnostics.push(makeDgmoError(line11, message, "warning", code));
22682
23071
  };
@@ -23279,6 +23668,81 @@ function measureInfra(content) {
23279
23668
  const parsed = parseInfra(content);
23280
23669
  return { nodes: parsed.nodes.length };
23281
23670
  }
23671
+ function minDimsSequence(c) {
23672
+ return {
23673
+ width: Math.max((c.participants ?? 2) * 80, 320),
23674
+ height: Math.max((c.messages ?? 1) * 20 + 120, 200)
23675
+ };
23676
+ }
23677
+ function minDimsRaci(c) {
23678
+ return {
23679
+ width: Math.max((c.roles ?? 2) * 50 + 180, 300),
23680
+ height: Math.max((c.tasks ?? 1) * 28 + 80, 200)
23681
+ };
23682
+ }
23683
+ function minDimsMindmap(c) {
23684
+ return {
23685
+ width: Math.max((c.nodes ?? 3) * 30, 300),
23686
+ height: Math.max((c.depth ?? 2) * 60, 200)
23687
+ };
23688
+ }
23689
+ function minDimsTechRadar() {
23690
+ return { width: 360, height: 400 };
23691
+ }
23692
+ function minDimsHeatmap(c) {
23693
+ return {
23694
+ width: Math.max((c.columns ?? 3) * 40, 300),
23695
+ height: Math.max((c.rows ?? 3) * 30 + 60, 200)
23696
+ };
23697
+ }
23698
+ function minDimsArc(c) {
23699
+ return {
23700
+ width: 300,
23701
+ height: Math.max((c.nodes ?? 3) * 20 + 120, 200)
23702
+ };
23703
+ }
23704
+ function minDimsOrg(c) {
23705
+ return {
23706
+ width: Math.max((c.nodes ?? 3) * 60, 300),
23707
+ height: Math.max((c.depth ?? 2) * 80, 200)
23708
+ };
23709
+ }
23710
+ function minDimsGantt(c) {
23711
+ return {
23712
+ width: 400,
23713
+ height: Math.max((c.tasks ?? 3) * 24 + 80, 200)
23714
+ };
23715
+ }
23716
+ function minDimsKanban(c) {
23717
+ return {
23718
+ width: Math.max((c.columns ?? 3) * 120, 360),
23719
+ height: 300
23720
+ };
23721
+ }
23722
+ function minDimsEntities(c) {
23723
+ return {
23724
+ width: Math.max((c.nodes ?? 2) * 140, 300),
23725
+ height: Math.max((c.nodes ?? 2) * 80, 200)
23726
+ };
23727
+ }
23728
+ function minDimsGraph(c) {
23729
+ return {
23730
+ width: Math.max((c.nodes ?? 3) * 60, 300),
23731
+ height: Math.max((c.nodes ?? 3) * 50, 200)
23732
+ };
23733
+ }
23734
+ function minDimsPert(c) {
23735
+ return {
23736
+ width: Math.max((c.tasks ?? 3) * 80, 340),
23737
+ height: Math.max((c.tasks ?? 3) * 40 + 80, 200)
23738
+ };
23739
+ }
23740
+ function minDimsInfra(c) {
23741
+ return {
23742
+ width: Math.max((c.nodes ?? 3) * 80, 300),
23743
+ height: Math.max((c.nodes ?? 3) * 60, 200)
23744
+ };
23745
+ }
23282
23746
  function isExtendedChartParser(parse) {
23283
23747
  return EXTENDED_CHART_DOORS.has(parse);
23284
23748
  }
@@ -23322,33 +23786,50 @@ var init_chart_type_registry = __esm({
23322
23786
  id: "sequence",
23323
23787
  category: "diagram",
23324
23788
  parse: parseSequenceDgmo,
23325
- measure: measureSequence
23789
+ measure: measureSequence,
23790
+ minDims: minDimsSequence
23326
23791
  },
23327
23792
  {
23328
23793
  id: "flowchart",
23329
23794
  category: "diagram",
23330
23795
  parse: parseFlowchart,
23331
- measure: measureFlowchart
23796
+ measure: measureFlowchart,
23797
+ minDims: minDimsGraph
23332
23798
  },
23333
23799
  {
23334
23800
  id: "class",
23335
23801
  category: "diagram",
23336
23802
  parse: parseClassDiagram,
23337
- measure: measureClass
23803
+ measure: measureClass,
23804
+ minDims: minDimsEntities
23805
+ },
23806
+ {
23807
+ id: "er",
23808
+ category: "diagram",
23809
+ parse: parseERDiagram,
23810
+ measure: measureER,
23811
+ minDims: minDimsEntities
23338
23812
  },
23339
- { id: "er", category: "diagram", parse: parseERDiagram, measure: measureER },
23340
23813
  {
23341
23814
  id: "state",
23342
23815
  category: "diagram",
23343
23816
  parse: parseState,
23344
- measure: measureStateGraph
23817
+ measure: measureStateGraph,
23818
+ minDims: minDimsGraph
23819
+ },
23820
+ {
23821
+ id: "org",
23822
+ category: "diagram",
23823
+ parse: parseOrg,
23824
+ measure: measureOrg,
23825
+ minDims: minDimsOrg
23345
23826
  },
23346
- { id: "org", category: "diagram", parse: parseOrg, measure: measureOrg },
23347
23827
  {
23348
23828
  id: "kanban",
23349
23829
  category: "diagram",
23350
23830
  parse: parseKanban,
23351
- measure: measureKanban
23831
+ measure: measureKanban,
23832
+ minDims: minDimsKanban
23352
23833
  },
23353
23834
  { id: "c4", category: "diagram", parse: parseC4 },
23354
23835
  { id: "sitemap", category: "diagram", parse: parseSitemap },
@@ -23356,25 +23837,40 @@ var init_chart_type_registry = __esm({
23356
23837
  id: "infra",
23357
23838
  category: "diagram",
23358
23839
  parse: parseInfra,
23359
- measure: measureInfra
23840
+ measure: measureInfra,
23841
+ minDims: minDimsInfra
23360
23842
  },
23361
23843
  {
23362
23844
  id: "gantt",
23363
23845
  category: "diagram",
23364
23846
  parse: parseGantt,
23365
- measure: measureGantt
23847
+ measure: measureGantt,
23848
+ minDims: minDimsGantt
23849
+ },
23850
+ {
23851
+ id: "pert",
23852
+ category: "diagram",
23853
+ parse: parsePert,
23854
+ measure: measurePert,
23855
+ minDims: minDimsPert
23366
23856
  },
23367
- { id: "pert", category: "diagram", parse: parsePert, measure: measurePert },
23368
23857
  { id: "boxes-and-lines", category: "diagram", parse: parseBoxesAndLines },
23369
23858
  {
23370
23859
  id: "mindmap",
23371
23860
  category: "diagram",
23372
23861
  parse: parseMindmap,
23373
- measure: measureMindmap
23862
+ measure: measureMindmap,
23863
+ minDims: minDimsMindmap
23374
23864
  },
23375
23865
  { id: "wireframe", category: "diagram", parse: parseWireframe },
23376
23866
  { id: "journey-map", category: "diagram", parse: parseJourneyMap },
23377
- { id: "raci", category: "diagram", parse: parseRaci, measure: measureRaci },
23867
+ {
23868
+ id: "raci",
23869
+ category: "diagram",
23870
+ parse: parseRaci,
23871
+ measure: measureRaci,
23872
+ minDims: minDimsRaci
23873
+ },
23378
23874
  { id: "rasci", category: "diagram", parse: parseRaci, measure: measureRaci },
23379
23875
  { id: "daci", category: "diagram", parse: parseRaci, measure: measureRaci },
23380
23876
  // ── Standard ECharts charts (parseChart) ──────────────────
@@ -23396,7 +23892,8 @@ var init_chart_type_registry = __esm({
23396
23892
  id: "heatmap",
23397
23893
  category: "data-chart",
23398
23894
  parse: parseHeatmap,
23399
- measure: measureHeatmap
23895
+ measure: measureHeatmap,
23896
+ minDims: minDimsHeatmap
23400
23897
  },
23401
23898
  { id: "funnel", category: "data-chart", parse: parseFunnel },
23402
23899
  // ── D3 visualizations — own per-viz parser door (Story 109.2) ──
@@ -23406,7 +23903,8 @@ var init_chart_type_registry = __esm({
23406
23903
  id: "arc",
23407
23904
  category: "visualization",
23408
23905
  parse: parseArc,
23409
- measure: measureArc
23906
+ measure: measureArc,
23907
+ minDims: minDimsArc
23410
23908
  },
23411
23909
  { id: "timeline", category: "visualization", parse: parseTimeline },
23412
23910
  { id: "venn", category: "visualization", parse: parseVenn },
@@ -23416,7 +23914,8 @@ var init_chart_type_registry = __esm({
23416
23914
  id: "tech-radar",
23417
23915
  category: "visualization",
23418
23916
  parse: parseTechRadar,
23419
- measure: measureTechRadar
23917
+ measure: measureTechRadar,
23918
+ minDims: minDimsTechRadar
23420
23919
  },
23421
23920
  { id: "cycle", category: "visualization", parse: parseCycle },
23422
23921
  { id: "pyramid", category: "visualization", parse: parsePyramid },
@@ -24637,7 +25136,7 @@ function nodeStroke(palette, nodeColor2) {
24637
25136
  }
24638
25137
  function containerFill(palette, isDark, nodeColor2) {
24639
25138
  if (nodeColor2) {
24640
- return mix(nodeColor2, isDark ? palette.surface : palette.bg, 10);
25139
+ return mix(nodeColor2, themeBaseBg(palette, isDark), 10);
24641
25140
  }
24642
25141
  return mix(palette.surface, palette.bg, 40);
24643
25142
  }
@@ -24795,10 +25294,15 @@ function renderOrg(container, parsed, layout, palette, isDark, onClickItem, expo
24795
25294
  const iconY = iconPad;
24796
25295
  const focusG = cG.append("g").attr("class", "org-focus-icon").attr("data-focus-node", c.nodeId).attr("data-export-ignore", "true").attr("transform", `translate(${iconX}, ${iconY})`);
24797
25296
  focusG.append("rect").attr("x", -3).attr("y", -3).attr("width", iconSize + 6).attr("height", iconSize + 6).attr("fill", "transparent");
25297
+ const iconColor = contrastText(
25298
+ fill2,
25299
+ palette.textOnFillLight,
25300
+ palette.textOnFillDark
25301
+ );
24798
25302
  const cx = iconSize / 2;
24799
25303
  const cy = iconSize / 2;
24800
- focusG.append("circle").attr("cx", cx).attr("cy", cy).attr("r", iconSize / 2 - 1).attr("fill", "none").attr("stroke", palette.textMuted).attr("stroke-width", 1.5);
24801
- focusG.append("circle").attr("cx", cx).attr("cy", cy).attr("r", 2).attr("fill", palette.textMuted);
25304
+ focusG.append("circle").attr("cx", cx).attr("cy", cy).attr("r", iconSize / 2 - 1).attr("fill", "none").attr("stroke", iconColor).attr("stroke-width", 1.5);
25305
+ focusG.append("circle").attr("cx", cx).attr("cy", cy).attr("r", 2).attr("fill", iconColor);
24802
25306
  }
24803
25307
  }
24804
25308
  for (const edge of layout.edges) {
@@ -24887,10 +25391,11 @@ function renderOrg(container, parsed, layout, palette, isDark, onClickItem, expo
24887
25391
  const iconY = iconPad;
24888
25392
  const focusG = nodeG.append("g").attr("class", "org-focus-icon").attr("data-focus-node", node.id).attr("data-export-ignore", "true").attr("transform", `translate(${iconX}, ${iconY})`);
24889
25393
  focusG.append("rect").attr("x", -3).attr("y", -3).attr("width", iconSize + 6).attr("height", iconSize + 6).attr("fill", "transparent");
25394
+ const iconColor = labelColor;
24890
25395
  const cx = iconSize / 2;
24891
25396
  const cy = iconSize / 2;
24892
- focusG.append("circle").attr("cx", cx).attr("cy", cy).attr("r", iconSize / 2 - 1).attr("fill", "none").attr("stroke", palette.textMuted).attr("stroke-width", 1.5);
24893
- focusG.append("circle").attr("cx", cx).attr("cy", cy).attr("r", 2).attr("fill", palette.textMuted);
25397
+ focusG.append("circle").attr("cx", cx).attr("cy", cy).attr("r", iconSize / 2 - 1).attr("fill", "none").attr("stroke", iconColor).attr("stroke-width", 1.5);
25398
+ focusG.append("circle").attr("cx", cx).attr("cy", cy).attr("r", 2).attr("fill", iconColor);
24894
25399
  }
24895
25400
  }
24896
25401
  if (hasAncestorTrail) {
@@ -24987,16 +25492,16 @@ function renderOrg(container, parsed, layout, palette, isDark, onClickItem, expo
24987
25492
  const computedLayout = legendHandle.getLayout();
24988
25493
  if (computedLayout.activeCapsule?.addonX != null) {
24989
25494
  const capsule = computedLayout.activeCapsule;
24990
- const groupKey = capsule.groupName.toLowerCase();
24991
- const isHidden = hiddenAttributes?.has(groupKey) ?? false;
25495
+ const groupKey2 = capsule.groupName.toLowerCase();
25496
+ const isHidden = hiddenAttributes?.has(groupKey2) ?? false;
24992
25497
  const activeGroupEl = legendParentBase.select(
24993
- `[data-legend-group="${groupKey}"]`
25498
+ `[data-legend-group="${groupKey2}"]`
24994
25499
  );
24995
25500
  if (!activeGroupEl.empty()) {
24996
25501
  const eyeX = capsule.addonX;
24997
25502
  const eyeY = (LEGEND_HEIGHT - LEGEND_EYE_SIZE) / 2;
24998
25503
  const hitPad = 6;
24999
- const eyeG = activeGroupEl.append("g").attr("class", "org-legend-eye").attr("data-legend-visibility", groupKey).style("cursor", "pointer").attr("opacity", isHidden ? 0.4 : 0.7);
25504
+ const eyeG = activeGroupEl.append("g").attr("class", "org-legend-eye").attr("data-legend-visibility", groupKey2).style("cursor", "pointer").attr("opacity", isHidden ? 0.4 : 0.7);
25000
25505
  eyeG.append("rect").attr("x", eyeX - hitPad).attr("y", eyeY - hitPad).attr("width", LEGEND_EYE_SIZE + hitPad * 2).attr("height", LEGEND_EYE_SIZE + hitPad * 2).attr("fill", "transparent").attr("pointer-events", "all");
25001
25506
  eyeG.append("path").attr("d", isHidden ? EYE_CLOSED_PATH : EYE_OPEN_PATH).attr("transform", `translate(${eyeX}, ${eyeY})`).attr("fill", "none").attr("stroke", palette.textMuted).attr("stroke-width", 1.2).attr("stroke-linecap", "round").attr("stroke-linejoin", "round");
25002
25507
  }
@@ -25811,7 +26316,7 @@ function nodeStroke2(_palette, nodeColor2) {
25811
26316
  }
25812
26317
  function containerFill2(palette, isDark, nodeColor2) {
25813
26318
  if (nodeColor2) {
25814
- return mix(nodeColor2, isDark ? palette.surface : palette.bg, 10);
26319
+ return mix(nodeColor2, themeBaseBg(palette, isDark), 10);
25815
26320
  }
25816
26321
  return mix(palette.surface, palette.bg, 40);
25817
26322
  }
@@ -26114,14 +26619,14 @@ function renderLegend(parent, legendGroups, palette, isDark, activeTagGroup, fix
26114
26619
  const computedLayout = legendHandle.getLayout();
26115
26620
  if (computedLayout.activeCapsule?.addonX != null) {
26116
26621
  const capsule = computedLayout.activeCapsule;
26117
- const groupKey = capsule.groupName.toLowerCase();
26118
- const isHidden = hiddenAttributes?.has(groupKey) ?? false;
26119
- const activeGroupEl = parent.select(`[data-legend-group="${groupKey}"]`);
26622
+ const groupKey2 = capsule.groupName.toLowerCase();
26623
+ const isHidden = hiddenAttributes?.has(groupKey2) ?? false;
26624
+ const activeGroupEl = parent.select(`[data-legend-group="${groupKey2}"]`);
26120
26625
  if (!activeGroupEl.empty()) {
26121
26626
  const eyeX = capsule.addonX;
26122
26627
  const eyeY = (LEGEND_HEIGHT - LEGEND_EYE_SIZE) / 2;
26123
26628
  const hitPad = 6;
26124
- const eyeG = activeGroupEl.append("g").attr("class", "sitemap-legend-eye").attr("data-legend-visibility", groupKey).style("cursor", "pointer").attr("opacity", isHidden ? 0.4 : 0.7);
26629
+ const eyeG = activeGroupEl.append("g").attr("class", "sitemap-legend-eye").attr("data-legend-visibility", groupKey2).style("cursor", "pointer").attr("opacity", isHidden ? 0.4 : 0.7);
26125
26630
  eyeG.append("rect").attr("x", eyeX - hitPad).attr("y", eyeY - hitPad).attr("width", LEGEND_EYE_SIZE + hitPad * 2).attr("height", LEGEND_EYE_SIZE + hitPad * 2).attr("fill", "transparent").attr("pointer-events", "all");
26126
26631
  eyeG.append("path").attr("d", isHidden ? EYE_CLOSED_PATH : EYE_OPEN_PATH).attr("transform", `translate(${eyeX}, ${eyeY})`).attr("fill", "none").attr("stroke", palette.textMuted).attr("stroke-width", 1.2).attr("stroke-linecap", "round").attr("stroke-linejoin", "round");
26127
26632
  }
@@ -28708,7 +29213,8 @@ function renderBoxesAndLines(container, parsed, layout, palette, isDark, options
28708
29213
  onToggleDescriptions,
28709
29214
  onToggleControlsExpand,
28710
29215
  exportMode = false,
28711
- controlsHost
29216
+ controlsHost,
29217
+ rampDomain
28712
29218
  } = options ?? {};
28713
29219
  d3Selection11.select(container).selectAll(":not([data-d3-tooltip])").remove();
28714
29220
  const width = exportDims?.width ?? container.clientWidth;
@@ -28728,8 +29234,8 @@ function renderBoxesAndLines(container, parsed, layout, palette, isDark, options
28728
29234
  const sTitleY = sctx.structural(TITLE_Y);
28729
29235
  const nodeValues = parsed.nodes.filter((n) => n.value !== void 0).map((n) => n.value);
28730
29236
  const hasRamp = nodeValues.length > 0;
28731
- const rampMin = hasRamp ? Math.min(...nodeValues) : 0;
28732
- const rampMax = Math.max(...nodeValues);
29237
+ const rampMin = rampDomain?.min ?? (hasRamp ? Math.min(...nodeValues) : 0);
29238
+ const rampMax = rampDomain?.max ?? Math.max(...nodeValues);
28733
29239
  const rampHue = resolveColor(parsed.boxMetricColor ?? "", palette) ?? palette.primary;
28734
29240
  const rampLow = parsed.boxMetricLowColor ? resolveColor(parsed.boxMetricLowColor, palette) ?? void 0 : void 0;
28735
29241
  const rampBase = isDark ? mix(palette.surface, palette.text, 28) : palette.bg;
@@ -28881,7 +29387,7 @@ function renderBoxesAndLines(container, parsed, layout, palette, isDark, options
28881
29387
  group.collapsed ? "bl-group bl-group-collapsed" : "bl-group"
28882
29388
  ).attr("data-line-number", String(group.lineNumber)).attr("data-node-id", group.label).attr("data-group-toggle", group.label).style("cursor", "pointer");
28883
29389
  if (group.collapsed) {
28884
- const fillColor = isDark ? palette.surface : palette.bg;
29390
+ const fillColor = themeBaseBg(palette, isDark);
28885
29391
  const strokeColor = palette.border;
28886
29392
  groupG.append("rect").attr("x", gx).attr("y", gy).attr("width", group.width).attr("height", group.height).attr("rx", NODE_RX).attr("ry", NODE_RX).attr("fill", fillColor).attr("stroke", strokeColor).attr("stroke-width", sNodeStrokeWidth);
28887
29393
  const clipId = `bl-clip-${group.label.replace(/[[\]\s]/g, "")}`;
@@ -28909,8 +29415,8 @@ function renderBoxesAndLines(container, parsed, layout, palette, isDark, options
28909
29415
  const color = edgeColorMap.get(i) ?? palette.textMuted;
28910
29416
  if (hidden.size > 0) {
28911
29417
  let isHidden = false;
28912
- for (const [groupKey, hiddenVals] of hidden) {
28913
- const val = le.metadata[groupKey];
29418
+ for (const [groupKey2, hiddenVals] of hidden) {
29419
+ const val = le.metadata[groupKey2];
28914
29420
  if (val && hiddenVals.has(val.toLowerCase())) {
28915
29421
  isHidden = true;
28916
29422
  break;
@@ -29010,8 +29516,8 @@ function renderBoxesAndLines(container, parsed, layout, palette, isDark, options
29010
29516
  if (!node) continue;
29011
29517
  if (hidden.size > 0) {
29012
29518
  let isHidden = false;
29013
- for (const [groupKey, hiddenVals] of hidden) {
29014
- const val = node.metadata[groupKey];
29519
+ for (const [groupKey2, hiddenVals] of hidden) {
29520
+ const val = node.metadata[groupKey2];
29015
29521
  if (val && hiddenVals.has(val.toLowerCase())) {
29016
29522
  isHidden = true;
29017
29523
  break;
@@ -29237,6 +29743,15 @@ function renderBoxesAndLines(container, parsed, layout, palette, isDark, options
29237
29743
  });
29238
29744
  legendG.selectAll("[data-legend-group]").classed("bl-legend-group", true);
29239
29745
  }
29746
+ if (!exportDims && !exportMode) {
29747
+ const iconSize = 14;
29748
+ const focusG = svg.append("g").attr("class", "bl-focus-icon").attr("data-export-ignore", "true").style("display", "none").style("pointer-events", "auto").style("cursor", "pointer");
29749
+ focusG.append("rect").attr("x", -3).attr("y", -3).attr("width", iconSize + 6).attr("height", iconSize + 6).attr("fill", "transparent");
29750
+ const cx = iconSize / 2;
29751
+ const cy = iconSize / 2;
29752
+ focusG.append("circle").attr("cx", cx).attr("cy", cy).attr("r", iconSize / 2 - 1).attr("fill", palette.bg).attr("stroke", palette.textMuted).attr("stroke-width", 1.5);
29753
+ focusG.append("circle").attr("cx", cx).attr("cy", cy).attr("r", 2).attr("fill", palette.textMuted);
29754
+ }
29240
29755
  }
29241
29756
  function renderBoxesAndLinesForExport(container, parsed, layout, palette, isDark, options) {
29242
29757
  renderBoxesAndLines(container, parsed, layout, palette, isDark, {
@@ -29833,7 +30348,7 @@ function shuffle(a, r) {
29833
30348
  return x;
29834
30349
  }
29835
30350
  function flatten(d) {
29836
- const toks = d.match(/[MLQC]|-?\d*\.?\d+(?:e-?\d+)?/gi) ?? [];
30351
+ const toks = d.match(PATH_TOKEN_RE) ?? [];
29837
30352
  const pts = [];
29838
30353
  let i = 0, cx = 0, cy = 0, cmd = "";
29839
30354
  const num = () => parseFloat(toks[i++]);
@@ -29877,17 +30392,10 @@ function flatten(d) {
29877
30392
  }
29878
30393
  return pts;
29879
30394
  }
29880
- function segPoint(p1, p2, p3, p4) {
29881
- const den = (p2.x - p1.x) * (p4.y - p3.y) - (p2.y - p1.y) * (p4.x - p3.x);
29882
- if (Math.abs(den) < 1e-9) return null;
29883
- const t = ((p3.x - p1.x) * (p4.y - p3.y) - (p3.y - p1.y) * (p4.x - p3.x)) / den, u = ((p3.x - p1.x) * (p2.y - p1.y) - (p3.y - p1.y) * (p2.x - p1.x)) / den;
29884
- return t > 0 && t < 1 && u > 0 && u < 1 ? { x: p1.x + t * (p2.x - p1.x), y: p1.y + t * (p2.y - p1.y) } : null;
29885
- }
29886
- function countSplineCrossings(layout) {
29887
- const center = /* @__PURE__ */ new Map();
29888
- for (const n of layout.nodes) center.set(n.label, { x: n.x, y: n.y });
29889
- for (const g of layout.groups)
29890
- if (g.collapsed) center.set("__group_" + g.label, { x: g.x, y: g.y });
30395
+ function flatPolys(layout) {
30396
+ const key = layout.edges;
30397
+ const hit = FLAT_CACHE.get(key);
30398
+ if (hit) return hit;
29891
30399
  const polys = layout.edges.map((e) => {
29892
30400
  const pts = e.points.length >= 2 ? flatten(splineGen(e.points) ?? "") : [];
29893
30401
  let x0 = Infinity, y0 = Infinity, x1 = -Infinity, y1 = -Infinity;
@@ -29897,8 +30405,24 @@ function countSplineCrossings(layout) {
29897
30405
  if (p.y < y0) y0 = p.y;
29898
30406
  if (p.y > y1) y1 = p.y;
29899
30407
  }
29900
- return { pts, s: e.source, t: e.target, x0, y0, x1, y1 };
30408
+ return { pts, x0, y0, x1, y1 };
29901
30409
  });
30410
+ FLAT_CACHE.set(key, polys);
30411
+ return polys;
30412
+ }
30413
+ function segPoint(p1, p2, p3, p4) {
30414
+ const den = (p2.x - p1.x) * (p4.y - p3.y) - (p2.y - p1.y) * (p4.x - p3.x);
30415
+ if (Math.abs(den) < 1e-9) return null;
30416
+ const t = ((p3.x - p1.x) * (p4.y - p3.y) - (p3.y - p1.y) * (p4.x - p3.x)) / den, u = ((p3.x - p1.x) * (p2.y - p1.y) - (p3.y - p1.y) * (p2.x - p1.x)) / den;
30417
+ return t > 0 && t < 1 && u > 0 && u < 1 ? { x: p1.x + t * (p2.x - p1.x), y: p1.y + t * (p2.y - p1.y) } : null;
30418
+ }
30419
+ function countSplineCrossings(layout, floor = Infinity) {
30420
+ const center = /* @__PURE__ */ new Map();
30421
+ for (const n of layout.nodes) center.set(n.label, { x: n.x, y: n.y });
30422
+ for (const g of layout.groups)
30423
+ if (g.collapsed) center.set("__group_" + g.label, { x: g.x, y: g.y });
30424
+ const polys = flatPolys(layout);
30425
+ const edges = layout.edges;
29902
30426
  const R = 34;
29903
30427
  let total = 0;
29904
30428
  for (let a = 0; a < polys.length; a++)
@@ -29906,23 +30430,33 @@ function countSplineCrossings(layout) {
29906
30430
  const A = polys[a], B = polys[b];
29907
30431
  if (A.pts.length < 2 || B.pts.length < 2) continue;
29908
30432
  if (A.x1 < B.x0 || B.x1 < A.x0 || A.y1 < B.y0 || B.y1 < A.y0) continue;
29909
- const shared = [A.s, A.t].filter((n) => n === B.s || n === B.t).map((n) => center.get(n)).filter(Boolean);
30433
+ const ea = edges[a], eb = edges[b];
30434
+ let sh0, sh1;
30435
+ if (ea.source === eb.source || ea.source === eb.target)
30436
+ sh0 = center.get(ea.source);
30437
+ if (ea.target === eb.source || ea.target === eb.target)
30438
+ sh1 = center.get(ea.target);
29910
30439
  const hits = [];
29911
- for (let i = 1; i < A.pts.length; i++)
29912
- for (let j = 1; j < B.pts.length; j++) {
29913
- const p = segPoint(
29914
- A.pts[i - 1],
29915
- A.pts[i],
29916
- B.pts[j - 1],
29917
- B.pts[j]
29918
- );
30440
+ const ap = A.pts, bp = B.pts;
30441
+ for (let i = 1; i < ap.length; i++) {
30442
+ const a0 = ap[i - 1], a1 = ap[i];
30443
+ const axMin = a0.x < a1.x ? a0.x : a1.x, axMax = a0.x > a1.x ? a0.x : a1.x, ayMin = a0.y < a1.y ? a0.y : a1.y, ayMax = a0.y > a1.y ? a0.y : a1.y;
30444
+ for (let j = 1; j < bp.length; j++) {
30445
+ const b0 = bp[j - 1], b1 = bp[j];
30446
+ if (axMax < (b0.x < b1.x ? b0.x : b1.x)) continue;
30447
+ if ((b0.x > b1.x ? b0.x : b1.x) < axMin) continue;
30448
+ if (ayMax < (b0.y < b1.y ? b0.y : b1.y)) continue;
30449
+ if ((b0.y > b1.y ? b0.y : b1.y) < ayMin) continue;
30450
+ const p = segPoint(a0, a1, b0, b1);
29919
30451
  if (!p) continue;
29920
- if (shared.some((c) => Math.hypot(p.x - c.x, p.y - c.y) < R))
29921
- continue;
30452
+ if (sh0 && Math.hypot(p.x - sh0.x, p.y - sh0.y) < R) continue;
30453
+ if (sh1 && Math.hypot(p.x - sh1.x, p.y - sh1.y) < R) continue;
29922
30454
  if (!hits.some((h) => Math.hypot(h.x - p.x, h.y - p.y) < 6))
29923
30455
  hits.push(p);
29924
30456
  }
30457
+ }
29925
30458
  total += hits.length;
30459
+ if (total > floor) return total;
29926
30460
  }
29927
30461
  return total;
29928
30462
  }
@@ -29960,17 +30494,8 @@ function detectEdgeOverlaps(layout, opts) {
29960
30494
  w: g.width,
29961
30495
  h: g.height
29962
30496
  });
29963
- const polys = layout.edges.map((e) => {
29964
- const pts = e.points.length >= 2 ? flatten(splineGen(e.points) ?? "") : [];
29965
- let x0 = Infinity, y0 = Infinity, x1 = -Infinity, y1 = -Infinity;
29966
- for (const p of pts) {
29967
- if (p.x < x0) x0 = p.x;
29968
- if (p.x > x1) x1 = p.x;
29969
- if (p.y < y0) y0 = p.y;
29970
- if (p.y > y1) y1 = p.y;
29971
- }
29972
- return { pts, s: e.source, t: e.target, x0, y0, x1, y1 };
29973
- });
30497
+ const polys = flatPolys(layout);
30498
+ const edges = layout.edges;
29974
30499
  const runs = [];
29975
30500
  for (let a = 0; a < polys.length; a++)
29976
30501
  for (let b = a + 1; b < polys.length; b++) {
@@ -29978,7 +30503,12 @@ function detectEdgeOverlaps(layout, opts) {
29978
30503
  if (A.pts.length < 2 || B.pts.length < 2) continue;
29979
30504
  if (A.x1 + dist < B.x0 || B.x1 + dist < A.x0 || A.y1 + dist < B.y0 || B.y1 + dist < A.y0)
29980
30505
  continue;
29981
- const shared = [A.s, A.t].filter((n) => n === B.s || n === B.t).map((n) => rect.get(n)).filter(Boolean);
30506
+ const ea = edges[a], eb = edges[b];
30507
+ let shr0, shr1;
30508
+ if (ea.source === eb.source || ea.source === eb.target)
30509
+ shr0 = rect.get(ea.source);
30510
+ if (ea.target === eb.source || ea.target === eb.target)
30511
+ shr1 = rect.get(ea.target);
29982
30512
  let run = [];
29983
30513
  let runLen = 0;
29984
30514
  const flush = () => {
@@ -29992,7 +30522,7 @@ function detectEdgeOverlaps(layout, opts) {
29992
30522
  runLen = 0;
29993
30523
  };
29994
30524
  for (const p of A.pts) {
29995
- const nearShared = shared.some((r) => pointRectDist(p, r) < nodeClear);
30525
+ const nearShared = shr0 !== void 0 && pointRectDist(p, shr0) < nodeClear || shr1 !== void 0 && pointRectDist(p, shr1) < nodeClear;
29996
30526
  const covered = !nearShared && distToPoly(p, B.pts) < dist;
29997
30527
  if (covered) {
29998
30528
  if (run.length)
@@ -30027,9 +30557,10 @@ function detectEdgeNodePierces(layout, opts) {
30027
30557
  });
30028
30558
  const inside = (p, r) => Math.abs(p.x - r.x) < r.w / 2 - inset && Math.abs(p.y - r.y) < r.h / 2 - inset;
30029
30559
  const out = [];
30560
+ const polys = flatPolys(layout);
30030
30561
  layout.edges.forEach((e, idx) => {
30031
30562
  if (e.points.length < 2) return;
30032
- const poly = flatten(splineGen(e.points) ?? "");
30563
+ const poly = polys[idx].pts;
30033
30564
  for (const r of rects) {
30034
30565
  if (r.key === e.source || r.key === e.target || "__group_" + r.key === e.source || "__group_" + r.key === e.target)
30035
30566
  continue;
@@ -30376,8 +30907,10 @@ function edgeLength(layout) {
30376
30907
  );
30377
30908
  return total;
30378
30909
  }
30379
- function layoutBoxesAndLinesSearch(parsed, collapseInfo, opts) {
30910
+ async function layoutBoxesAndLinesSearch(parsed, collapseInfo, opts) {
30380
30911
  const hideDescriptions = opts?.hideDescriptions ?? false;
30912
+ const onProgress = opts?.onProgress;
30913
+ const tick = onProgress ? () => new Promise((r) => setTimeout(r)) : () => void 0;
30381
30914
  const collapsedGroupLabels = /* @__PURE__ */ new Set();
30382
30915
  if (collapseInfo) {
30383
30916
  const missing = /* @__PURE__ */ new Set();
@@ -30791,17 +31324,25 @@ function layoutBoxesAndLinesSearch(parsed, collapseInfo, opts) {
30791
31324
  seed: s
30792
31325
  });
30793
31326
  const badness = (lay, floor) => {
30794
- const x = countSplineCrossings(lay);
31327
+ const x = countSplineCrossings(lay, floor);
30795
31328
  if (x > floor) return Infinity;
30796
31329
  return x + countEdgeOverlaps(lay) + countEdgeNodePierces(lay) + countGroupOverlaps(lay);
30797
31330
  };
30798
31331
  const objective = (lay, viol) => viol * 1e6 + edgeLength(lay) + lambda * meanDrift(lay, prev) * 10;
31332
+ const progressTotal = configs.length + Math.min(opts?.refineK ?? 6, configs.length);
31333
+ let progressDone = 0;
31334
+ const step = async (phase) => {
31335
+ if (!onProgress) return;
31336
+ onProgress(++progressDone, progressTotal, phase);
31337
+ await tick();
31338
+ };
30799
31339
  const pool = [];
30800
31340
  for (const cfg of configs) {
30801
31341
  try {
30802
31342
  pool.push(place(cfg));
30803
31343
  } catch {
30804
31344
  }
31345
+ await step("Optimizing layout");
30805
31346
  }
30806
31347
  if (!pool.length)
30807
31348
  return place({ ranker: "network-simplex", nodesep: 50, ranksep: 60 });
@@ -30810,9 +31351,9 @@ function layoutBoxesAndLinesSearch(parsed, collapseInfo, opts) {
30810
31351
  layered = layeredCandidates(parsed, sizes);
30811
31352
  } catch {
30812
31353
  }
30813
- pool.sort(
30814
- (a, b) => objective(a, countCrossingsFast(a)) - objective(b, countCrossingsFast(b))
30815
- );
31354
+ const fastKey = /* @__PURE__ */ new Map();
31355
+ for (const lay of pool) fastKey.set(lay, objective(lay, countCrossingsFast(lay)));
31356
+ pool.sort((a, b) => fastKey.get(a) - fastKey.get(b));
30816
31357
  const refineK = Math.min(REFINE_K, pool.length);
30817
31358
  let best = pool[0];
30818
31359
  let bestObj = Infinity;
@@ -30827,7 +31368,10 @@ function layoutBoxesAndLinesSearch(parsed, collapseInfo, opts) {
30827
31368
  best = lay;
30828
31369
  }
30829
31370
  };
30830
- for (const lay of pool.slice(0, refineK)) consider(lay);
31371
+ for (const lay of pool.slice(0, refineK)) {
31372
+ consider(lay);
31373
+ await step("Refining layout");
31374
+ }
30831
31375
  if (bestBad >= ESCALATE_THRESHOLD && n <= ESCALATE_MAX_N) {
30832
31376
  const extra = [];
30833
31377
  for (let s = seedCount; s < seedCount + ESCALATE_SEEDS; s++) {
@@ -30843,9 +31387,10 @@ function layoutBoxesAndLinesSearch(parsed, collapseInfo, opts) {
30843
31387
  } catch {
30844
31388
  }
30845
31389
  }
30846
- extra.sort(
30847
- (a, b) => objective(a, countCrossingsFast(a)) - objective(b, countCrossingsFast(b))
30848
- );
31390
+ const extraKey = /* @__PURE__ */ new Map();
31391
+ for (const lay of extra)
31392
+ extraKey.set(lay, objective(lay, countCrossingsFast(lay)));
31393
+ extra.sort((a, b) => extraKey.get(a) - extraKey.get(b));
30849
31394
  for (const lay of extra.slice(0, ESCALATE_REFINE)) consider(lay);
30850
31395
  }
30851
31396
  for (const lay of layered) {
@@ -30872,7 +31417,7 @@ function layoutBoxesAndLinesSearch(parsed, collapseInfo, opts) {
30872
31417
  }
30873
31418
  return best;
30874
31419
  }
30875
- var import_dagre4, import_d3_shape, DEFAULT_LAMBDA, ESCALATE_THRESHOLD, ESCALATE_MAX_N, ESCALATE_SEEDS, ESCALATE_REFINE, splineGen, GROUP_LABEL_ZONE2;
31420
+ var import_dagre4, import_d3_shape, DEFAULT_LAMBDA, ESCALATE_THRESHOLD, ESCALATE_MAX_N, ESCALATE_SEEDS, ESCALATE_REFINE, splineGen, PATH_TOKEN_RE, FLAT_CACHE, GROUP_LABEL_ZONE2;
30876
31421
  var init_layout_search = __esm({
30877
31422
  "src/boxes-and-lines/layout-search.ts"() {
30878
31423
  "use strict";
@@ -30886,6 +31431,8 @@ var init_layout_search = __esm({
30886
31431
  ESCALATE_SEEDS = 18;
30887
31432
  ESCALATE_REFINE = 10;
30888
31433
  splineGen = (0, import_d3_shape.line)().x((d) => d.x).y((d) => d.y).curve(import_d3_shape.curveBasis);
31434
+ PATH_TOKEN_RE = /[MLQC]|-?\d*\.?\d+(?:e-?\d+)?/gi;
31435
+ FLAT_CACHE = /* @__PURE__ */ new WeakMap();
30889
31436
  GROUP_LABEL_ZONE2 = 32;
30890
31437
  }
30891
31438
  });
@@ -30970,12 +31517,15 @@ function computeNodeSize(node, reserveValueRow) {
30970
31517
  }
30971
31518
  async function layoutBoxesAndLines(parsed, collapseInfo, layoutOptions) {
30972
31519
  const { layoutBoxesAndLinesSearch: layoutBoxesAndLinesSearch2 } = await Promise.resolve().then(() => (init_layout_search(), layout_search_exports));
30973
- const searched = layoutBoxesAndLinesSearch2(parsed, collapseInfo, {
31520
+ const searched = await layoutBoxesAndLinesSearch2(parsed, collapseInfo, {
30974
31521
  ...layoutOptions?.hideDescriptions !== void 0 && {
30975
31522
  hideDescriptions: layoutOptions.hideDescriptions
30976
31523
  },
30977
31524
  ...layoutOptions?.previousPositions !== void 0 && {
30978
31525
  previousPositions: layoutOptions.previousPositions
31526
+ },
31527
+ ...layoutOptions?.onProgress !== void 0 && {
31528
+ onProgress: layoutOptions.onProgress
30979
31529
  }
30980
31530
  });
30981
31531
  return attachNotes(
@@ -31759,7 +32309,12 @@ function renderMindmap(container, parsed, layout, palette, isDark, onClickItem,
31759
32309
  const titleReserve = fixedTitle ? TITLE_HEIGHT4 : 0;
31760
32310
  const availWidth = containerWidth;
31761
32311
  const availHeight = containerHeight - DIAGRAM_PADDING7 * 2 - legendReserve - titleReserve;
31762
- const ctx = isExport ? ScaleContext.identity() : ScaleContext.from(availWidth, layout.width);
32312
+ let ctx = isExport ? ScaleContext.identity() : ScaleContext.fromBox(
32313
+ availWidth,
32314
+ layout.width,
32315
+ availHeight,
32316
+ layout.height
32317
+ );
31763
32318
  let renderLayout = layout;
31764
32319
  if (ctx.factor < 1) {
31765
32320
  const hiddenCounts = /* @__PURE__ */ new Map();
@@ -31768,17 +32323,37 @@ function renderMindmap(container, parsed, layout, palette, isDark, onClickItem,
31768
32323
  hiddenCounts.set(n.id, n.hiddenCount);
31769
32324
  }
31770
32325
  }
31771
- renderLayout = layoutMindmap(parsed, palette, {
32326
+ const relayout = (c) => layoutMindmap(parsed, palette, {
31772
32327
  interactive: !isExport,
31773
32328
  ...hiddenCounts.size > 0 && { hiddenCounts },
31774
32329
  activeTagGroup: activeTagGroup ?? null,
31775
32330
  ...hideDescriptions !== void 0 && { hideDescriptions },
31776
- ctx
32331
+ ctx: c
31777
32332
  });
32333
+ renderLayout = relayout(ctx);
32334
+ for (let i = 0; i < 3 && !ctx.isBelowFloor; i++) {
32335
+ const refit = Math.min(
32336
+ availWidth / renderLayout.width,
32337
+ availHeight / renderLayout.height
32338
+ );
32339
+ if (refit >= 0.999) break;
32340
+ ctx = ScaleContext.fromFactor(ctx.factor * refit);
32341
+ renderLayout = relayout(ctx);
32342
+ }
31778
32343
  }
31779
- const offsetX = Math.max(0, (availWidth - renderLayout.width) / 2);
31780
- const offsetY = DIAGRAM_PADDING7 + legendReserve + titleReserve + Math.max(0, (availHeight - renderLayout.height) / 2);
31781
- const mainG = svg.append("g").attr("transform", `translate(${offsetX}, ${offsetY})`);
32344
+ const fitScale = isExport ? 1 : Math.min(
32345
+ 1,
32346
+ renderLayout.width > 0 ? availWidth / renderLayout.width : 1,
32347
+ renderLayout.height > 0 ? availHeight / renderLayout.height : 1
32348
+ );
32349
+ const scaledWidth = renderLayout.width * fitScale;
32350
+ const scaledHeight = renderLayout.height * fitScale;
32351
+ const offsetX = Math.max(0, (availWidth - scaledWidth) / 2);
32352
+ const offsetY = DIAGRAM_PADDING7 + legendReserve + titleReserve + Math.max(0, (availHeight - scaledHeight) / 2);
32353
+ const mainG = svg.append("g").attr(
32354
+ "transform",
32355
+ `translate(${offsetX}, ${offsetY})${fitScale < 1 ? ` scale(${fitScale})` : ""}`
32356
+ );
31782
32357
  if (ctx.isBelowFloor) {
31783
32358
  svg.attr("width", "100%");
31784
32359
  }
@@ -39142,10 +39717,10 @@ function renderLegend3(rootSvg, legendGroups, totalWidth, legendY, palette, isDa
39142
39717
  });
39143
39718
  legendG.selectAll("[data-legend-group]").classed("infra-legend-group", true);
39144
39719
  for (const group of legendGroups) {
39145
- const groupKey = group.name.toLowerCase();
39720
+ const groupKey2 = group.name.toLowerCase();
39146
39721
  for (const entry of group.entries) {
39147
39722
  const entryEl = legendG.select(
39148
- `[data-legend-group="${groupKey}"] [data-legend-entry="${entry.value.toLowerCase()}"]`
39723
+ `[data-legend-group="${groupKey2}"] [data-legend-entry="${entry.value.toLowerCase()}"]`
39149
39724
  );
39150
39725
  if (!entryEl.empty()) {
39151
39726
  entryEl.attr("data-legend-entry", entry.key.toLowerCase()).attr("data-legend-color", entry.color).attr("data-legend-type", group.type).attr(
@@ -41124,7 +41699,7 @@ __export(renderer_exports11, {
41124
41699
  renderPertForExport: () => renderPertForExport
41125
41700
  });
41126
41701
  function analysisBlockChrome(palette, isDark) {
41127
- const surfaceBg = isDark ? palette.surface : palette.bg;
41702
+ const surfaceBg = themeBaseBg(palette, isDark);
41128
41703
  return {
41129
41704
  fill: mix(palette.surface, palette.bg, 40),
41130
41705
  stroke: mix(palette.textMuted, surfaceBg, 35)
@@ -45836,7 +46411,7 @@ function renderState(container, graph, layout, palette, isDark, onClickItem, exp
45836
46411
  const gy = group.y - sGroupExtraPadding - sGroupLabelFontSize - 4;
45837
46412
  const gw = group.width + sGroupExtraPadding * 2;
45838
46413
  const gh = group.height + sGroupExtraPadding * 2 + sGroupLabelFontSize + 4;
45839
- const fillColor = group.color ? mix(group.color, isDark ? palette.surface : palette.bg, 10) : isDark ? palette.surface : mix(palette.border, palette.bg, 30);
46414
+ const fillColor = group.color ? mix(group.color, themeBaseBg(palette, isDark), 10) : isDark ? palette.surface : mix(palette.border, palette.bg, 30);
45840
46415
  const strokeColor = group.color ?? palette.textMuted;
45841
46416
  const groupWrapper = contentG.append("g").attr("class", "st-group-wrapper").attr("data-line-number", String(group.lineNumber)).attr("data-group-id", group.id).attr("data-group-toggle", group.id).attr("tabindex", "0").attr("role", "button").attr("aria-expanded", "true").attr("aria-label", `Collapse group ${group.label}`).style("cursor", "pointer");
45842
46417
  groupWrapper.append("rect").attr("x", gx).attr("y", gy).attr("width", gw).attr("height", gh).attr("rx", 6).attr("fill", fillColor).attr("stroke", strokeColor).attr("stroke-width", 1).attr("stroke-opacity", 0.5).attr("class", "st-group");
@@ -50029,6 +50604,16 @@ __export(resolver_exports, {
50029
50604
  isSubNationalUsExtent: () => isSubNationalUsExtent,
50030
50605
  resolveMap: () => resolveMap
50031
50606
  });
50607
+ function containerOvershoot(span, usOriented) {
50608
+ if (usOriented) return CONTAINER_OVERSHOOT_MAX;
50609
+ return Math.max(
50610
+ CONTAINER_OVERSHOOT_MIN,
50611
+ Math.min(
50612
+ CONTAINER_OVERSHOOT_MAX,
50613
+ CONTAINER_OVERSHOOT_MAX - CONTAINER_OVERSHOOT_DECAY * span
50614
+ )
50615
+ );
50616
+ }
50032
50617
  function bboxArea(b) {
50033
50618
  return (b[1][0] - b[0][0]) * (b[1][1] - b[0][1]);
50034
50619
  }
@@ -50525,7 +51110,7 @@ function resolveMap(parsed, data) {
50525
51110
  const containerUnion = unionExtent(containerBoxes, points);
50526
51111
  if (containerUnion)
50527
51112
  extent3 = pad(
50528
- clampContainerToCluster(containerUnion, points),
51113
+ clampContainerToCluster(containerUnion, points, usOriented),
50529
51114
  PAD_FRACTION
50530
51115
  );
50531
51116
  }
@@ -50609,17 +51194,21 @@ function mostCommonCountry(regions, poiCountries) {
50609
51194
  }
50610
51195
  return best;
50611
51196
  }
50612
- function clampContainerToCluster(container, points) {
51197
+ function clampContainerToCluster(container, points, usOriented) {
50613
51198
  const poi = unionExtent([], points);
50614
51199
  if (!poi) return container;
50615
51200
  let [[west, south], [east, north]] = container;
50616
51201
  const [[pWest, pSouth], [pEast, pNorth]] = poi;
50617
- south = Math.max(south, pSouth - CONTAINER_OVERSHOOT_DEG);
50618
- north = Math.min(north, pNorth + CONTAINER_OVERSHOOT_DEG);
50619
- if (east <= 180 && pEast <= 180) {
50620
- west = Math.max(west, pWest - CONTAINER_OVERSHOOT_DEG);
50621
- east = Math.min(east, pEast + CONTAINER_OVERSHOOT_DEG);
50622
- }
51202
+ const over = containerOvershoot(
51203
+ Math.max(pEast - pWest, pNorth - pSouth),
51204
+ usOriented
51205
+ );
51206
+ south = Math.max(south, pSouth - over);
51207
+ north = Math.min(north, pNorth + over);
51208
+ const wOver = pWest - over;
51209
+ const eOver = pEast + over;
51210
+ west = west >= -180 && west <= pWest ? Math.max(west, wOver) : wOver;
51211
+ east = east <= 180 && east >= pEast ? Math.min(east, eOver) : eOver;
50623
51212
  return [
50624
51213
  [west, south],
50625
51214
  [east, north]
@@ -50637,7 +51226,7 @@ function firstError(diags) {
50637
51226
  const e = diags.find((d) => d.severity === "error");
50638
51227
  return e ? formatDgmoError(e) : null;
50639
51228
  }
50640
- var WORLD_SPAN, MERCATOR_MAX_LAT, PAD_FRACTION, REGION_PAD_FRACTION, WORLD_LAT_SOUTH, WORLD_LAT_NORTH, POI_ZOOM_FLOOR_DEG, CONTAINER_OVERSHOOT_DEG, US_NATIONAL_LON_SPAN, CONUS_BBOX, US_SUBNATIONAL_AREA_FRACTION, REGION_ALIASES, US_STATE_POSTAL;
51229
+ var WORLD_SPAN, MERCATOR_MAX_LAT, PAD_FRACTION, REGION_PAD_FRACTION, WORLD_LAT_SOUTH, WORLD_LAT_NORTH, POI_ZOOM_FLOOR_DEG, CONTAINER_OVERSHOOT_MAX, CONTAINER_OVERSHOOT_MIN, CONTAINER_OVERSHOOT_DECAY, US_NATIONAL_LON_SPAN, CONUS_BBOX, US_SUBNATIONAL_AREA_FRACTION, REGION_ALIASES, US_STATE_POSTAL;
50641
51230
  var init_resolver2 = __esm({
50642
51231
  "src/map/resolver.ts"() {
50643
51232
  "use strict";
@@ -50650,7 +51239,9 @@ var init_resolver2 = __esm({
50650
51239
  WORLD_LAT_SOUTH = -58;
50651
51240
  WORLD_LAT_NORTH = 78;
50652
51241
  POI_ZOOM_FLOOR_DEG = 7;
50653
- CONTAINER_OVERSHOOT_DEG = 8;
51242
+ CONTAINER_OVERSHOOT_MAX = 8;
51243
+ CONTAINER_OVERSHOOT_MIN = 3;
51244
+ CONTAINER_OVERSHOOT_DECAY = 0.3;
50654
51245
  US_NATIONAL_LON_SPAN = 48;
50655
51246
  CONUS_BBOX = [
50656
51247
  [-125, 25],
@@ -50816,12 +51407,12 @@ function tierBand(maxSpanDeg) {
50816
51407
  }
50817
51408
  function labelBudget(width, height, band) {
50818
51409
  const bandCap = {
50819
- world: 7,
50820
- continental: 6,
50821
- regional: 5,
50822
- local: 4
51410
+ world: 10,
51411
+ continental: 9,
51412
+ regional: 7,
51413
+ local: 6
50823
51414
  };
50824
- const area2 = Math.floor(Math.sqrt(Math.max(0, width * height)) / 150);
51415
+ const area2 = Math.floor(Math.sqrt(Math.max(0, width * height)) / 105);
50825
51416
  return Math.max(0, Math.min(area2, bandCap[band]));
50826
51417
  }
50827
51418
  function waterEligible(tier, kind, band) {
@@ -50875,6 +51466,11 @@ function rectAround(cx, cy, lines, letterSpacing, font = FONT) {
50875
51466
  const h = (lines.length - 1) * lineHeight + font + 2 * PADY;
50876
51467
  return { x: cx - w / 2, y: cy - h / 2, w, h };
50877
51468
  }
51469
+ function rectDist2(px, py, x0, y0, x1, y1) {
51470
+ const dx = Math.max(x0 - px, 0, px - x1);
51471
+ const dy = Math.max(y0 - py, 0, py - y1);
51472
+ return dx * dx + dy * dy;
51473
+ }
50878
51474
  function rectFits(r, width, height) {
50879
51475
  return r.x >= 0 && r.y >= 0 && r.x + r.w <= width && r.y + r.h <= height;
50880
51476
  }
@@ -50893,6 +51489,7 @@ function placeContextLabels(args) {
50893
51489
  palette,
50894
51490
  project,
50895
51491
  collides,
51492
+ contentPoints,
50896
51493
  overLand
50897
51494
  } = args;
50898
51495
  void projection;
@@ -50963,8 +51560,17 @@ function placeContextLabels(args) {
50963
51560
  const [x0, y0, x1, y1] = c.bbox;
50964
51561
  const w = x1 - x0;
50965
51562
  const h = y1 - y0;
50966
- return { c, w, h, area: w * h };
50967
- }).filter((r) => Number.isFinite(r.area) && r.area > 0).sort((a, b) => b.area - a.area);
51563
+ let dist = Infinity;
51564
+ if (contentPoints?.length) {
51565
+ for (const p of contentPoints) {
51566
+ const d = rectDist2(p[0], p[1], x0, y0, x1, y1);
51567
+ if (d < dist) dist = d;
51568
+ }
51569
+ }
51570
+ return { c, w, h, area: w * h, dist };
51571
+ }).filter((r) => Number.isFinite(r.area) && r.area > 0).sort(
51572
+ (a, b) => contentPoints?.length ? a.dist - b.dist || b.area - a.area : b.area - a.area
51573
+ );
50968
51574
  const canvasLinear = Math.sqrt(Math.max(1, width * height));
50969
51575
  let ci = 0;
50970
51576
  for (const r of ranked) {
@@ -50981,7 +51587,7 @@ function placeContextLabels(args) {
50981
51587
  );
50982
51588
  const fontSize = Math.round(FONT + t * (COUNTRY_FONT_MAX - FONT));
50983
51589
  const fade = Math.round(t * COUNTRY_FADE_MAX);
50984
- const color = fade > 0 ? mix(countryColor, palette.bg, fade) : countryColor;
51590
+ const color = fade > 0 ? mix(countryColor, palette.bg, 100 - fade) : countryColor;
50985
51591
  const text = c.name;
50986
51592
  const tw = labelWidth(text, 0, fontSize);
50987
51593
  if (tw > w || fontSize + 2 * PADY > h) continue;
@@ -50994,6 +51600,9 @@ function placeContextLabels(args) {
50994
51600
  letterSpacing: 0,
50995
51601
  color,
50996
51602
  fontSize,
51603
+ // Multi-position dodging: carry the ordered interior positions through to the
51604
+ // commit loop. Invariant anchor === positions[0], so `cx/cy` is positions[0].
51605
+ ...c.positions ? { positions: c.positions } : {},
50997
51606
  // Band 1 (orientation-value ranking): above MINOR water (band 2, 2000+) but
50998
51607
  // below MAJOR water — oceans + major seas (band 0, ≤~16). So a big country
50999
51608
  // (US, Canada, Russia) outranks a minor sea/bay (Sargasso, Bahía de
@@ -51008,39 +51617,53 @@ function placeContextLabels(args) {
51008
51617
  const countryCount = candidates.reduce((n, c) => n + (c.italic ? 0 : 1), 0);
51009
51618
  const waterCap = budget - Math.min(2, countryCount);
51010
51619
  let waterPlaced = 0;
51011
- for (const cand of candidates) {
51012
- if (placed.length >= budget) break;
51013
- if (cand.italic && waterPlaced >= waterCap) continue;
51620
+ const gateAt = (cx, cy, cand) => {
51014
51621
  const rect = rectAround(
51015
- cand.cx,
51016
- cand.cy,
51622
+ cx,
51623
+ cy,
51017
51624
  cand.lines,
51018
51625
  cand.letterSpacing,
51019
51626
  cand.fontSize
51020
51627
  );
51021
- if (!rectFits(rect, width, height)) continue;
51628
+ if (!rectFits(rect, width, height)) return null;
51022
51629
  if (cand.italic && overLand) {
51023
51630
  const inset = 2;
51024
- const top = cand.cy - (cand.lines.length - 1) / 2 * LINE_HEIGHT;
51631
+ const top = cy - (cand.lines.length - 1) / 2 * LINE_HEIGHT;
51025
51632
  const touchesLand = cand.lines.some((line11, li) => {
51026
51633
  const lw = labelWidth(line11, cand.letterSpacing);
51027
- const x0 = cand.cx - lw / 2 + inset;
51028
- const x1 = cand.cx + lw / 2 - inset;
51029
- const xs = [x0, (x0 + cand.cx) / 2, cand.cx, (cand.cx + x1) / 2, x1];
51634
+ const x0 = cx - lw / 2 + inset;
51635
+ const x1 = cx + lw / 2 - inset;
51636
+ const xs = [x0, (x0 + cx) / 2, cx, (cx + x1) / 2, x1];
51030
51637
  const base = top + li * LINE_HEIGHT;
51031
51638
  return [base, base - FONT * 0.4, base - FONT * 0.8].some(
51032
51639
  (y) => xs.some((x) => overLand(x, y))
51033
51640
  );
51034
51641
  });
51035
- if (touchesLand) continue;
51642
+ if (touchesLand) return null;
51036
51643
  }
51037
- if (collides(rect)) continue;
51038
- if (placedRects.some((r) => overlapsPadded(rect, r, CONTEXT_PAD))) continue;
51039
- placedRects.push(rect);
51644
+ if (collides(rect)) return null;
51645
+ if (placedRects.some((r) => overlapsPadded(rect, r, CONTEXT_PAD)))
51646
+ return null;
51647
+ return rect;
51648
+ };
51649
+ for (const cand of candidates) {
51650
+ if (placed.length >= budget) break;
51651
+ if (cand.italic && waterPlaced >= waterCap) continue;
51652
+ const positions = cand.positions ?? [[cand.cx, cand.cy]];
51653
+ let chosen = null;
51654
+ for (const [px, py] of positions) {
51655
+ const rect = gateAt(px, py, cand);
51656
+ if (rect) {
51657
+ chosen = { x: px, y: py, rect };
51658
+ break;
51659
+ }
51660
+ }
51661
+ if (!chosen) continue;
51662
+ placedRects.push(chosen.rect);
51040
51663
  if (cand.italic) waterPlaced++;
51041
51664
  placed.push({
51042
- x: cand.cx,
51043
- y: cand.cy,
51665
+ x: chosen.x,
51666
+ y: chosen.y,
51044
51667
  text: cand.text,
51045
51668
  anchor: "middle",
51046
51669
  color: cand.color,
@@ -51058,7 +51681,7 @@ function placeContextLabels(args) {
51058
51681
  }
51059
51682
  return placed;
51060
51683
  }
51061
- var FONT, LINE_HEIGHT, PADX, PADY, WATER_LETTER_SPACING, CONTEXT_PAD, EDGE_CLAMP_MARGIN, EDGE_CLAMP_OVERSHOOT, COUNTRY_FONT_MAX, COUNTRY_SIZE_FRAC_MIN, COUNTRY_SIZE_FRAC_MAX, COUNTRY_FADE_MAX, KIND_ORDER;
51684
+ var FONT, LINE_HEIGHT, PADX, PADY, WATER_LETTER_SPACING, CONTEXT_PAD, EDGE_CLAMP_MARGIN, EDGE_CLAMP_OVERSHOOT, COUNTRY_FONT_MAX, COUNTRY_SIZE_FRAC_MIN, COUNTRY_SIZE_FRAC_MAX, COUNTRY_FADE_MAX, MAX_COUNTRY_POSITIONS, COUNTRY_POS_GRID, COUNTRY_POS_TOPN_MARGIN, KIND_ORDER;
51062
51685
  var init_context_labels = __esm({
51063
51686
  "src/map/context-labels.ts"() {
51064
51687
  "use strict";
@@ -51076,6 +51699,9 @@ var init_context_labels = __esm({
51076
51699
  COUNTRY_SIZE_FRAC_MIN = 0.06;
51077
51700
  COUNTRY_SIZE_FRAC_MAX = 0.32;
51078
51701
  COUNTRY_FADE_MAX = 45;
51702
+ MAX_COUNTRY_POSITIONS = 4;
51703
+ COUNTRY_POS_GRID = 5;
51704
+ COUNTRY_POS_TOPN_MARGIN = 3;
51079
51705
  KIND_ORDER = {
51080
51706
  ocean: 0,
51081
51707
  sea: 1,
@@ -51158,6 +51784,84 @@ function decodeLayer(topo) {
51158
51784
  decodeCache.set(topo, out);
51159
51785
  return out;
51160
51786
  }
51787
+ function countryLabelPositions(args) {
51788
+ const { geometry, bounds, project, width, height, curated } = args;
51789
+ const w0 = bounds[0][0];
51790
+ const s0 = bounds[0][1];
51791
+ const e0 = bounds[1][0];
51792
+ const n0 = bounds[1][1];
51793
+ if (![w0, s0, e0, n0].every(Number.isFinite) || e0 <= w0 || n0 <= s0) {
51794
+ return mkCurated(curated, project);
51795
+ }
51796
+ const N = COUNTRY_POS_GRID;
51797
+ const onLand = [];
51798
+ const kept = [];
51799
+ for (let i = 0; i < N; i++) {
51800
+ onLand[i] = [];
51801
+ const lon = w0 + (i + 0.5) / N * (e0 - w0);
51802
+ for (let j = 0; j < N; j++) {
51803
+ const lat = s0 + (j + 0.5) / N * (n0 - s0);
51804
+ const land = pointInGeometry(geometry, lon, lat);
51805
+ onLand[i][j] = land;
51806
+ if (!land) continue;
51807
+ const p = project(lon, lat);
51808
+ if (!p || !Number.isFinite(p[0]) || !Number.isFinite(p[1])) continue;
51809
+ if (p[0] < 0 || p[0] > width || p[1] < 0 || p[1] > height) continue;
51810
+ kept.push({ i, j, lon, lat, sx: p[0], sy: p[1] });
51811
+ }
51812
+ }
51813
+ if (!kept.length) return mkCurated(curated, project);
51814
+ const cx = kept.reduce((s, c) => s + c.sx, 0) / kept.length;
51815
+ const cy = kept.reduce((s, c) => s + c.sy, 0) / kept.length;
51816
+ const interiorness = (c) => {
51817
+ let n = 0;
51818
+ for (let di = -1; di <= 1; di++)
51819
+ for (let dj = -1; dj <= 1; dj++) {
51820
+ if (di === 0 && dj === 0) continue;
51821
+ const ni = c.i + di;
51822
+ const nj = c.j + dj;
51823
+ if (ni >= 0 && ni < N && nj >= 0 && nj < N && onLand[ni][nj]) n++;
51824
+ }
51825
+ return n;
51826
+ };
51827
+ const dist2ToCentre = (c) => (c.sx - cx) ** 2 + (c.sy - cy) ** 2;
51828
+ const pool = [...kept];
51829
+ pool.sort((a, b) => {
51830
+ const d = interiorness(b) - interiorness(a);
51831
+ return d !== 0 ? d : dist2ToCentre(a) - dist2ToCentre(b);
51832
+ });
51833
+ const ordered = [pool.shift()];
51834
+ while (ordered.length < MAX_COUNTRY_POSITIONS && pool.length) {
51835
+ let bestIdx = 0;
51836
+ let bestMin = -1;
51837
+ for (let k = 0; k < pool.length; k++) {
51838
+ const c = pool[k];
51839
+ let minD = Infinity;
51840
+ for (const o of ordered) {
51841
+ const d = (c.sx - o.sx) ** 2 + (c.sy - o.sy) ** 2;
51842
+ if (d < minD) minD = d;
51843
+ }
51844
+ if (minD > bestMin) {
51845
+ bestMin = minD;
51846
+ bestIdx = k;
51847
+ }
51848
+ }
51849
+ ordered.push(pool.splice(bestIdx, 1)[0]);
51850
+ }
51851
+ const grid = ordered.map((c) => ({
51852
+ lonLat: [c.lon, c.lat],
51853
+ screen: [c.sx, c.sy]
51854
+ }));
51855
+ const curatedPos = curated ? mkCurated(curated, project) : [];
51856
+ const out = [...curatedPos, ...grid].slice(0, MAX_COUNTRY_POSITIONS);
51857
+ return out;
51858
+ }
51859
+ function mkCurated(curated, project) {
51860
+ if (!curated) return [];
51861
+ const p = project(curated[0], curated[1]);
51862
+ if (!p || !Number.isFinite(p[0]) || !Number.isFinite(p[1])) return [];
51863
+ return [{ lonLat: [curated[0], curated[1]], screen: [p[0], p[1]] }];
51864
+ }
51161
51865
  function projectionFor(family, extent3) {
51162
51866
  switch (family) {
51163
51867
  case "albers-usa":
@@ -51985,6 +52689,8 @@ function layoutMap(resolvedIn, data, size, opts) {
51985
52689
  if (p[1] < minY) minY = p[1];
51986
52690
  if (p[1] > maxY) maxY = p[1];
51987
52691
  }
52692
+ r.bbox = [minX, minY, maxX, maxY];
52693
+ r.rings = rings;
51988
52694
  return { fill: r.fill, rings, minX, minY, maxX, maxY };
51989
52695
  });
51990
52696
  const fillAt = (x, y) => {
@@ -53175,6 +53881,7 @@ function layoutMap(resolvedIn, data, size, opts) {
53175
53881
  for (const box of insets)
53176
53882
  obstacles.push({ x: box.x, y: box.y, w: box.w, h: box.h });
53177
53883
  const countryCandidates = [];
53884
+ const rawCountries = [];
53178
53885
  for (const f of worldLayer.values()) {
53179
53886
  const iso = typeof f.id === "string" ? f.id : String(f.id ?? "");
53180
53887
  if (!iso || regionById.has(iso)) continue;
@@ -53191,11 +53898,59 @@ function layoutMap(resolvedIn, data, size, opts) {
53191
53898
  if (!Number.isFinite(x0) || !Number.isFinite(x1)) continue;
53192
53899
  const anchorLngLat = WORLD_LABEL_ANCHORS[iso];
53193
53900
  const a = anchorLngLat ? project(anchorLngLat[0], anchorLngLat[1]) : path.centroid(f);
53194
- countryCandidates.push({
53901
+ rawCountries.push({
53902
+ f,
53903
+ iso,
53195
53904
  name: f.properties?.name ?? iso,
53196
53905
  bbox: [x0, y0, x1, y1],
53197
53906
  anchor: a && Number.isFinite(a[0]) ? [a[0], a[1]] : null,
53198
- curatedAnchor: !!anchorLngLat
53907
+ curatedLngLat: anchorLngLat ?? null,
53908
+ area: (x1 - x0) * (y1 - y0)
53909
+ });
53910
+ }
53911
+ const cBand = tierBand(Math.max(dLonSpan, dLatSpan));
53912
+ const cBudget = labelBudget(width, height, cBand);
53913
+ const contentPoints = markers.map((m) => [m.cx, m.cy]);
53914
+ const topN = cBudget + COUNTRY_POS_TOPN_MARGIN;
53915
+ const rankOrder = rawCountries.map((r, idx) => {
53916
+ let dist = Infinity;
53917
+ const [x0, y0, x1, y1] = r.bbox;
53918
+ for (const [px, py] of contentPoints) {
53919
+ const dx = Math.max(x0 - px, 0, px - x1);
53920
+ const dy = Math.max(y0 - py, 0, py - y1);
53921
+ const d = dx * dx + dy * dy;
53922
+ if (d < dist) dist = d;
53923
+ }
53924
+ return { idx, area: r.area, dist };
53925
+ }).filter((r) => Number.isFinite(r.area) && r.area > 0).sort(
53926
+ (a, b) => contentPoints.length ? a.dist - b.dist || b.area - a.area : b.area - a.area
53927
+ ).slice(0, topN);
53928
+ const genIdx = new Set(rankOrder.map((r) => r.idx));
53929
+ for (let i = 0; i < rawCountries.length; i++) {
53930
+ const r = rawCountries[i];
53931
+ let anchor = r.anchor;
53932
+ let positions;
53933
+ if (genIdx.has(i) && anchor) {
53934
+ const gb = (0, import_d3_geo2.geoBounds)(r.f);
53935
+ const gen = countryLabelPositions({
53936
+ geometry: r.f.geometry,
53937
+ bounds: gb,
53938
+ project,
53939
+ width,
53940
+ height,
53941
+ curated: r.curatedLngLat
53942
+ });
53943
+ if (gen.length) {
53944
+ positions = gen.map((p) => p.screen);
53945
+ anchor = positions[0];
53946
+ }
53947
+ }
53948
+ countryCandidates.push({
53949
+ name: r.name,
53950
+ bbox: r.bbox,
53951
+ anchor,
53952
+ curatedAnchor: !!r.curatedLngLat,
53953
+ ...positions ? { positions } : {}
53199
53954
  });
53200
53955
  }
53201
53956
  const framedStateContainers = (resolved.poiFrameContainers ?? []).some(
@@ -53229,6 +53984,7 @@ function layoutMap(resolvedIn, data, size, opts) {
53229
53984
  palette,
53230
53985
  project,
53231
53986
  collides,
53987
+ contentPoints,
53232
53988
  // Water labels must stay over open water — `fillAt` returns the ocean
53233
53989
  // backdrop colour off-land and a region fill on-land (lakes/states count
53234
53990
  // as land here, which is the safe side for an ocean name).
@@ -53482,7 +54238,7 @@ function ringToCoastPaths(ring, frame) {
53482
54238
  function coastlineOuterRings(regions, minExtent, frame) {
53483
54239
  const paths = [];
53484
54240
  for (const r of regions) {
53485
- const rings = parsePathRings(r.d);
54241
+ const rings = r.rings ?? parsePathRings(r.d);
53486
54242
  for (let i = 0; i < rings.length; i++) {
53487
54243
  const ring = rings[i];
53488
54244
  if (ring.length < 3) continue;
@@ -53677,14 +54433,22 @@ function renderMap(container, resolved, data, palette, isDark, onClickItem, expo
53677
54433
  if (decoCluster !== void 0)
53678
54434
  gPatch.attr("data-cluster-deco", decoCluster);
53679
54435
  for (const r of layout.regions) {
53680
- let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;
53681
- for (const ring of parsePathRings(r.d))
53682
- for (const [px, py] of ring) {
53683
- if (px < minX) minX = px;
53684
- if (px > maxX) maxX = px;
53685
- if (py < minY) minY = py;
53686
- if (py > maxY) maxY = py;
53687
- }
54436
+ let minX, minY, maxX, maxY;
54437
+ if (r.bbox) {
54438
+ [minX, minY, maxX, maxY] = r.bbox;
54439
+ } else {
54440
+ minX = Infinity;
54441
+ minY = Infinity;
54442
+ maxX = -Infinity;
54443
+ maxY = -Infinity;
54444
+ for (const ring of parsePathRings(r.d))
54445
+ for (const [px, py] of ring) {
54446
+ if (px < minX) minX = px;
54447
+ if (px > maxX) maxX = px;
54448
+ if (py < minY) minY = py;
54449
+ if (py > maxY) maxY = py;
54450
+ }
54451
+ }
53688
54452
  const hit = blobRects.some(
53689
54453
  (b) => minX <= b.x1 && maxX >= b.x0 && minY <= b.y1 && maxY >= b.y0
53690
54454
  );
@@ -54912,7 +55676,7 @@ function renderRaci(container, parsed, palette, isDark, handlers, exportDims) {
54912
55676
  const tasksAll = [...allTasks(parsed)];
54913
55677
  if (tasksAll.length === 0 && parsed.phases.length === 0) return;
54914
55678
  const solid = parsed.options["solid-fill"] === "on";
54915
- const surfaceBg = isDark ? palette.surface : palette.bg;
55679
+ const surfaceBg = themeBaseBg(palette, isDark);
54916
55680
  const roleCount = Math.max(1, parsed.roles.length);
54917
55681
  const idealWidth = roleCount * ROLE_COL_MAX + TASK_LABEL_MAX + 2 * H_MARGIN;
54918
55682
  const ctx = exportDims ? ScaleContext.identity() : ScaleContext.from(width, idealWidth);
@@ -55090,10 +55854,10 @@ function renderRaci(container, parsed, palette, isDark, handlers, exportDims) {
55090
55854
  const cx = roleX(i) + sColumnInset;
55091
55855
  const cw = roleColW - 2 * sColumnInset;
55092
55856
  const roleColor = parsed.roleColors[i] ?? autoAccent(i, palette);
55093
- const bodyFill = mix(roleColor, isDark ? palette.surface : palette.bg, 16);
55857
+ const bodyFill = mix(roleColor, themeBaseBg(palette, isDark), 16);
55094
55858
  const headerFill = mix(
55095
55859
  roleColor,
55096
- isDark ? palette.surface : palette.bg,
55860
+ themeBaseBg(palette, isDark),
55097
55861
  30
55098
55862
  );
55099
55863
  const colG = columnsG.append("g").attr("class", "raci-column").attr("data-role-id", roleId);
@@ -55682,15 +56446,15 @@ function propagateGroupTags(participantMeta, groups) {
55682
56446
  }
55683
56447
  }
55684
56448
  }
55685
- function computeReceiverInheritance(participants, messages, groupKey, participantMeta) {
56449
+ function computeReceiverInheritance(participants, messages, groupKey2, participantMeta) {
55686
56450
  const inheritance = /* @__PURE__ */ new Map();
55687
56451
  for (const p of participants) {
55688
56452
  const meta = participantMeta.get(p.id);
55689
- if (meta?.[groupKey]) continue;
56453
+ if (meta?.[groupKey2]) continue;
55690
56454
  const incomingValues = /* @__PURE__ */ new Set();
55691
56455
  for (const msg of messages) {
55692
- if (msg.to === p.id && msg.metadata?.[groupKey]) {
55693
- incomingValues.add(msg.metadata[groupKey]);
56456
+ if (msg.to === p.id && msg.metadata?.[groupKey2]) {
56457
+ incomingValues.add(msg.metadata[groupKey2]);
55694
56458
  }
55695
56459
  }
55696
56460
  if (incomingValues.size === 1) {
@@ -55716,7 +56480,7 @@ function resolveSequenceTags(parsed, activeTagGroup) {
55716
56480
  }
55717
56481
  return result;
55718
56482
  }
55719
- const groupKey = group.name.toLowerCase();
56483
+ const groupKey2 = group.name.toLowerCase();
55720
56484
  const participantMeta = /* @__PURE__ */ new Map();
55721
56485
  for (const p of parsed.participants) {
55722
56486
  participantMeta.set(p.id, { ...p.metadata || {} });
@@ -55725,27 +56489,27 @@ function resolveSequenceTags(parsed, activeTagGroup) {
55725
56489
  const inherited = computeReceiverInheritance(
55726
56490
  parsed.participants,
55727
56491
  parsed.messages,
55728
- groupKey,
56492
+ groupKey2,
55729
56493
  participantMeta
55730
56494
  );
55731
56495
  for (const [id, value] of inherited) {
55732
56496
  const meta = participantMeta.get(id);
55733
- meta[groupKey] = value;
56497
+ meta[groupKey2] = value;
55734
56498
  }
55735
56499
  if (group.defaultValue) {
55736
56500
  for (const p of parsed.participants) {
55737
56501
  const meta = participantMeta.get(p.id);
55738
- if (!(groupKey in meta)) {
55739
- meta[groupKey] = group.defaultValue;
56502
+ if (!(groupKey2 in meta)) {
56503
+ meta[groupKey2] = group.defaultValue;
55740
56504
  }
55741
56505
  }
55742
56506
  }
55743
56507
  for (const p of parsed.participants) {
55744
56508
  const meta = participantMeta.get(p.id);
55745
- result.participants.set(p.id, meta[groupKey] || void 0);
56509
+ result.participants.set(p.id, meta[groupKey2] || void 0);
55746
56510
  }
55747
56511
  for (const msg of parsed.messages) {
55748
- result.messages.set(msg.lineNumber, msg.metadata?.[groupKey] || void 0);
56512
+ result.messages.set(msg.lineNumber, msg.metadata?.[groupKey2] || void 0);
55749
56513
  }
55750
56514
  return result;
55751
56515
  }
@@ -56820,7 +57584,7 @@ function renderSequenceDiagram(container, parsed, palette, isDark, _onNavigateTo
56820
57584
  const groupTagColor = getTagColor(groupTagValue || void 0);
56821
57585
  const fillColor = groupTagColor ? mix(
56822
57586
  groupTagColor,
56823
- isDark ? palette.surface : palette.bg,
57587
+ themeBaseBg(palette, isDark),
56824
57588
  isDark ? 15 : 20
56825
57589
  ) : isDark ? palette.surface : palette.bg;
56826
57590
  const strokeColor = groupTagColor || palette.textMuted;
@@ -56874,7 +57638,7 @@ function renderSequenceDiagram(container, parsed, palette, isDark, _onNavigateTo
56874
57638
  participantG.append("title").text("Click to expand");
56875
57639
  const pFill = effectiveTagColor ? mix(
56876
57640
  effectiveTagColor,
56877
- isDark ? palette.surface : palette.bg,
57641
+ themeBaseBg(palette, isDark),
56878
57642
  isDark ? 30 : 40
56879
57643
  ) : isDark ? mix(palette.overlay, palette.surface, 50) : mix(palette.bg, palette.surface, 50);
56880
57644
  const pStroke = effectiveTagColor || palette.border;
@@ -57081,7 +57845,7 @@ function renderSequenceDiagram(container, parsed, palette, isDark, _onNavigateTo
57081
57845
  const actTagValue = triggerMsg ? tagMap?.messages.get(triggerMsg.lineNumber) : void 0;
57082
57846
  const actTagColor = getTagColor(actTagValue);
57083
57847
  const actBaseColor = actTagColor || palette.primary;
57084
- svg.append("rect").attr("x", x).attr("y", y1).attr("width", sActivationWidth).attr("height", y2 - y1).attr("fill", isDark ? palette.surface : palette.bg);
57848
+ svg.append("rect").attr("x", x).attr("y", y1).attr("width", sActivationWidth).attr("height", y2 - y1).attr("fill", themeBaseBg(palette, isDark));
57085
57849
  const actFill = shapeFill(palette, actBaseColor, isDark, { solid });
57086
57850
  const actRect = svg.append("rect").attr("x", x).attr("y", y1).attr("width", sActivationWidth).attr("height", y2 - y1).attr("fill", actFill).attr("stroke", actBaseColor).attr("stroke-width", 1).attr("stroke-opacity", 0.5).attr("data-participant-id", act.participantId).attr("data-msg-lines", coveredLines.join(",")).attr("data-line-number", coveredLines[0] ?? "").attr("class", "activation");
57087
57851
  if (tagKey && actTagValue) {
@@ -57883,6 +58647,8 @@ __export(advanced_exports, {
57883
58647
  CHART_TYPE_DESCRIPTIONS: () => CHART_TYPE_DESCRIPTIONS,
57884
58648
  ECHART_EXPORT_WIDTH: () => ECHART_EXPORT_WIDTH,
57885
58649
  INFRA_BEHAVIOR_KEYS: () => INFRA_BEHAVIOR_KEYS,
58650
+ INVALID_COLOR_CODE: () => INVALID_COLOR_CODE,
58651
+ INVALID_CSS_COLOR_HEX: () => INVALID_CSS_COLOR_HEX,
57886
58652
  LEGEND_GEAR_PILL_W: () => LEGEND_GEAR_PILL_W,
57887
58653
  LEGEND_HEIGHT: () => LEGEND_HEIGHT,
57888
58654
  RACI_ERROR_CODES: () => RACI_ERROR_CODES,
@@ -57944,6 +58710,7 @@ __export(advanced_exports, {
57944
58710
  extractInfraSymbols: () => extractSymbols4,
57945
58711
  extractPertSymbols: () => extractPertSymbols,
57946
58712
  findUnsafePipePositions: () => findUnsafePipePositions,
58713
+ focusBoxesAndLines: () => focusBoxesAndLines,
57947
58714
  focusOrgTree: () => focusOrgTree,
57948
58715
  formatDateLabel: () => formatDateLabel,
57949
58716
  formatDgmoError: () => formatDgmoError,
@@ -57964,8 +58731,10 @@ __export(advanced_exports, {
57964
58731
  hslToHex: () => hslToHex,
57965
58732
  inferParticipantType: () => inferParticipantType,
57966
58733
  inferRoles: () => inferRoles,
58734
+ invalidColorDiagnostic: () => invalidColorDiagnostic,
57967
58735
  isArchiveColumn: () => isArchiveColumn,
57968
58736
  isExtendedChartType: () => isExtendedChartType,
58737
+ isInvalidColorToken: () => isInvalidColorToken,
57969
58738
  isLegacyMetadataLine: () => isLegacyMetadataLine,
57970
58739
  isRecognizedColorName: () => isRecognizedColorName,
57971
58740
  isSequenceBlock: () => isSequenceBlock,
@@ -58006,6 +58775,7 @@ __export(advanced_exports, {
58006
58775
  migrateContent: () => migrateContent,
58007
58776
  mix: () => mix,
58008
58777
  mulberry32: () => mulberry32,
58778
+ nearestNamedColor: () => nearestNamedColor,
58009
58779
  nord: () => nord,
58010
58780
  nordPalette: () => nordPalette,
58011
58781
  normalizeName: () => normalizeName,
@@ -59048,7 +59818,7 @@ function setupTimeline(container, parsed, palette, isDark, exportDims, activeTag
59048
59818
  const textColor = palette.text;
59049
59819
  const mutedColor = palette.border;
59050
59820
  const bgColor = palette.bg;
59051
- const bg = isDark ? palette.surface : palette.bg;
59821
+ const bg = themeBaseBg(palette, isDark);
59052
59822
  const colors = getSeriesColors(palette);
59053
59823
  const groupColorMap = /* @__PURE__ */ new Map();
59054
59824
  timelineGroups.forEach((grp, i) => {
@@ -59381,10 +60151,10 @@ function renderTimelineTagLegendOverlay(container, parsed, palette, isDark, setu
59381
60151
  }
59382
60152
  },
59383
60153
  onGroupRendered: (groupName, groupEl, isActive) => {
59384
- const groupKey = groupName.toLowerCase();
59385
- groupEl.attr("data-tag-group", groupKey);
60154
+ const groupKey2 = groupName.toLowerCase();
60155
+ groupEl.attr("data-tag-group", groupKey2);
59386
60156
  if (isActive && !viewMode) {
59387
- const isSwimActive = currentSwimlaneGroup?.toLowerCase() === groupKey;
60157
+ const isSwimActive = currentSwimlaneGroup?.toLowerCase() === groupKey2;
59388
60158
  const pillWidth2 = measureLegendText(groupName, LG_PILL_FONT_SIZE) + LG_PILL_PAD;
59389
60159
  const pillXOff = LG_CAPSULE_PAD;
59390
60160
  const iconX = pillXOff + pillWidth2 + 5;
@@ -59395,9 +60165,9 @@ function renderTimelineTagLegendOverlay(container, parsed, palette, isDark, setu
59395
60165
  iconY,
59396
60166
  isSwimActive
59397
60167
  );
59398
- iconEl.attr("data-swimlane-toggle", groupKey).on("click", (event) => {
60168
+ iconEl.attr("data-swimlane-toggle", groupKey2).on("click", (event) => {
59399
60169
  event.stopPropagation();
59400
- currentSwimlaneGroup = currentSwimlaneGroup === groupKey ? null : groupKey;
60170
+ currentSwimlaneGroup = currentSwimlaneGroup === groupKey2 ? null : groupKey2;
59401
60171
  onTagStateChange?.(
59402
60172
  currentActiveGroup,
59403
60173
  currentSwimlaneGroup
@@ -59463,9 +60233,10 @@ function renderTimelineTagLegendOverlay(container, parsed, palette, isDark, setu
59463
60233
  drawLegend2();
59464
60234
  }
59465
60235
  }
59466
- function renderTimelineHorizontalTimeSort(container, parsed, palette, isDark, setup, hovers, onClickItem, _exportDims, _swimlaneTagGroup, _activeTagGroup, _onTagStateChange, _viewMode) {
60236
+ function renderTimelineHorizontalTimeSort(container, parsed, palette, isDark, setup, hovers, onClickItem, exportDims, _swimlaneTagGroup, _activeTagGroup, _onTagStateChange, _viewMode) {
59467
60237
  const {
59468
60238
  width,
60239
+ height,
59469
60240
  tooltip,
59470
60241
  solid,
59471
60242
  textColor,
@@ -59517,9 +60288,11 @@ function renderTimelineHorizontalTimeSort(container, parsed, palette, isDark, se
59517
60288
  const rowH = ctx.structural(28);
59518
60289
  const innerHeight = rowH * sorted.length;
59519
60290
  const usedHeight = margin.top + innerHeight + margin.bottom;
60291
+ const fitToContainer = !exportDims && height > 0 && usedHeight > height;
60292
+ const svgHeight = fitToContainer ? height : usedHeight;
59520
60293
  const xScale = d3Scale3.scaleLinear().domain([minDate - datePadding, maxDate + datePadding]).range([0, innerWidth]);
59521
- const svg = d3Selection3.select(container).append("svg").attr("width", width).attr("height", usedHeight).attr("viewBox", `0 0 ${width} ${usedHeight}`).attr("preserveAspectRatio", "xMidYMin meet").style("background", bgColor);
59522
- if (ctx.isBelowFloor) {
60294
+ const svg = d3Selection3.select(container).append("svg").attr("width", width).attr("height", svgHeight).attr("viewBox", `0 0 ${width} ${usedHeight}`).attr("preserveAspectRatio", "xMidYMin meet").style("background", bgColor);
60295
+ if (ctx.isBelowFloor && !fitToContainer) {
59523
60296
  svg.attr("width", "100%");
59524
60297
  }
59525
60298
  const g = svg.append("g").attr("transform", `translate(${margin.left},${margin.top})`);
@@ -61253,7 +62026,7 @@ function renderQuadrant(container, parsed, palette, isDark, onClickItem, exportD
61253
62026
  onClickItem
61254
62027
  );
61255
62028
  const chartG = svg.append("g").attr("transform", `translate(${margin.left}, ${margin.top})`);
61256
- const bg = isDark ? palette.surface : palette.bg;
62029
+ const bg = themeBaseBg(palette, isDark);
61257
62030
  const getQuadrantColor = (label, defaultIdx) => {
61258
62031
  return label?.color ?? defaultColors[defaultIdx % defaultColors.length];
61259
62032
  };
@@ -61592,18 +62365,22 @@ async function renderForExport(content, theme, palette, viewState, options) {
61592
62365
  palette,
61593
62366
  viewState,
61594
62367
  options,
61595
- exportMode
62368
+ exportMode,
62369
+ isDark: theme === "dark"
61596
62370
  };
61597
62371
  const handler = detectedType !== null ? DIAGRAM_EXPORT_HANDLERS[detectedType] : void 0;
61598
62372
  return (handler ?? exportVisualization)(ctx);
61599
62373
  }
62374
+ function ctxTagOverride(ctx) {
62375
+ return ctx.viewState?.tag ?? ctx.options?.tagGroup;
62376
+ }
61600
62377
  async function exportOrg(ctx) {
61601
- const { content, theme, palette, viewState, options, exportMode } = ctx;
62378
+ const { content, theme, palette, viewState, exportMode } = ctx;
61602
62379
  const { parseOrg: parseOrg2 } = await Promise.resolve().then(() => (init_parser10(), parser_exports4));
61603
62380
  const { layoutOrg: layoutOrg2 } = await Promise.resolve().then(() => (init_layout(), layout_exports));
61604
62381
  const { collapseOrgTree: collapseOrgTree2 } = await Promise.resolve().then(() => (init_collapse(), collapse_exports));
61605
62382
  const { renderOrg: renderOrg2 } = await Promise.resolve().then(() => (init_renderer(), renderer_exports));
61606
- const isDark = theme === "dark";
62383
+ const isDark = ctx.isDark;
61607
62384
  const effectivePalette = await resolveExportPalette(theme, palette);
61608
62385
  const orgParsed = parseOrg2(content, effectivePalette);
61609
62386
  if (orgParsed.error) return "";
@@ -61611,7 +62388,7 @@ async function exportOrg(ctx) {
61611
62388
  const activeTagGroup = resolveActiveTagGroup(
61612
62389
  orgParsed.tagGroups,
61613
62390
  orgParsed.options["active-tag"],
61614
- viewState?.tag ?? options?.tagGroup
62391
+ ctxTagOverride(ctx)
61615
62392
  );
61616
62393
  const hiddenAttributes = viewState?.ha ? new Set(viewState.ha) : void 0;
61617
62394
  const { parsed: effectiveParsed, hiddenCounts } = collapsedNodes && collapsedNodes.size > 0 ? collapseOrgTree2(orgParsed, collapsedNodes) : { parsed: orgParsed, hiddenCounts: /* @__PURE__ */ new Map() };
@@ -61644,12 +62421,12 @@ async function exportOrg(ctx) {
61644
62421
  return finalizeSvgExport(container, theme, effectivePalette);
61645
62422
  }
61646
62423
  async function exportSitemap(ctx) {
61647
- const { content, theme, palette, viewState, options, exportMode } = ctx;
62424
+ const { content, theme, palette, viewState, exportMode } = ctx;
61648
62425
  const { parseSitemap: parseSitemap2 } = await Promise.resolve().then(() => (init_parser11(), parser_exports5));
61649
62426
  const { layoutSitemap: layoutSitemap2 } = await Promise.resolve().then(() => (init_layout2(), layout_exports2));
61650
62427
  const { collapseSitemapTree: collapseSitemapTree2 } = await Promise.resolve().then(() => (init_collapse2(), collapse_exports2));
61651
62428
  const { renderSitemap: renderSitemap2 } = await Promise.resolve().then(() => (init_renderer2(), renderer_exports2));
61652
- const isDark = theme === "dark";
62429
+ const isDark = ctx.isDark;
61653
62430
  const effectivePalette = await resolveExportPalette(theme, palette);
61654
62431
  const sitemapParsed = parseSitemap2(content, effectivePalette);
61655
62432
  if (sitemapParsed.error || sitemapParsed.roots.length === 0) return "";
@@ -61657,7 +62434,7 @@ async function exportSitemap(ctx) {
61657
62434
  const activeTagGroup = resolveActiveTagGroup(
61658
62435
  sitemapParsed.tagGroups,
61659
62436
  sitemapParsed.options["active-tag"],
61660
- viewState?.tag ?? options?.tagGroup
62437
+ ctxTagOverride(ctx)
61661
62438
  );
61662
62439
  const hiddenAttributes = viewState?.ha ? new Set(viewState.ha) : void 0;
61663
62440
  const { parsed: effectiveParsed, hiddenCounts } = collapsedNodes && collapsedNodes.size > 0 ? collapseSitemapTree2(sitemapParsed, collapsedNodes) : { parsed: sitemapParsed, hiddenCounts: /* @__PURE__ */ new Map() };
@@ -61688,7 +62465,7 @@ async function exportSitemap(ctx) {
61688
62465
  return finalizeSvgExport(container, theme, effectivePalette);
61689
62466
  }
61690
62467
  async function exportKanban(ctx) {
61691
- const { content, theme, palette, viewState, options, exportMode } = ctx;
62468
+ const { content, theme, palette, viewState, exportMode } = ctx;
61692
62469
  const { parseKanban: parseKanban2 } = await Promise.resolve().then(() => (init_parser13(), parser_exports7));
61693
62470
  const { renderKanban: renderKanban2 } = await Promise.resolve().then(() => (init_renderer3(), renderer_exports3));
61694
62471
  const effectivePalette = await resolveExportPalette(theme, palette);
@@ -61700,11 +62477,11 @@ async function exportKanban(ctx) {
61700
62477
  document.body.appendChild(container);
61701
62478
  const kanbanCollapsedLanes = viewState?.cl ? new Set(viewState.cl) : void 0;
61702
62479
  const kanbanCollapsedColumns = viewState?.cc ? new Set(viewState.cc) : void 0;
61703
- renderKanban2(container, kanbanParsed, effectivePalette, theme === "dark", {
62480
+ renderKanban2(container, kanbanParsed, effectivePalette, ctx.isDark, {
61704
62481
  activeTagGroup: resolveActiveTagGroup(
61705
62482
  kanbanParsed.tagGroups,
61706
62483
  kanbanParsed.options["active-tag"],
61707
- viewState?.tag ?? options?.tagGroup
62484
+ ctxTagOverride(ctx)
61708
62485
  ),
61709
62486
  currentSwimlaneGroup: viewState?.swim ?? null,
61710
62487
  ...kanbanCollapsedLanes !== void 0 && {
@@ -61737,7 +62514,7 @@ async function exportClass(ctx) {
61737
62514
  classParsed,
61738
62515
  classLayout,
61739
62516
  effectivePalette,
61740
- theme === "dark",
62517
+ ctx.isDark,
61741
62518
  void 0,
61742
62519
  { width: exportWidth, height: exportHeight },
61743
62520
  void 0,
@@ -61746,7 +62523,7 @@ async function exportClass(ctx) {
61746
62523
  return finalizeSvgExport(container, theme, effectivePalette);
61747
62524
  }
61748
62525
  async function exportEr(ctx) {
61749
- const { content, theme, palette, viewState, options, exportMode } = ctx;
62526
+ const { content, theme, palette, viewState, exportMode } = ctx;
61750
62527
  const { parseERDiagram: parseERDiagram2 } = await Promise.resolve().then(() => (init_parser9(), parser_exports3));
61751
62528
  const { layoutERDiagram: layoutERDiagram2 } = await Promise.resolve().then(() => (init_layout4(), layout_exports4));
61752
62529
  const { renderERDiagram: renderERDiagram2 } = await Promise.resolve().then(() => (init_renderer5(), renderer_exports5));
@@ -61764,13 +62541,13 @@ async function exportEr(ctx) {
61764
62541
  erParsed,
61765
62542
  erLayout,
61766
62543
  effectivePalette,
61767
- theme === "dark",
62544
+ ctx.isDark,
61768
62545
  void 0,
61769
62546
  { width: exportWidth, height: exportHeight },
61770
62547
  resolveActiveTagGroup(
61771
62548
  erParsed.tagGroups,
61772
62549
  erParsed.options["active-tag"],
61773
- viewState?.tag ?? options?.tagGroup
62550
+ ctxTagOverride(ctx)
61774
62551
  ),
61775
62552
  viewState?.sem,
61776
62553
  exportMode
@@ -61778,7 +62555,7 @@ async function exportEr(ctx) {
61778
62555
  return finalizeSvgExport(container, theme, effectivePalette);
61779
62556
  }
61780
62557
  async function exportBoxesAndLines(ctx) {
61781
- const { content, theme, palette, viewState, options, exportMode } = ctx;
62558
+ const { content, theme, palette, viewState, exportMode } = ctx;
61782
62559
  const { parseBoxesAndLines: parseBoxesAndLines2 } = await Promise.resolve().then(() => (init_parser18(), parser_exports12));
61783
62560
  const effectivePalette = await resolveExportPalette(theme, palette);
61784
62561
  const blParsed = parseBoxesAndLines2(content, effectivePalette);
@@ -61798,13 +62575,13 @@ async function exportBoxesAndLines(ctx) {
61798
62575
  const exportWidth = blLayout.width + PADDING3 * 2;
61799
62576
  const exportHeight = blLayout.height + PADDING3 * 2 + titleOffset;
61800
62577
  const container = createExportContainer(exportWidth, exportHeight);
61801
- const blActiveTagGroup = viewState?.tag ?? options?.tagGroup;
62578
+ const blActiveTagGroup = ctxTagOverride(ctx);
61802
62579
  renderBoxesAndLinesForExport2(
61803
62580
  container,
61804
62581
  blParsed,
61805
62582
  blLayout,
61806
62583
  effectivePalette,
61807
- theme === "dark",
62584
+ ctx.isDark,
61808
62585
  {
61809
62586
  exportDims: { width: exportWidth, height: exportHeight },
61810
62587
  ...blActiveTagGroup !== void 0 && {
@@ -61819,12 +62596,12 @@ async function exportBoxesAndLines(ctx) {
61819
62596
  return finalizeSvgExport(container, theme, effectivePalette);
61820
62597
  }
61821
62598
  async function exportMindmap(ctx) {
61822
- const { content, theme, palette, viewState, options, exportMode } = ctx;
62599
+ const { content, theme, palette, viewState, exportMode } = ctx;
61823
62600
  const { parseMindmap: parseMindmap2 } = await Promise.resolve().then(() => (init_parser19(), parser_exports13));
61824
62601
  const { layoutMindmap: layoutMindmap2 } = await Promise.resolve().then(() => (init_layout6(), layout_exports6));
61825
62602
  const { collapseMindmapTree: collapseMindmapTree2 } = await Promise.resolve().then(() => (init_collapse3(), collapse_exports3));
61826
62603
  const { renderMindmap: renderMindmap2 } = await Promise.resolve().then(() => (init_renderer7(), renderer_exports7));
61827
- const isDark = theme === "dark";
62604
+ const isDark = ctx.isDark;
61828
62605
  const effectivePalette = await resolveExportPalette(theme, palette);
61829
62606
  const mmParsed = parseMindmap2(content, effectivePalette);
61830
62607
  if (mmParsed.error) return "";
@@ -61832,7 +62609,7 @@ async function exportMindmap(ctx) {
61832
62609
  const activeTagGroup = resolveActiveTagGroup(
61833
62610
  mmParsed.tagGroups,
61834
62611
  mmParsed.options["active-tag"],
61835
- viewState?.tag ?? options?.tagGroup
62612
+ ctxTagOverride(ctx)
61836
62613
  );
61837
62614
  const hideDescriptions = mmParsed.options["no-descriptions"] === "true" || viewState?.hd === true;
61838
62615
  const { roots: effectiveRoots, hiddenCounts } = collapsedNodes && collapsedNodes.size > 0 ? collapseMindmapTree2(mmParsed.roots, collapsedNodes) : { roots: mmParsed.roots, hiddenCounts: /* @__PURE__ */ new Map() };
@@ -61882,7 +62659,7 @@ async function exportWireframe(ctx) {
61882
62659
  wireframeParsed,
61883
62660
  wireframeLayout,
61884
62661
  effectivePalette,
61885
- theme === "dark",
62662
+ ctx.isDark,
61886
62663
  void 0,
61887
62664
  { width: exportWidth, height: exportHeight },
61888
62665
  theme
@@ -61890,7 +62667,7 @@ async function exportWireframe(ctx) {
61890
62667
  return finalizeSvgExport(container, theme, effectivePalette);
61891
62668
  }
61892
62669
  async function exportC4(ctx) {
61893
- const { content, theme, palette, viewState, options, exportMode } = ctx;
62670
+ const { content, theme, palette, viewState, exportMode } = ctx;
61894
62671
  const { parseC4: parseC42 } = await Promise.resolve().then(() => (init_parser14(), parser_exports8));
61895
62672
  const {
61896
62673
  layoutC4Context: layoutC4Context2,
@@ -61902,9 +62679,9 @@ async function exportC4(ctx) {
61902
62679
  const effectivePalette = await resolveExportPalette(theme, palette);
61903
62680
  const c4Parsed = parseC42(content, effectivePalette);
61904
62681
  if (c4Parsed.error || c4Parsed.elements.length === 0) return "";
61905
- const c4Level = options?.c4Level ?? viewState?.c4l ?? "context";
61906
- const c4System = options?.c4System ?? viewState?.c4s;
61907
- const c4Container = options?.c4Container ?? viewState?.c4c;
62682
+ const c4Level = ctx.options?.c4Level ?? viewState?.c4l ?? "context";
62683
+ const c4System = ctx.options?.c4System ?? viewState?.c4s;
62684
+ const c4Container = ctx.options?.c4Container ?? viewState?.c4c;
61908
62685
  const c4Layout = c4Level === "deployment" ? layoutC4Deployment2(c4Parsed) : c4Level === "components" && c4System && c4Container ? layoutC4Components2(c4Parsed, c4System, c4Container) : c4Level === "containers" && c4System ? layoutC4Containers2(c4Parsed, c4System) : layoutC4Context2(c4Parsed);
61909
62686
  if (c4Layout.nodes.length === 0) return "";
61910
62687
  const PADDING3 = 20;
@@ -61918,13 +62695,13 @@ async function exportC4(ctx) {
61918
62695
  c4Parsed,
61919
62696
  c4Layout,
61920
62697
  effectivePalette,
61921
- theme === "dark",
62698
+ ctx.isDark,
61922
62699
  void 0,
61923
62700
  { width: exportWidth, height: exportHeight },
61924
62701
  resolveActiveTagGroup(
61925
62702
  c4Parsed.tagGroups,
61926
62703
  c4Parsed.options["active-tag"],
61927
- viewState?.tag ?? options?.tagGroup
62704
+ ctxTagOverride(ctx)
61928
62705
  ),
61929
62706
  exportMode
61930
62707
  );
@@ -61945,14 +62722,14 @@ async function exportFlowchart(ctx) {
61945
62722
  fcParsed,
61946
62723
  layout,
61947
62724
  effectivePalette,
61948
- theme === "dark",
62725
+ ctx.isDark,
61949
62726
  void 0,
61950
62727
  { width: EXPORT_WIDTH, height: EXPORT_HEIGHT }
61951
62728
  );
61952
62729
  return finalizeSvgExport(container, theme, effectivePalette);
61953
62730
  }
61954
62731
  async function exportInfra(ctx) {
61955
- const { content, theme, palette, viewState, options } = ctx;
62732
+ const { content, theme, palette, viewState } = ctx;
61956
62733
  const { parseInfra: parseInfra2 } = await Promise.resolve().then(() => (init_parser15(), parser_exports9));
61957
62734
  const { computeInfra: computeInfra2 } = await Promise.resolve().then(() => (init_compute(), compute_exports));
61958
62735
  const { layoutInfra: layoutInfra2 } = await Promise.resolve().then(() => (init_layout10(), layout_exports10));
@@ -61965,7 +62742,7 @@ async function exportInfra(ctx) {
61965
62742
  const activeTagGroup = resolveActiveTagGroup(
61966
62743
  infraParsed.tagGroups,
61967
62744
  infraParsed.options["active-tag"],
61968
- viewState?.tag ?? options?.tagGroup
62745
+ ctxTagOverride(ctx)
61969
62746
  );
61970
62747
  const showInfraTitle = !!infraParsed.title && infraParsed.options["no-title"] !== "on";
61971
62748
  const titleOffset = showInfraTitle ? 40 : 0;
@@ -61983,7 +62760,7 @@ async function exportInfra(ctx) {
61983
62760
  container,
61984
62761
  infraLayout,
61985
62762
  effectivePalette,
61986
- theme === "dark",
62763
+ ctx.isDark,
61987
62764
  showInfraTitle ? infraParsed.title : null,
61988
62765
  showInfraTitle ? infraParsed.titleLineNumber : null,
61989
62766
  infraTagGroups,
@@ -62030,7 +62807,7 @@ async function exportPert(ctx) {
62030
62807
  pertResolved,
62031
62808
  pertLayout,
62032
62809
  effectivePalette,
62033
- theme === "dark",
62810
+ ctx.isDark,
62034
62811
  {
62035
62812
  title: pertParsed.title,
62036
62813
  exportDims: { width: exportW, height: exportH },
@@ -62043,7 +62820,7 @@ async function exportPert(ctx) {
62043
62820
  return finalizeSvgExport(container, theme, effectivePalette);
62044
62821
  }
62045
62822
  async function exportGantt(ctx) {
62046
- const { content, theme, palette, viewState, options, exportMode } = ctx;
62823
+ const { content, theme, palette, viewState, exportMode } = ctx;
62047
62824
  const { parseGantt: parseGantt2 } = await Promise.resolve().then(() => (init_parser16(), parser_exports10));
62048
62825
  const { calculateSchedule: calculateSchedule2 } = await Promise.resolve().then(() => (init_calculator(), calculator_exports));
62049
62826
  const { renderGantt: renderGantt2 } = await Promise.resolve().then(() => (init_renderer12(), renderer_exports12));
@@ -62061,7 +62838,7 @@ async function exportGantt(ctx) {
62061
62838
  container,
62062
62839
  resolved,
62063
62840
  effectivePalette,
62064
- theme === "dark",
62841
+ ctx.isDark,
62065
62842
  {
62066
62843
  ...ganttCollapsedGroups !== void 0 && {
62067
62844
  collapsedGroups: ganttCollapsedGroups
@@ -62075,7 +62852,7 @@ async function exportGantt(ctx) {
62075
62852
  currentActiveGroup: resolveActiveTagGroup(
62076
62853
  resolved.tagGroups,
62077
62854
  resolved.options.activeTag ?? void 0,
62078
- viewState?.tag ?? options?.tagGroup
62855
+ ctxTagOverride(ctx)
62079
62856
  ),
62080
62857
  exportMode
62081
62858
  },
@@ -62098,7 +62875,7 @@ async function exportState(ctx) {
62098
62875
  stateParsed,
62099
62876
  layout,
62100
62877
  effectivePalette,
62101
- theme === "dark",
62878
+ ctx.isDark,
62102
62879
  void 0,
62103
62880
  { width: EXPORT_WIDTH, height: EXPORT_HEIGHT }
62104
62881
  );
@@ -62118,7 +62895,7 @@ async function exportTechRadar(ctx) {
62118
62895
  container,
62119
62896
  radarParsed,
62120
62897
  effectivePalette,
62121
- theme === "dark",
62898
+ ctx.isDark,
62122
62899
  { width: RADAR_EXPORT_W, height: RADAR_EXPORT_H },
62123
62900
  viewState,
62124
62901
  exportMode
@@ -62135,13 +62912,13 @@ async function exportJourneyMap(ctx) {
62135
62912
  if (jmParsed.error || jmParsed.phases.length === 0 && jmParsed.steps.length === 0)
62136
62913
  return "";
62137
62914
  const jmLayout = layoutJourneyMap2(jmParsed, effectivePalette, {
62138
- isDark: theme === "dark"
62915
+ isDark: ctx.isDark
62139
62916
  });
62140
62917
  const container = createExportContainer(
62141
62918
  jmLayout.totalWidth,
62142
62919
  jmLayout.totalHeight
62143
62920
  );
62144
- renderJourneyMap2(container, jmParsed, effectivePalette, theme === "dark", {
62921
+ renderJourneyMap2(container, jmParsed, effectivePalette, ctx.isDark, {
62145
62922
  exportDims: { width: jmLayout.totalWidth, height: jmLayout.totalHeight },
62146
62923
  exportMode
62147
62924
  });
@@ -62159,7 +62936,7 @@ async function exportCycle(ctx) {
62159
62936
  container,
62160
62937
  cycleParsed,
62161
62938
  effectivePalette,
62162
- theme === "dark",
62939
+ ctx.isDark,
62163
62940
  { width: EXPORT_WIDTH, height: EXPORT_HEIGHT },
62164
62941
  viewState,
62165
62942
  exportMode
@@ -62196,7 +62973,7 @@ async function exportMap(ctx) {
62196
62973
  mapResolved,
62197
62974
  mapData,
62198
62975
  effectivePalette,
62199
- theme === "dark",
62976
+ ctx.isDark,
62200
62977
  dims
62201
62978
  );
62202
62979
  return finalizeSvgExport(container, theme, effectivePalette);
@@ -62213,7 +62990,7 @@ async function exportPyramid(ctx) {
62213
62990
  container,
62214
62991
  pyramidParsed,
62215
62992
  effectivePalette,
62216
- theme === "dark",
62993
+ ctx.isDark,
62217
62994
  { width: EXPORT_WIDTH, height: EXPORT_HEIGHT }
62218
62995
  );
62219
62996
  return finalizeSvgExport(container, theme, effectivePalette);
@@ -62230,7 +63007,7 @@ async function exportRing(ctx) {
62230
63007
  container,
62231
63008
  ringParsed,
62232
63009
  effectivePalette,
62233
- theme === "dark",
63010
+ ctx.isDark,
62234
63011
  { width: EXPORT_WIDTH, height: EXPORT_HEIGHT }
62235
63012
  );
62236
63013
  return finalizeSvgExport(container, theme, effectivePalette);
@@ -62247,7 +63024,7 @@ async function exportRaci(ctx) {
62247
63024
  container,
62248
63025
  raciParsed,
62249
63026
  effectivePalette,
62250
- theme === "dark",
63027
+ ctx.isDark,
62251
63028
  { width: EXPORT_WIDTH, height: EXPORT_HEIGHT }
62252
63029
  );
62253
63030
  return finalizeSvgExport(container, theme, effectivePalette);
@@ -62270,7 +63047,7 @@ async function exportSlope(ctx) {
62270
63047
  container,
62271
63048
  parsed,
62272
63049
  effectivePalette,
62273
- theme === "dark",
63050
+ ctx.isDark,
62274
63051
  void 0,
62275
63052
  dims
62276
63053
  );
@@ -62286,14 +63063,14 @@ async function exportArc(ctx) {
62286
63063
  container,
62287
63064
  parsed,
62288
63065
  effectivePalette,
62289
- theme === "dark",
63066
+ ctx.isDark,
62290
63067
  void 0,
62291
63068
  dims
62292
63069
  );
62293
63070
  return finalizeSvgExport(container, theme, effectivePalette);
62294
63071
  }
62295
63072
  async function exportTimeline(ctx) {
62296
- const { content, theme, palette, viewState, options, exportMode } = ctx;
63073
+ const { content, theme, palette, viewState, exportMode } = ctx;
62297
63074
  const parsed = parseTimeline(content, palette);
62298
63075
  if (parsed.error || parsed.timelineEvents.length === 0) return "";
62299
63076
  const effectivePalette = await resolveExportPalette(theme, palette);
@@ -62302,13 +63079,13 @@ async function exportTimeline(ctx) {
62302
63079
  container,
62303
63080
  parsed,
62304
63081
  effectivePalette,
62305
- theme === "dark",
63082
+ ctx.isDark,
62306
63083
  void 0,
62307
63084
  dims,
62308
63085
  resolveActiveTagGroup(
62309
63086
  parsed.timelineTagGroups,
62310
63087
  parsed.timelineActiveTag,
62311
- viewState?.tag ?? options?.tagGroup
63088
+ ctxTagOverride(ctx)
62312
63089
  ),
62313
63090
  viewState?.swim,
62314
63091
  void 0,
@@ -62327,7 +63104,7 @@ async function exportWordcloud(ctx) {
62327
63104
  container,
62328
63105
  parsed,
62329
63106
  effectivePalette,
62330
- theme === "dark",
63107
+ ctx.isDark,
62331
63108
  dims
62332
63109
  );
62333
63110
  return finalizeSvgExport(container, theme, effectivePalette);
@@ -62342,7 +63119,7 @@ async function exportVenn(ctx) {
62342
63119
  container,
62343
63120
  parsed,
62344
63121
  effectivePalette,
62345
- theme === "dark",
63122
+ ctx.isDark,
62346
63123
  void 0,
62347
63124
  dims
62348
63125
  );
@@ -62358,14 +63135,14 @@ async function exportQuadrant(ctx) {
62358
63135
  container,
62359
63136
  parsed,
62360
63137
  effectivePalette,
62361
- theme === "dark",
63138
+ ctx.isDark,
62362
63139
  void 0,
62363
63140
  dims
62364
63141
  );
62365
63142
  return finalizeSvgExport(container, theme, effectivePalette);
62366
63143
  }
62367
63144
  async function exportVisualization(ctx) {
62368
- const { content, theme, palette, viewState, options } = ctx;
63145
+ const { content, theme, palette, viewState } = ctx;
62369
63146
  const parsed = parseVisualization(content, palette);
62370
63147
  if (parsed.type !== "sequence") {
62371
63148
  if (parsed.error) {
@@ -62376,7 +63153,7 @@ async function exportVisualization(ctx) {
62376
63153
  }
62377
63154
  }
62378
63155
  const effectivePalette = await resolveExportPalette(theme, palette);
62379
- const isDark = theme === "dark";
63156
+ const isDark = ctx.isDark;
62380
63157
  const container = createExportContainer(EXPORT_WIDTH, EXPORT_HEIGHT);
62381
63158
  const { parseSequenceDgmo: parseSequenceDgmo2 } = await Promise.resolve().then(() => (init_parser7(), parser_exports));
62382
63159
  const { renderSequenceDiagram: renderSequenceDiagram2 } = await Promise.resolve().then(() => (init_renderer20(), renderer_exports20));
@@ -62384,7 +63161,7 @@ async function exportVisualization(ctx) {
62384
63161
  if (seqParsed.error || seqParsed.participants.length === 0) return "";
62385
63162
  const collapsedSections = viewState?.cs ? new Set(viewState.cs) : void 0;
62386
63163
  const collapsedGroups = viewState?.cg ? new Set(viewState.cg.map(Number).filter((n) => Number.isFinite(n))) : void 0;
62387
- const seqActiveTagGroup = viewState?.tag ?? options?.tagGroup;
63164
+ const seqActiveTagGroup = ctxTagOverride(ctx);
62388
63165
  renderSequenceDiagram2(
62389
63166
  container,
62390
63167
  seqParsed,
@@ -62649,6 +63426,162 @@ function collapseBoxesAndLines(parsed, collapsedGroups) {
62649
63426
  };
62650
63427
  }
62651
63428
 
63429
+ // src/boxes-and-lines/focus.ts
63430
+ var GROUP_PREFIX = "__group_";
63431
+ var groupKey = (label) => `${GROUP_PREFIX}${label}`;
63432
+ var isGroupKey = (k) => k.startsWith(GROUP_PREFIX);
63433
+ var groupLabelOf = (k) => k.slice(GROUP_PREFIX.length);
63434
+ function focusBoxesAndLines(parsed, target) {
63435
+ const allValues = parsed.nodes.filter((n) => n.value !== void 0).map((n) => n.value);
63436
+ const rampDomain = allValues.length > 0 ? { min: Math.min(...allValues), max: Math.max(...allValues) } : null;
63437
+ const nodeLabelSet = new Set(parsed.nodes.map((n) => n.label));
63438
+ const groupByLabel = /* @__PURE__ */ new Map();
63439
+ for (const g of parsed.groups) groupByLabel.set(g.label, g);
63440
+ const parentOf = /* @__PURE__ */ new Map();
63441
+ for (const g of parsed.groups)
63442
+ for (const child of g.children) parentOf.set(child, g.label);
63443
+ const topAncestor = (label) => {
63444
+ let p = parentOf.get(label);
63445
+ if (p === void 0) return void 0;
63446
+ for (; ; ) {
63447
+ const up = parentOf.get(p);
63448
+ if (up === void 0) return p;
63449
+ p = up;
63450
+ }
63451
+ };
63452
+ const descendantsOf = (groupLabel) => {
63453
+ const nodes2 = /* @__PURE__ */ new Set();
63454
+ const groups2 = /* @__PURE__ */ new Set();
63455
+ const seen = /* @__PURE__ */ new Set([groupLabel]);
63456
+ const stack = [groupLabel];
63457
+ while (stack.length) {
63458
+ const cur = stack.pop();
63459
+ const g = groupByLabel.get(cur);
63460
+ if (!g) continue;
63461
+ for (const child of g.children) {
63462
+ if (groupByLabel.has(child)) {
63463
+ if (!seen.has(child)) {
63464
+ seen.add(child);
63465
+ groups2.add(child);
63466
+ stack.push(child);
63467
+ }
63468
+ } else {
63469
+ nodes2.add(child);
63470
+ }
63471
+ }
63472
+ }
63473
+ return { nodes: nodes2, groups: groups2 };
63474
+ };
63475
+ const focusNodeLabels = /* @__PURE__ */ new Set();
63476
+ const focusGroupLabels = /* @__PURE__ */ new Set();
63477
+ const focusEndpointSet = /* @__PURE__ */ new Set();
63478
+ if (target.kind === "group") {
63479
+ const gl = isGroupKey(target.id) ? groupLabelOf(target.id) : target.id;
63480
+ if (groupByLabel.has(gl)) {
63481
+ focusGroupLabels.add(gl);
63482
+ focusEndpointSet.add(groupKey(gl));
63483
+ const desc = descendantsOf(gl);
63484
+ for (const n of desc.nodes) {
63485
+ focusNodeLabels.add(n);
63486
+ focusEndpointSet.add(n);
63487
+ }
63488
+ for (const sg of desc.groups) {
63489
+ focusGroupLabels.add(sg);
63490
+ focusEndpointSet.add(groupKey(sg));
63491
+ }
63492
+ }
63493
+ } else {
63494
+ if (nodeLabelSet.has(target.id)) {
63495
+ focusNodeLabels.add(target.id);
63496
+ focusEndpointSet.add(target.id);
63497
+ }
63498
+ }
63499
+ const neighborIds = /* @__PURE__ */ new Set();
63500
+ const collapsedNeighborGroupIds = /* @__PURE__ */ new Set();
63501
+ const neighborBoxes = /* @__PURE__ */ new Set();
63502
+ const keepGroupLabels = new Set(focusGroupLabels);
63503
+ const keptEdges = [];
63504
+ const selfLoops = [];
63505
+ const keepGroupAndSubgroups = (gl) => {
63506
+ keepGroupLabels.add(gl);
63507
+ for (const sg of descendantsOf(gl).groups) keepGroupLabels.add(sg);
63508
+ };
63509
+ const classifyNeighbor = (key) => {
63510
+ if (isGroupKey(key)) {
63511
+ const gl = groupLabelOf(key);
63512
+ if (!groupByLabel.has(gl)) return false;
63513
+ if (focusGroupLabels.has(gl)) return true;
63514
+ neighborIds.add(key);
63515
+ collapsedNeighborGroupIds.add(gl);
63516
+ keepGroupAndSubgroups(gl);
63517
+ return true;
63518
+ }
63519
+ if (focusNodeLabels.has(key)) return true;
63520
+ if (!nodeLabelSet.has(key)) return false;
63521
+ const top = topAncestor(key);
63522
+ if (top !== void 0 && !focusGroupLabels.has(top)) {
63523
+ neighborIds.add(groupKey(top));
63524
+ collapsedNeighborGroupIds.add(top);
63525
+ keepGroupAndSubgroups(top);
63526
+ return true;
63527
+ }
63528
+ neighborIds.add(key);
63529
+ neighborBoxes.add(key);
63530
+ return true;
63531
+ };
63532
+ for (const edge of parsed.edges) {
63533
+ const inS = focusEndpointSet.has(edge.source);
63534
+ const inT = focusEndpointSet.has(edge.target);
63535
+ if (edge.source === edge.target) {
63536
+ if (inS) selfLoops.push(edge);
63537
+ continue;
63538
+ }
63539
+ if (inS && inT) {
63540
+ keptEdges.push(edge);
63541
+ continue;
63542
+ }
63543
+ if (!inS && !inT) continue;
63544
+ const other = inS ? edge.target : edge.source;
63545
+ if (classifyNeighbor(other)) keptEdges.push(edge);
63546
+ }
63547
+ const keepNodeLabels = /* @__PURE__ */ new Set([
63548
+ ...focusNodeLabels,
63549
+ ...neighborBoxes
63550
+ ]);
63551
+ const nodes = parsed.nodes.filter((n) => keepNodeLabels.has(n.label));
63552
+ const groups = parsed.groups.filter((g) => keepGroupLabels.has(g.label));
63553
+ const notes = parsed.notes?.filter((note) => keepNodeLabels.has(note.ref));
63554
+ const filtered = {
63555
+ ...parsed,
63556
+ nodes,
63557
+ edges: keptEdges,
63558
+ groups,
63559
+ ...notes !== void 0 && { notes }
63560
+ };
63561
+ delete filtered.nodePositions;
63562
+ const collapsed = collapseBoxesAndLines(filtered, collapsedNeighborGroupIds);
63563
+ let resultParsed = collapsed.parsed;
63564
+ if (selfLoops.length > 0) {
63565
+ const visible = new Set(resultParsed.nodes.map((n) => n.label));
63566
+ const survivors = selfLoops.filter((e) => visible.has(e.source));
63567
+ if (survivors.length > 0)
63568
+ resultParsed = {
63569
+ ...resultParsed,
63570
+ edges: [...resultParsed.edges, ...survivors]
63571
+ };
63572
+ }
63573
+ return {
63574
+ parsed: resultParsed,
63575
+ neighborIds,
63576
+ collapsedNeighborGroupIds,
63577
+ rampDomain,
63578
+ collapseInfo: {
63579
+ collapsedChildCounts: collapsed.collapsedChildCounts,
63580
+ originalGroups: collapsed.originalGroups
63581
+ }
63582
+ };
63583
+ }
63584
+
62652
63585
  // src/advanced.ts
62653
63586
  init_parser11();
62654
63587
  init_layout2();
@@ -64059,6 +64992,8 @@ function formatLineDiff(path, original, migrated) {
64059
64992
  CHART_TYPE_DESCRIPTIONS,
64060
64993
  ECHART_EXPORT_WIDTH,
64061
64994
  INFRA_BEHAVIOR_KEYS,
64995
+ INVALID_COLOR_CODE,
64996
+ INVALID_CSS_COLOR_HEX,
64062
64997
  LEGEND_GEAR_PILL_W,
64063
64998
  LEGEND_HEIGHT,
64064
64999
  RACI_ERROR_CODES,
@@ -64120,6 +65055,7 @@ function formatLineDiff(path, original, migrated) {
64120
65055
  extractInfraSymbols,
64121
65056
  extractPertSymbols,
64122
65057
  findUnsafePipePositions,
65058
+ focusBoxesAndLines,
64123
65059
  focusOrgTree,
64124
65060
  formatDateLabel,
64125
65061
  formatDgmoError,
@@ -64140,8 +65076,10 @@ function formatLineDiff(path, original, migrated) {
64140
65076
  hslToHex,
64141
65077
  inferParticipantType,
64142
65078
  inferRoles,
65079
+ invalidColorDiagnostic,
64143
65080
  isArchiveColumn,
64144
65081
  isExtendedChartType,
65082
+ isInvalidColorToken,
64145
65083
  isLegacyMetadataLine,
64146
65084
  isRecognizedColorName,
64147
65085
  isSequenceBlock,
@@ -64182,6 +65120,7 @@ function formatLineDiff(path, original, migrated) {
64182
65120
  migrateContent,
64183
65121
  mix,
64184
65122
  mulberry32,
65123
+ nearestNamedColor,
64185
65124
  nord,
64186
65125
  nordPalette,
64187
65126
  normalizeName,