@digilogiclabs/saas-factory-ui 1.30.2 → 1.30.3

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.
package/dist/index.d.mts CHANGED
@@ -5293,7 +5293,7 @@ declare function FlowTree({ data, title, eyebrow, tagline, renderIcon: renderIco
5293
5293
  * delta: it keeps connector strokes crisp under the pan/zoom transform's
5294
5294
  * `scale()` (otherwise sub-1 fit-zoom renders them sub-pixel and invisible).
5295
5295
  */
5296
- declare const FLOW_TREE_CSS = "\n@import url(\"https://fonts.googleapis.com/css2?family=Instrument+Serif:ital@0;1&family=Inter:wght@400;500;600&family=JetBrains+Mono:wght@400;500&display=swap\");\n\n.ft-shell {\n --ft-bg: oklch(0.165 0.008 80);\n --ft-panel: oklch(0.21 0.008 80);\n --ft-panel-2: oklch(0.25 0.01 80);\n --ft-fg: oklch(0.96 0.005 85);\n --ft-muted-fg: oklch(0.68 0.008 80);\n --ft-dim-fg: oklch(0.5 0.008 80);\n --ft-line: oklch(0.28 0.008 80);\n --ft-line-strong: oklch(0.4 0.008 80);\n --ft-grid-strong: oklch(0.24 0.008 80);\n --ft-tier-orange: #f16c25;\n --ft-tier-teal: #5fb7b8;\n --ft-tier-blue: oklch(0.72 0.12 240);\n --ft-tier-amber: oklch(0.8 0.14 75);\n --ft-tier-green: oklch(0.74 0.14 155);\n --ft-accent: var(--ft-tier-orange);\n --ft-serif: \"Instrument Serif\", Georgia, serif;\n --ft-sans: \"Inter\", system-ui, sans-serif;\n --ft-mono: \"JetBrains Mono\", ui-monospace, Menlo, monospace;\n\n /* Defensive shell sizing \u2014 fills flex parents (flex: 1) and block\n parents with definite dimensions (width/height: 100%). */\n flex: 1 1 auto;\n width: 100%;\n height: 100%;\n min-height: 420px;\n display: flex;\n flex-direction: column;\n background: var(--ft-bg);\n border: 1px solid var(--ft-line);\n border-radius: 2px;\n overflow: hidden;\n color: var(--ft-fg);\n font-family: var(--ft-sans);\n font-size: 14px;\n line-height: 1.5;\n -webkit-font-smoothing: antialiased;\n box-shadow: 0 30px 60px -30px oklch(0 0 0 / 0.5);\n}\n.ft-shell * { box-sizing: border-box; }\n.ft-shell .ft-mono {\n font-family: var(--ft-mono);\n font-size: 11px;\n letter-spacing: 0.02em;\n}\n\n.ft-header {\n padding: 22px 28px 20px;\n border-bottom: 1px solid var(--ft-line);\n background: linear-gradient(180deg, oklch(0.21 0.01 60) 0%, oklch(0.19 0.008 70) 100%);\n display: flex;\n flex-direction: column;\n gap: 6px;\n}\n.ft-header__eyebrow {\n font-family: var(--ft-mono);\n font-size: 10.5px;\n letter-spacing: 0.22em;\n text-transform: uppercase;\n color: var(--ft-tier-orange);\n}\n.ft-header__title {\n margin: 0;\n font-family: var(--ft-serif);\n font-weight: 400;\n font-size: 44px;\n line-height: 1;\n letter-spacing: -0.015em;\n color: var(--ft-fg);\n}\n.ft-header__tagline {\n margin: 6px 0 0;\n max-width: 76ch;\n color: var(--ft-muted-fg);\n font-size: 13px;\n}\n\n.ft-stage {\n position: relative;\n flex: 1;\n min-height: 0;\n overflow: hidden;\n background:\n radial-gradient(1200px 700px at 15% -10%, oklch(0.22 0.012 60), transparent 60%),\n radial-gradient(900px 600px at 110% 110%, oklch(0.2 0.02 200 / 0.5), transparent 65%);\n}\n\n.ft-svg {\n display: block;\n width: 100%;\n height: 100%;\n background: transparent;\n cursor: grab;\n touch-action: none;\n user-select: none;\n}\n.ft-svg.is-dragging { cursor: grabbing; }\n\n.ft-controls {\n position: absolute;\n top: 14px;\n right: 14px;\n z-index: 5;\n display: flex;\n align-items: center;\n gap: 6px;\n background: oklch(0.2 0.008 80 / 0.94);\n border: 1px solid var(--ft-line-strong);\n padding: 5px 8px;\n backdrop-filter: blur(8px);\n border-radius: 2px;\n}\n.ft-controls button {\n font-family: var(--ft-mono);\n font-size: 12px;\n width: 26px;\n height: 26px;\n background: transparent;\n border: 1px solid var(--ft-line);\n color: var(--ft-fg);\n cursor: pointer;\n padding: 0;\n}\n.ft-controls button:hover { border-color: var(--ft-tier-orange); }\n.ft-controls__reset {\n width: auto !important;\n padding: 0 10px !important;\n font-size: 9.5px !important;\n letter-spacing: 0.1em;\n text-transform: uppercase;\n}\n.ft-controls__hint {\n font-family: var(--ft-mono);\n font-size: 9.5px;\n color: var(--ft-muted-fg);\n letter-spacing: 0.04em;\n padding-left: 8px;\n margin-left: 2px;\n border-left: 1px solid var(--ft-line);\n}\n\n.ft-legend {\n position: absolute;\n left: 18px;\n bottom: 14px;\n z-index: 5;\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: 6px;\n font-family: var(--ft-mono);\n font-size: 10px;\n color: var(--ft-muted-fg);\n background: oklch(0.2 0.008 80 / 0.88);\n border: 1px solid var(--ft-line);\n padding: 6px 10px;\n backdrop-filter: blur(6px);\n max-width: calc(100% - 220px);\n}\n.ft-legend__chip {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 2px 6px;\n margin: -2px 0;\n background: transparent;\n border: none;\n color: inherit;\n font: inherit;\n letter-spacing: inherit;\n cursor: pointer;\n border-radius: 2px;\n transition: background 120ms, color 120ms;\n}\n.ft-legend__chip:hover {\n background: oklch(0.24 0.01 80);\n color: var(--ft-fg);\n}\n.ft-legend__chip:disabled {\n cursor: default;\n color: var(--ft-fg);\n}\n.ft-legend__chip:disabled:hover { background: transparent; }\n.ft-legend__dot {\n width: 5px;\n height: 5px;\n border-radius: 50%;\n background: var(--ft-tier-orange);\n flex-shrink: 0;\n}\n.ft-legend__sep {\n color: var(--ft-line-strong);\n margin: 0 2px;\n pointer-events: none;\n user-select: none;\n}\n\n/* edges */\n.ft-edge {\n fill: none;\n /* Keep stroke widths crisp under the SVG <g scale(z)> pan/zoom transform.\n Without this, fit-to-viewport (z \u2248 0.6-0.9) renders 1.6px strokes as\n sub-pixel and they visually disappear. */\n vector-effect: non-scaling-stroke;\n transition: stroke 260ms, opacity 260ms;\n}\n.ft-edge--off { stroke: var(--ft-line); stroke-width: 1; opacity: 0.55; }\n.ft-edge--on {\n stroke: var(--ft-tier-orange);\n /* Verbatim restore of the reference design (local-docs/styles.css\n line 133-140). The 4px dash + 5px gap reads as continuous\n marching-ant flow \u2014 every frame, dash edges visibly sweep across\n the path because the gap (5px) is shorter than the dash itself.\n This is what gives the focused branches their \"alive\" feel; the\n wider gap variants (1/12 in 1.30.1, 0.1/9 in 1.30.0) read as\n isolated dots and look static at typical fit-zoom levels. */\n stroke-width: 1.6;\n stroke-dasharray: 4 5;\n opacity: 1;\n animation: ftDashFlow 1.4s linear infinite;\n /* Visibility-under-zoom fix from 1.29.1 \u2014 without this, fit-zoom\n transforms (z \u2248 0.4-0.7) render the 1.6px stroke as sub-pixel\n and the line becomes invisible. Keeps stroke-width and\n dasharray in screen pixels regardless of the SVG transform.\n Not in the reference because the reference demo runs at z=1. */\n vector-effect: non-scaling-stroke;\n}\n@keyframes ftDashFlow {\n /* -36 == 4 \u00D7 (4+5) so the pattern advances exactly four cycles\n per period at 1.4s \u2014 perceptibly fast flow without strobing. */\n to { stroke-dashoffset: -36; }\n}\n@media (prefers-reduced-motion: reduce) {\n /* a11y improvement not in the reference \u2014 users who suppress\n motion get a clean solid line instead of a static frozen dash. */\n .ft-edge--on {\n animation: none;\n stroke-dasharray: none;\n }\n}\n\n/* card */\n.ft-card {\n --tier-local: var(--tier, var(--ft-line-strong));\n width: 100%;\n height: 100%;\n display: grid;\n grid-template-columns: 1fr auto;\n gap: 0;\n align-items: stretch;\n background: oklch(0.21 0.008 80);\n border: 1px solid var(--ft-line);\n border-left: 3px solid var(--tier-local);\n border-radius: 2px;\n transition:\n background 260ms cubic-bezier(.2,.8,.2,1),\n border-color 260ms, box-shadow 260ms,\n transform 260ms cubic-bezier(.2,.8,.2,1),\n filter 260ms, opacity 260ms, color 260ms;\n overflow: visible;\n animation: ftCardIn 320ms cubic-bezier(.2,.8,.2,1) backwards;\n}\n@keyframes ftCardIn {\n from { opacity: 0; transform: translateX(-6px); }\n to { opacity: 1; transform: translateX(0); }\n}\n.ft-card__main {\n display: grid;\n grid-template-columns: auto 1fr auto;\n gap: 10px;\n align-items: center;\n padding: 0 10px 0 12px;\n background: transparent;\n border: none;\n color: inherit;\n font-family: var(--ft-sans);\n font-size: 13px;\n text-align: left;\n cursor: pointer;\n min-width: 0;\n}\n.ft-card__main:hover { background: oklch(0.23 0.01 80 / 0.6); }\n.ft-card__icon {\n width: 24px;\n height: 24px;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n color: var(--tier-local);\n border: 1px solid var(--ft-line-strong);\n background: oklch(0.17 0.008 80);\n flex-shrink: 0;\n}\n.ft-card__body { display: flex; flex-direction: column; min-width: 0; gap: 1px; }\n.ft-card__label {\n font-family: var(--ft-serif);\n font-size: 15px;\n line-height: 1.15;\n color: var(--ft-fg);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n display: flex;\n align-items: center;\n gap: 5px;\n}\n.ft-card__sub {\n font-family: var(--ft-mono);\n font-size: 9.5px;\n letter-spacing: 0.02em;\n color: var(--ft-muted-fg);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n.ft-card__lock { color: var(--ft-muted-fg); display: inline-flex; }\n.ft-card__caret {\n width: 18px;\n height: 18px;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n font-family: var(--ft-mono);\n font-size: 12px;\n color: var(--ft-muted-fg);\n border: 1px solid var(--ft-line);\n}\n.ft-card--active .ft-card__caret {\n color: var(--tier-local);\n border-color: var(--tier-local);\n}\n\n.ft-card__rail {\n display: flex;\n flex-direction: column;\n border-left: 1px solid var(--ft-line);\n background: oklch(0.19 0.008 80);\n}\n.ft-card__mini {\n flex: 1;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 28px;\n min-height: 20px;\n background: transparent;\n border: none;\n color: var(--ft-muted-fg);\n cursor: pointer;\n transition: background 150ms, color 150ms;\n border-bottom: 1px solid var(--ft-line);\n padding: 0;\n text-decoration: none;\n}\n.ft-card__mini:last-child { border-bottom: none; }\n.ft-card__mini:hover { background: oklch(0.23 0.01 80); color: var(--tier-local); }\n.ft-card__mini.is-on { color: var(--tier-local); background: oklch(0.23 0.01 80); }\n\n/* states */\n.ft-card--active {\n background: oklch(0.25 0.015 60);\n box-shadow: 0 0 0 1px var(--tier-local), 0 14px 34px -16px oklch(0.5 0.18 50 / 0.55);\n transform: scale(1.02);\n}\n.ft-card--dim {\n filter: grayscale(0.85) brightness(0.82);\n opacity: 0.7;\n transform: scale(0.88);\n transform-origin: center left;\n}\n.ft-card--dim .ft-card__label { color: var(--ft-dim-fg); }\n.ft-card--dim:hover {\n filter: grayscale(0.3) brightness(0.96);\n opacity: 1;\n transform: scale(0.94);\n}\n.ft-card--cta {\n border-left-color: var(--ft-tier-orange);\n background: linear-gradient(180deg, oklch(0.23 0.02 55) 0%, oklch(0.2 0.015 60) 100%);\n}\n.ft-card--root {\n border-left-color: var(--ft-tier-orange);\n background: oklch(0.26 0.015 55);\n}\n.ft-card--root .ft-card__icon {\n color: var(--ft-tier-orange);\n border-color: var(--ft-tier-orange);\n}\n\n/* detail pop */\n.ft-detail {\n position: relative;\n margin-top: 0;\n padding: 16px 18px 14px;\n background: oklch(0.16 0.008 80);\n border: 1px solid var(--ft-line-strong);\n border-left: 2px solid var(--ft-tier-orange);\n border-radius: 3px;\n animation: ftDetailIn 220ms cubic-bezier(.2,.8,.2,1) backwards;\n color: var(--ft-fg);\n width: 320px;\n box-shadow: 0 18px 40px -8px rgba(0,0,0,0.6), 0 2px 8px rgba(0,0,0,0.4);\n}\n.ft-detail__head {\n display: flex;\n align-items: center;\n /* Clear room for the two stacked rail buttons in the top-right\n (expand + close). Bumped from 28px \u2192 58px to fit both. */\n margin: -2px 58px 10px 0;\n}\n.ft-detail__title {\n font-family: var(--ft-mono);\n font-size: 10px;\n letter-spacing: 0.14em;\n text-transform: uppercase;\n color: var(--ft-muted-fg);\n}\n.ft-detail__close,\n.ft-detail__expand {\n position: absolute;\n top: 8px;\n width: 22px;\n height: 22px;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n background: transparent;\n border: 1px solid var(--ft-line);\n border-radius: 2px;\n color: var(--ft-muted-fg);\n cursor: pointer;\n padding: 0;\n transition: color 120ms, border-color 120ms, background 120ms;\n}\n.ft-detail__close { right: 8px; }\n/* Expand button sits immediately to the left of close. */\n.ft-detail__expand { right: 36px; }\n.ft-detail__close:hover,\n.ft-detail__expand:hover {\n color: var(--ft-fg);\n border-color: var(--ft-tier-orange);\n background: oklch(0.22 0.008 80);\n}\n@keyframes ftDetailIn {\n from { opacity: 0; transform: translateY(-4px); }\n to { opacity: 1; transform: translateY(0); }\n}\n.ft-detail__lead {\n /* Inter (sans) at slightly larger size + medium weight reads\n dramatically better than serif italic on dark stages, while still\n looking distinct from the body paragraph. The orange accent\n border on the left preserves the \"pull-quote\" rhythm. */\n font-family: var(--ft-sans);\n font-size: 14.5px;\n line-height: 1.45;\n font-style: normal;\n font-weight: 500;\n color: var(--ft-fg);\n padding-left: 10px;\n border-left: 2px solid var(--ft-tier-orange);\n margin-bottom: 12px;\n}\n.ft-detail__body {\n margin: 0 0 10px;\n font-size: 12px;\n color: var(--ft-muted-fg);\n line-height: 1.5;\n}\n.ft-detail__bullets {\n margin: 0 0 10px;\n padding-left: 16px;\n font-size: 12px;\n color: var(--ft-fg);\n}\n.ft-detail__bullets li { margin-bottom: 3px; }\n.ft-detail__meta {\n margin: 0 0 10px;\n padding: 0;\n display: flex;\n flex-direction: column;\n gap: 4px;\n}\n.ft-detail__meta-row {\n display: grid;\n grid-template-columns: 96px 1fr;\n gap: 8px;\n font-size: 11px;\n}\n.ft-detail__meta-row dt {\n font-family: var(--ft-mono);\n font-size: 9.5px;\n letter-spacing: 0.1em;\n text-transform: uppercase;\n color: var(--ft-muted-fg);\n padding-top: 1px;\n}\n.ft-detail__meta-row dd { margin: 0; color: var(--ft-fg); }\n.ft-detail__actions {\n display: flex;\n gap: 6px;\n flex-wrap: wrap;\n margin-top: 8px;\n}\n\n.ft-btn {\n font-family: var(--ft-mono);\n font-size: 10px;\n letter-spacing: 0.1em;\n text-transform: uppercase;\n padding: 7px 10px;\n background: transparent;\n color: var(--ft-fg);\n border: 1px solid var(--ft-line-strong);\n text-decoration: none;\n cursor: pointer;\n display: inline-flex;\n gap: 5px;\n align-items: center;\n transition: border-color 150ms, background 150ms;\n}\n.ft-btn:hover { border-color: var(--ft-tier-orange); }\n.ft-btn--primary {\n background: var(--ft-tier-orange);\n color: oklch(0.18 0.01 50);\n border-color: var(--ft-tier-orange);\n}\n\n@media (max-width: 760px) {\n .ft-header { padding: 16px 18px 14px; }\n .ft-header__title { font-size: 32px; }\n .ft-controls__hint { display: none; }\n .ft-legend { max-width: calc(100% - 24px); left: 10px; bottom: 10px; }\n /* Larger touch targets on phones \u2014 bumps zoom controls from 26px\n to 36px to comfortably clear the 44px Apple HIG / Material 48dp\n minimum once you account for visual padding. */\n .ft-controls { padding: 6px 8px; }\n .ft-controls button { width: 36px; height: 36px; font-size: 16px; }\n .ft-controls__reset { padding: 0 14px !important; height: 36px; }\n /* Inline detail popup buttons are intentionally compact in the\n inline footprint \u2014 but on touch the user can promote to the\n fullscreen overlay which has 28px buttons by default. */\n .ft-detail__close, .ft-detail__expand { width: 28px; height: 28px; }\n .ft-detail__expand { right: 42px; }\n .ft-detail__head { margin-right: 70px; }\n}\n@media (max-width: 480px) {\n /* Phone-sized: shrink card width so 5+ depth levels still fit\n reasonably without forcing the user to scroll horizontally to\n read the labels. Cards still ellipsis-truncate when needed. */\n .ft-card { font-size: 12px; }\n .ft-card__label { font-size: 14px; }\n .ft-card__sub { font-size: 9px; }\n .ft-controls__hint { display: none; }\n}\n\n/* \u2500\u2500\u2500 Fullscreen detail overlay \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n Triggered by the expand button in any inline DetailPop. Renders\n inside .ft-stage as an absolutely-positioned scrim + scrollable\n panel. The inline pop stays mounted (cheaper React tree) but the\n user's focus and the pointer-events both transfer to the overlay\n while it's visible.\n*/\n.ft-detail-overlay {\n position: absolute;\n inset: 0;\n z-index: 20;\n display: flex;\n align-items: stretch;\n justify-content: center;\n /* Translucent backdrop blurs the flow tree behind so the focused\n content reads cleanly without losing the user's \"where am I\"\n spatial anchor. */\n background: oklch(0.12 0.008 80 / 0.78);\n backdrop-filter: blur(6px);\n animation: ftOverlayIn 200ms cubic-bezier(.2,.8,.2,1);\n}\n@keyframes ftOverlayIn {\n from { opacity: 0; }\n to { opacity: 1; }\n}\n.ft-detail-overlay__panel {\n position: relative;\n margin: 36px;\n flex: 1 1 auto;\n max-width: 760px;\n background: oklch(0.18 0.008 80);\n border: 1px solid var(--ft-line-strong);\n border-left: 3px solid var(--ft-tier-orange);\n border-radius: 4px;\n overflow: auto;\n padding: 26px 32px 28px;\n box-shadow: 0 30px 80px -10px oklch(0 0 0 / 0.7);\n animation: ftOverlayPanelIn 240ms cubic-bezier(.2,.8,.2,1);\n}\n@keyframes ftOverlayPanelIn {\n from { opacity: 0; transform: translateY(8px); }\n to { opacity: 1; transform: translateY(0); }\n}\n.ft-detail-overlay__panel .ft-detail__title {\n font-size: 11px;\n}\n.ft-detail-overlay__panel .ft-detail__lead {\n font-size: 18px;\n line-height: 1.5;\n padding-left: 14px;\n}\n.ft-detail-overlay__panel .ft-detail__body {\n font-size: 14px;\n color: var(--ft-fg);\n line-height: 1.65;\n}\n.ft-detail-overlay__panel .ft-detail__bullets {\n font-size: 14px;\n line-height: 1.55;\n padding-left: 20px;\n}\n.ft-detail-overlay__panel .ft-detail__bullets li { margin-bottom: 6px; }\n.ft-detail-overlay__panel .ft-detail__meta-row {\n font-size: 13px;\n grid-template-columns: 140px 1fr;\n}\n.ft-detail-overlay__panel .ft-detail__meta-row dt { font-size: 10.5px; }\n.ft-detail-overlay__panel .ft-btn { font-size: 11px; padding: 9px 14px; }\n.ft-detail-overlay__head {\n display: flex;\n align-items: center;\n margin: 0 0 14px;\n padding-right: 70px;\n}\n.ft-detail-overlay__title {\n font-family: var(--ft-mono);\n font-size: 11px;\n letter-spacing: 0.18em;\n text-transform: uppercase;\n color: var(--ft-tier-orange);\n}\n.ft-detail-overlay__close,\n.ft-detail-overlay__collapse {\n position: absolute;\n top: 16px;\n width: 28px;\n height: 28px;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n background: transparent;\n border: 1px solid var(--ft-line-strong);\n border-radius: 2px;\n color: var(--ft-fg);\n cursor: pointer;\n padding: 0;\n transition: color 120ms, border-color 120ms, background 120ms;\n}\n.ft-detail-overlay__close { right: 16px; }\n.ft-detail-overlay__collapse { right: 52px; }\n.ft-detail-overlay__close:hover,\n.ft-detail-overlay__collapse:hover {\n color: var(--ft-tier-orange);\n border-color: var(--ft-tier-orange);\n background: oklch(0.22 0.008 80);\n}\n\n@media (max-width: 760px) {\n .ft-detail-overlay__panel {\n margin: 12px;\n padding: 18px 18px 22px;\n }\n .ft-detail-overlay__panel .ft-detail__lead { font-size: 16px; }\n}\n";
5296
+ declare const FLOW_TREE_CSS = "\n@import url(\"https://fonts.googleapis.com/css2?family=Instrument+Serif:ital@0;1&family=Inter:wght@400;500;600&family=JetBrains+Mono:wght@400;500&display=swap\");\n\n.ft-shell {\n --ft-bg: oklch(0.165 0.008 80);\n --ft-panel: oklch(0.21 0.008 80);\n --ft-panel-2: oklch(0.25 0.01 80);\n --ft-fg: oklch(0.96 0.005 85);\n --ft-muted-fg: oklch(0.68 0.008 80);\n --ft-dim-fg: oklch(0.5 0.008 80);\n --ft-line: oklch(0.28 0.008 80);\n --ft-line-strong: oklch(0.4 0.008 80);\n --ft-grid-strong: oklch(0.24 0.008 80);\n --ft-tier-orange: #f16c25;\n --ft-tier-teal: #5fb7b8;\n --ft-tier-blue: oklch(0.72 0.12 240);\n --ft-tier-amber: oklch(0.8 0.14 75);\n --ft-tier-green: oklch(0.74 0.14 155);\n --ft-accent: var(--ft-tier-orange);\n --ft-serif: \"Instrument Serif\", Georgia, serif;\n --ft-sans: \"Inter\", system-ui, sans-serif;\n --ft-mono: \"JetBrains Mono\", ui-monospace, Menlo, monospace;\n\n /* Defensive shell sizing \u2014 fills flex parents (flex: 1) and block\n parents with definite dimensions (width/height: 100%). */\n flex: 1 1 auto;\n width: 100%;\n height: 100%;\n min-height: 420px;\n display: flex;\n flex-direction: column;\n background: var(--ft-bg);\n border: 1px solid var(--ft-line);\n border-radius: 2px;\n overflow: hidden;\n color: var(--ft-fg);\n font-family: var(--ft-sans);\n font-size: 14px;\n line-height: 1.5;\n -webkit-font-smoothing: antialiased;\n box-shadow: 0 30px 60px -30px oklch(0 0 0 / 0.5);\n}\n.ft-shell * { box-sizing: border-box; }\n.ft-shell .ft-mono {\n font-family: var(--ft-mono);\n font-size: 11px;\n letter-spacing: 0.02em;\n}\n\n.ft-header {\n padding: 22px 28px 20px;\n border-bottom: 1px solid var(--ft-line);\n background: linear-gradient(180deg, oklch(0.21 0.01 60) 0%, oklch(0.19 0.008 70) 100%);\n display: flex;\n flex-direction: column;\n gap: 6px;\n}\n.ft-header__eyebrow {\n font-family: var(--ft-mono);\n font-size: 10.5px;\n letter-spacing: 0.22em;\n text-transform: uppercase;\n color: var(--ft-tier-orange);\n}\n.ft-header__title {\n margin: 0;\n font-family: var(--ft-serif);\n font-weight: 400;\n font-size: 44px;\n line-height: 1;\n letter-spacing: -0.015em;\n color: var(--ft-fg);\n}\n.ft-header__tagline {\n margin: 6px 0 0;\n max-width: 76ch;\n color: var(--ft-muted-fg);\n font-size: 13px;\n}\n\n.ft-stage {\n position: relative;\n flex: 1;\n min-height: 0;\n overflow: hidden;\n background:\n radial-gradient(1200px 700px at 15% -10%, oklch(0.22 0.012 60), transparent 60%),\n radial-gradient(900px 600px at 110% 110%, oklch(0.2 0.02 200 / 0.5), transparent 65%);\n}\n\n.ft-svg {\n display: block;\n width: 100%;\n height: 100%;\n background: transparent;\n cursor: grab;\n touch-action: none;\n user-select: none;\n}\n.ft-svg.is-dragging { cursor: grabbing; }\n\n.ft-controls {\n position: absolute;\n top: 14px;\n right: 14px;\n z-index: 5;\n display: flex;\n align-items: center;\n gap: 6px;\n background: oklch(0.2 0.008 80 / 0.94);\n border: 1px solid var(--ft-line-strong);\n padding: 5px 8px;\n backdrop-filter: blur(8px);\n border-radius: 2px;\n}\n.ft-controls button {\n font-family: var(--ft-mono);\n font-size: 12px;\n width: 26px;\n height: 26px;\n background: transparent;\n border: 1px solid var(--ft-line);\n color: var(--ft-fg);\n cursor: pointer;\n padding: 0;\n}\n.ft-controls button:hover { border-color: var(--ft-tier-orange); }\n.ft-controls__reset {\n width: auto !important;\n padding: 0 10px !important;\n font-size: 9.5px !important;\n letter-spacing: 0.1em;\n text-transform: uppercase;\n}\n.ft-controls__hint {\n font-family: var(--ft-mono);\n font-size: 9.5px;\n color: var(--ft-muted-fg);\n letter-spacing: 0.04em;\n padding-left: 8px;\n margin-left: 2px;\n border-left: 1px solid var(--ft-line);\n}\n\n.ft-legend {\n position: absolute;\n left: 18px;\n bottom: 14px;\n z-index: 5;\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: 6px;\n font-family: var(--ft-mono);\n font-size: 10px;\n color: var(--ft-muted-fg);\n background: oklch(0.2 0.008 80 / 0.88);\n border: 1px solid var(--ft-line);\n padding: 6px 10px;\n backdrop-filter: blur(6px);\n max-width: calc(100% - 220px);\n}\n.ft-legend__chip {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 2px 6px;\n margin: -2px 0;\n background: transparent;\n border: none;\n color: inherit;\n font: inherit;\n letter-spacing: inherit;\n cursor: pointer;\n border-radius: 2px;\n transition: background 120ms, color 120ms;\n}\n.ft-legend__chip:hover {\n background: oklch(0.24 0.01 80);\n color: var(--ft-fg);\n}\n.ft-legend__chip:disabled {\n cursor: default;\n color: var(--ft-fg);\n}\n.ft-legend__chip:disabled:hover { background: transparent; }\n.ft-legend__dot {\n width: 5px;\n height: 5px;\n border-radius: 50%;\n background: var(--ft-tier-orange);\n flex-shrink: 0;\n}\n.ft-legend__sep {\n color: var(--ft-line-strong);\n margin: 0 2px;\n pointer-events: none;\n user-select: none;\n}\n\n/* edges */\n.ft-edge {\n fill: none;\n /* Keep stroke widths crisp under the SVG <g scale(z)> pan/zoom transform.\n Without this, fit-to-viewport (z \u2248 0.6-0.9) renders 1.6px strokes as\n sub-pixel and they visually disappear. */\n vector-effect: non-scaling-stroke;\n transition: stroke 260ms, opacity 260ms;\n}\n.ft-edge--off { stroke: var(--ft-line); stroke-width: 1; opacity: 0.55; }\n.ft-edge--on {\n stroke: var(--ft-tier-orange);\n /* Verbatim restore of the reference design (local-docs/styles.css\n line 133-140). The 4px dash + 5px gap reads as continuous\n marching-ant flow \u2014 every frame, dash edges visibly sweep across\n the path because the gap (5px) is shorter than the dash itself.\n This is what gives the focused branches their \"alive\" feel; the\n wider gap variants (1/12 in 1.30.1, 0.1/9 in 1.30.0) read as\n isolated dots and look static at typical fit-zoom levels. */\n stroke-width: 1.6;\n stroke-dasharray: 4 5;\n opacity: 1;\n animation: ftDashFlow 1.4s linear infinite;\n /* Visibility-under-zoom fix from 1.29.1 \u2014 without this, fit-zoom\n transforms (z \u2248 0.4-0.7) render the 1.6px stroke as sub-pixel\n and the line becomes invisible. Keeps stroke-width and\n dasharray in screen pixels regardless of the SVG transform.\n Not in the reference because the reference demo runs at z=1. */\n vector-effect: non-scaling-stroke;\n}\n@keyframes ftDashFlow {\n /* -36 == 4 \u00D7 (4+5) so the pattern advances exactly four cycles\n per period at 1.4s \u2014 perceptibly fast flow without strobing. */\n to { stroke-dashoffset: -36; }\n}\n@media (prefers-reduced-motion: reduce) {\n /* a11y improvement not in the reference \u2014 users who suppress motion\n get the marching dashes frozen in place. The 4/5 dash pattern is\n fully readable without animation (it still reads as a directional\n \"this connects\" cue), so we keep the dasharray and only stop the\n animation. 1.30.1 dropped the dasharray entirely here, which\n silently regressed the reduced-motion path to look like a plain\n solid orange line \u2014 the s182 fix restores dash visibility. */\n .ft-edge--on {\n animation: none;\n }\n}\n\n/* card */\n.ft-card {\n --tier-local: var(--tier, var(--ft-line-strong));\n width: 100%;\n height: 100%;\n display: grid;\n grid-template-columns: 1fr auto;\n gap: 0;\n align-items: stretch;\n background: oklch(0.21 0.008 80);\n border: 1px solid var(--ft-line);\n border-left: 3px solid var(--tier-local);\n border-radius: 2px;\n transition:\n background 260ms cubic-bezier(.2,.8,.2,1),\n border-color 260ms, box-shadow 260ms,\n transform 260ms cubic-bezier(.2,.8,.2,1),\n filter 260ms, opacity 260ms, color 260ms;\n overflow: visible;\n animation: ftCardIn 320ms cubic-bezier(.2,.8,.2,1) backwards;\n}\n@keyframes ftCardIn {\n from { opacity: 0; transform: translateX(-6px); }\n to { opacity: 1; transform: translateX(0); }\n}\n.ft-card__main {\n display: grid;\n grid-template-columns: auto 1fr auto;\n gap: 10px;\n align-items: center;\n padding: 0 10px 0 12px;\n background: transparent;\n border: none;\n color: inherit;\n font-family: var(--ft-sans);\n font-size: 13px;\n text-align: left;\n cursor: pointer;\n min-width: 0;\n}\n.ft-card__main:hover { background: oklch(0.23 0.01 80 / 0.6); }\n.ft-card__icon {\n width: 24px;\n height: 24px;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n color: var(--tier-local);\n border: 1px solid var(--ft-line-strong);\n background: oklch(0.17 0.008 80);\n flex-shrink: 0;\n}\n.ft-card__body { display: flex; flex-direction: column; min-width: 0; gap: 1px; }\n.ft-card__label {\n font-family: var(--ft-serif);\n font-size: 15px;\n line-height: 1.15;\n color: var(--ft-fg);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n display: flex;\n align-items: center;\n gap: 5px;\n}\n.ft-card__sub {\n font-family: var(--ft-mono);\n font-size: 9.5px;\n letter-spacing: 0.02em;\n color: var(--ft-muted-fg);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n.ft-card__lock { color: var(--ft-muted-fg); display: inline-flex; }\n.ft-card__caret {\n width: 18px;\n height: 18px;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n font-family: var(--ft-mono);\n font-size: 12px;\n color: var(--ft-muted-fg);\n border: 1px solid var(--ft-line);\n}\n.ft-card--active .ft-card__caret {\n color: var(--tier-local);\n border-color: var(--tier-local);\n}\n\n.ft-card__rail {\n display: flex;\n flex-direction: column;\n border-left: 1px solid var(--ft-line);\n background: oklch(0.19 0.008 80);\n}\n.ft-card__mini {\n flex: 1;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 28px;\n min-height: 20px;\n background: transparent;\n border: none;\n color: var(--ft-muted-fg);\n cursor: pointer;\n transition: background 150ms, color 150ms;\n border-bottom: 1px solid var(--ft-line);\n padding: 0;\n text-decoration: none;\n}\n.ft-card__mini:last-child { border-bottom: none; }\n.ft-card__mini:hover { background: oklch(0.23 0.01 80); color: var(--tier-local); }\n.ft-card__mini.is-on { color: var(--tier-local); background: oklch(0.23 0.01 80); }\n\n/* states */\n.ft-card--active {\n background: oklch(0.25 0.015 60);\n box-shadow: 0 0 0 1px var(--tier-local), 0 14px 34px -16px oklch(0.5 0.18 50 / 0.55);\n transform: scale(1.02);\n}\n.ft-card--dim {\n filter: grayscale(0.85) brightness(0.82);\n opacity: 0.7;\n transform: scale(0.88);\n transform-origin: center left;\n}\n.ft-card--dim .ft-card__label { color: var(--ft-dim-fg); }\n.ft-card--dim:hover {\n filter: grayscale(0.3) brightness(0.96);\n opacity: 1;\n transform: scale(0.94);\n}\n.ft-card--cta {\n border-left-color: var(--ft-tier-orange);\n background: linear-gradient(180deg, oklch(0.23 0.02 55) 0%, oklch(0.2 0.015 60) 100%);\n}\n.ft-card--root {\n border-left-color: var(--ft-tier-orange);\n background: oklch(0.26 0.015 55);\n}\n.ft-card--root .ft-card__icon {\n color: var(--ft-tier-orange);\n border-color: var(--ft-tier-orange);\n}\n\n/* detail pop */\n.ft-detail {\n position: relative;\n margin-top: 0;\n padding: 16px 18px 14px;\n background: oklch(0.16 0.008 80);\n border: 1px solid var(--ft-line-strong);\n border-left: 2px solid var(--ft-tier-orange);\n border-radius: 3px;\n animation: ftDetailIn 220ms cubic-bezier(.2,.8,.2,1) backwards;\n color: var(--ft-fg);\n width: 320px;\n box-shadow: 0 18px 40px -8px rgba(0,0,0,0.6), 0 2px 8px rgba(0,0,0,0.4);\n}\n.ft-detail__head {\n display: flex;\n align-items: center;\n /* Clear room for the two stacked rail buttons in the top-right\n (expand + close). Bumped from 28px \u2192 58px to fit both. */\n margin: -2px 58px 10px 0;\n}\n.ft-detail__title {\n font-family: var(--ft-mono);\n font-size: 10px;\n letter-spacing: 0.14em;\n text-transform: uppercase;\n color: var(--ft-muted-fg);\n}\n.ft-detail__close,\n.ft-detail__expand {\n position: absolute;\n top: 8px;\n width: 22px;\n height: 22px;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n background: transparent;\n border: 1px solid var(--ft-line);\n border-radius: 2px;\n color: var(--ft-muted-fg);\n cursor: pointer;\n padding: 0;\n transition: color 120ms, border-color 120ms, background 120ms;\n}\n.ft-detail__close { right: 8px; }\n/* Expand button sits immediately to the left of close. */\n.ft-detail__expand { right: 36px; }\n.ft-detail__close:hover,\n.ft-detail__expand:hover {\n color: var(--ft-fg);\n border-color: var(--ft-tier-orange);\n background: oklch(0.22 0.008 80);\n}\n@keyframes ftDetailIn {\n from { opacity: 0; transform: translateY(-4px); }\n to { opacity: 1; transform: translateY(0); }\n}\n.ft-detail__lead {\n /* Inter (sans) at slightly larger size + medium weight reads\n dramatically better than serif italic on dark stages, while still\n looking distinct from the body paragraph. The orange accent\n border on the left preserves the \"pull-quote\" rhythm. */\n font-family: var(--ft-sans);\n font-size: 14.5px;\n line-height: 1.45;\n font-style: normal;\n font-weight: 500;\n color: var(--ft-fg);\n padding-left: 10px;\n border-left: 2px solid var(--ft-tier-orange);\n margin-bottom: 12px;\n}\n.ft-detail__body {\n margin: 0 0 10px;\n font-size: 12px;\n color: var(--ft-muted-fg);\n line-height: 1.5;\n}\n.ft-detail__bullets {\n margin: 0 0 10px;\n padding-left: 16px;\n font-size: 12px;\n color: var(--ft-fg);\n}\n.ft-detail__bullets li { margin-bottom: 3px; }\n.ft-detail__meta {\n margin: 0 0 10px;\n padding: 0;\n display: flex;\n flex-direction: column;\n gap: 4px;\n}\n.ft-detail__meta-row {\n display: grid;\n grid-template-columns: 96px 1fr;\n gap: 8px;\n font-size: 11px;\n}\n.ft-detail__meta-row dt {\n font-family: var(--ft-mono);\n font-size: 9.5px;\n letter-spacing: 0.1em;\n text-transform: uppercase;\n color: var(--ft-muted-fg);\n padding-top: 1px;\n}\n.ft-detail__meta-row dd { margin: 0; color: var(--ft-fg); }\n.ft-detail__actions {\n display: flex;\n gap: 6px;\n flex-wrap: wrap;\n margin-top: 8px;\n}\n\n.ft-btn {\n font-family: var(--ft-mono);\n font-size: 10px;\n letter-spacing: 0.1em;\n text-transform: uppercase;\n padding: 7px 10px;\n background: transparent;\n color: var(--ft-fg);\n border: 1px solid var(--ft-line-strong);\n text-decoration: none;\n cursor: pointer;\n display: inline-flex;\n gap: 5px;\n align-items: center;\n transition: border-color 150ms, background 150ms;\n}\n.ft-btn:hover { border-color: var(--ft-tier-orange); }\n.ft-btn--primary {\n background: var(--ft-tier-orange);\n color: oklch(0.18 0.01 50);\n border-color: var(--ft-tier-orange);\n}\n\n@media (max-width: 760px) {\n .ft-header { padding: 16px 18px 14px; }\n .ft-header__title { font-size: 32px; }\n .ft-controls__hint { display: none; }\n .ft-legend { max-width: calc(100% - 24px); left: 10px; bottom: 10px; }\n /* Larger touch targets on phones \u2014 bumps zoom controls from 26px\n to 36px to comfortably clear the 44px Apple HIG / Material 48dp\n minimum once you account for visual padding. */\n .ft-controls { padding: 6px 8px; }\n .ft-controls button { width: 36px; height: 36px; font-size: 16px; }\n .ft-controls__reset { padding: 0 14px !important; height: 36px; }\n /* Inline detail popup buttons are intentionally compact in the\n inline footprint \u2014 but on touch the user can promote to the\n fullscreen overlay which has 28px buttons by default. */\n .ft-detail__close, .ft-detail__expand { width: 28px; height: 28px; }\n .ft-detail__expand { right: 42px; }\n .ft-detail__head { margin-right: 70px; }\n}\n@media (max-width: 480px) {\n /* Phone-sized: shrink card width so 5+ depth levels still fit\n reasonably without forcing the user to scroll horizontally to\n read the labels. Cards still ellipsis-truncate when needed. */\n .ft-card { font-size: 12px; }\n .ft-card__label { font-size: 14px; }\n .ft-card__sub { font-size: 9px; }\n .ft-controls__hint { display: none; }\n}\n\n/* \u2500\u2500\u2500 Fullscreen detail overlay \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n Triggered by the expand button in any inline DetailPop. Renders\n inside .ft-stage as an absolutely-positioned scrim + scrollable\n panel. The inline pop stays mounted (cheaper React tree) but the\n user's focus and the pointer-events both transfer to the overlay\n while it's visible.\n*/\n.ft-detail-overlay {\n position: absolute;\n inset: 0;\n z-index: 20;\n display: flex;\n align-items: stretch;\n justify-content: center;\n /* Translucent backdrop blurs the flow tree behind so the focused\n content reads cleanly without losing the user's \"where am I\"\n spatial anchor. */\n background: oklch(0.12 0.008 80 / 0.78);\n backdrop-filter: blur(6px);\n animation: ftOverlayIn 200ms cubic-bezier(.2,.8,.2,1);\n}\n@keyframes ftOverlayIn {\n from { opacity: 0; }\n to { opacity: 1; }\n}\n.ft-detail-overlay__panel {\n position: relative;\n margin: 36px;\n flex: 1 1 auto;\n max-width: 760px;\n background: oklch(0.18 0.008 80);\n border: 1px solid var(--ft-line-strong);\n border-left: 3px solid var(--ft-tier-orange);\n border-radius: 4px;\n overflow: auto;\n padding: 26px 32px 28px;\n box-shadow: 0 30px 80px -10px oklch(0 0 0 / 0.7);\n animation: ftOverlayPanelIn 240ms cubic-bezier(.2,.8,.2,1);\n}\n@keyframes ftOverlayPanelIn {\n from { opacity: 0; transform: translateY(8px); }\n to { opacity: 1; transform: translateY(0); }\n}\n.ft-detail-overlay__panel .ft-detail__title {\n font-size: 11px;\n}\n.ft-detail-overlay__panel .ft-detail__lead {\n font-size: 18px;\n line-height: 1.5;\n padding-left: 14px;\n}\n.ft-detail-overlay__panel .ft-detail__body {\n font-size: 14px;\n color: var(--ft-fg);\n line-height: 1.65;\n}\n.ft-detail-overlay__panel .ft-detail__bullets {\n font-size: 14px;\n line-height: 1.55;\n padding-left: 20px;\n}\n.ft-detail-overlay__panel .ft-detail__bullets li { margin-bottom: 6px; }\n.ft-detail-overlay__panel .ft-detail__meta-row {\n font-size: 13px;\n grid-template-columns: 140px 1fr;\n}\n.ft-detail-overlay__panel .ft-detail__meta-row dt { font-size: 10.5px; }\n.ft-detail-overlay__panel .ft-btn { font-size: 11px; padding: 9px 14px; }\n.ft-detail-overlay__head {\n display: flex;\n align-items: center;\n margin: 0 0 14px;\n padding-right: 70px;\n}\n.ft-detail-overlay__title {\n font-family: var(--ft-mono);\n font-size: 11px;\n letter-spacing: 0.18em;\n text-transform: uppercase;\n color: var(--ft-tier-orange);\n}\n.ft-detail-overlay__close,\n.ft-detail-overlay__collapse {\n position: absolute;\n top: 16px;\n width: 28px;\n height: 28px;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n background: transparent;\n border: 1px solid var(--ft-line-strong);\n border-radius: 2px;\n color: var(--ft-fg);\n cursor: pointer;\n padding: 0;\n transition: color 120ms, border-color 120ms, background 120ms;\n}\n.ft-detail-overlay__close { right: 16px; }\n.ft-detail-overlay__collapse { right: 52px; }\n.ft-detail-overlay__close:hover,\n.ft-detail-overlay__collapse:hover {\n color: var(--ft-tier-orange);\n border-color: var(--ft-tier-orange);\n background: oklch(0.22 0.008 80);\n}\n\n@media (max-width: 760px) {\n .ft-detail-overlay__panel {\n margin: 12px;\n padding: 18px 18px 22px;\n }\n .ft-detail-overlay__panel .ft-detail__lead { font-size: 16px; }\n}\n";
5297
5297
 
5298
5298
  type GameTimerMode = "countdown" | "countup";
5299
5299
  type GameTimerThemePreset = "green" | "red" | "blue" | "amber" | "purple" | "pink" | "teal";
package/dist/index.d.ts CHANGED
@@ -5293,7 +5293,7 @@ declare function FlowTree({ data, title, eyebrow, tagline, renderIcon: renderIco
5293
5293
  * delta: it keeps connector strokes crisp under the pan/zoom transform's
5294
5294
  * `scale()` (otherwise sub-1 fit-zoom renders them sub-pixel and invisible).
5295
5295
  */
5296
- declare const FLOW_TREE_CSS = "\n@import url(\"https://fonts.googleapis.com/css2?family=Instrument+Serif:ital@0;1&family=Inter:wght@400;500;600&family=JetBrains+Mono:wght@400;500&display=swap\");\n\n.ft-shell {\n --ft-bg: oklch(0.165 0.008 80);\n --ft-panel: oklch(0.21 0.008 80);\n --ft-panel-2: oklch(0.25 0.01 80);\n --ft-fg: oklch(0.96 0.005 85);\n --ft-muted-fg: oklch(0.68 0.008 80);\n --ft-dim-fg: oklch(0.5 0.008 80);\n --ft-line: oklch(0.28 0.008 80);\n --ft-line-strong: oklch(0.4 0.008 80);\n --ft-grid-strong: oklch(0.24 0.008 80);\n --ft-tier-orange: #f16c25;\n --ft-tier-teal: #5fb7b8;\n --ft-tier-blue: oklch(0.72 0.12 240);\n --ft-tier-amber: oklch(0.8 0.14 75);\n --ft-tier-green: oklch(0.74 0.14 155);\n --ft-accent: var(--ft-tier-orange);\n --ft-serif: \"Instrument Serif\", Georgia, serif;\n --ft-sans: \"Inter\", system-ui, sans-serif;\n --ft-mono: \"JetBrains Mono\", ui-monospace, Menlo, monospace;\n\n /* Defensive shell sizing \u2014 fills flex parents (flex: 1) and block\n parents with definite dimensions (width/height: 100%). */\n flex: 1 1 auto;\n width: 100%;\n height: 100%;\n min-height: 420px;\n display: flex;\n flex-direction: column;\n background: var(--ft-bg);\n border: 1px solid var(--ft-line);\n border-radius: 2px;\n overflow: hidden;\n color: var(--ft-fg);\n font-family: var(--ft-sans);\n font-size: 14px;\n line-height: 1.5;\n -webkit-font-smoothing: antialiased;\n box-shadow: 0 30px 60px -30px oklch(0 0 0 / 0.5);\n}\n.ft-shell * { box-sizing: border-box; }\n.ft-shell .ft-mono {\n font-family: var(--ft-mono);\n font-size: 11px;\n letter-spacing: 0.02em;\n}\n\n.ft-header {\n padding: 22px 28px 20px;\n border-bottom: 1px solid var(--ft-line);\n background: linear-gradient(180deg, oklch(0.21 0.01 60) 0%, oklch(0.19 0.008 70) 100%);\n display: flex;\n flex-direction: column;\n gap: 6px;\n}\n.ft-header__eyebrow {\n font-family: var(--ft-mono);\n font-size: 10.5px;\n letter-spacing: 0.22em;\n text-transform: uppercase;\n color: var(--ft-tier-orange);\n}\n.ft-header__title {\n margin: 0;\n font-family: var(--ft-serif);\n font-weight: 400;\n font-size: 44px;\n line-height: 1;\n letter-spacing: -0.015em;\n color: var(--ft-fg);\n}\n.ft-header__tagline {\n margin: 6px 0 0;\n max-width: 76ch;\n color: var(--ft-muted-fg);\n font-size: 13px;\n}\n\n.ft-stage {\n position: relative;\n flex: 1;\n min-height: 0;\n overflow: hidden;\n background:\n radial-gradient(1200px 700px at 15% -10%, oklch(0.22 0.012 60), transparent 60%),\n radial-gradient(900px 600px at 110% 110%, oklch(0.2 0.02 200 / 0.5), transparent 65%);\n}\n\n.ft-svg {\n display: block;\n width: 100%;\n height: 100%;\n background: transparent;\n cursor: grab;\n touch-action: none;\n user-select: none;\n}\n.ft-svg.is-dragging { cursor: grabbing; }\n\n.ft-controls {\n position: absolute;\n top: 14px;\n right: 14px;\n z-index: 5;\n display: flex;\n align-items: center;\n gap: 6px;\n background: oklch(0.2 0.008 80 / 0.94);\n border: 1px solid var(--ft-line-strong);\n padding: 5px 8px;\n backdrop-filter: blur(8px);\n border-radius: 2px;\n}\n.ft-controls button {\n font-family: var(--ft-mono);\n font-size: 12px;\n width: 26px;\n height: 26px;\n background: transparent;\n border: 1px solid var(--ft-line);\n color: var(--ft-fg);\n cursor: pointer;\n padding: 0;\n}\n.ft-controls button:hover { border-color: var(--ft-tier-orange); }\n.ft-controls__reset {\n width: auto !important;\n padding: 0 10px !important;\n font-size: 9.5px !important;\n letter-spacing: 0.1em;\n text-transform: uppercase;\n}\n.ft-controls__hint {\n font-family: var(--ft-mono);\n font-size: 9.5px;\n color: var(--ft-muted-fg);\n letter-spacing: 0.04em;\n padding-left: 8px;\n margin-left: 2px;\n border-left: 1px solid var(--ft-line);\n}\n\n.ft-legend {\n position: absolute;\n left: 18px;\n bottom: 14px;\n z-index: 5;\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: 6px;\n font-family: var(--ft-mono);\n font-size: 10px;\n color: var(--ft-muted-fg);\n background: oklch(0.2 0.008 80 / 0.88);\n border: 1px solid var(--ft-line);\n padding: 6px 10px;\n backdrop-filter: blur(6px);\n max-width: calc(100% - 220px);\n}\n.ft-legend__chip {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 2px 6px;\n margin: -2px 0;\n background: transparent;\n border: none;\n color: inherit;\n font: inherit;\n letter-spacing: inherit;\n cursor: pointer;\n border-radius: 2px;\n transition: background 120ms, color 120ms;\n}\n.ft-legend__chip:hover {\n background: oklch(0.24 0.01 80);\n color: var(--ft-fg);\n}\n.ft-legend__chip:disabled {\n cursor: default;\n color: var(--ft-fg);\n}\n.ft-legend__chip:disabled:hover { background: transparent; }\n.ft-legend__dot {\n width: 5px;\n height: 5px;\n border-radius: 50%;\n background: var(--ft-tier-orange);\n flex-shrink: 0;\n}\n.ft-legend__sep {\n color: var(--ft-line-strong);\n margin: 0 2px;\n pointer-events: none;\n user-select: none;\n}\n\n/* edges */\n.ft-edge {\n fill: none;\n /* Keep stroke widths crisp under the SVG <g scale(z)> pan/zoom transform.\n Without this, fit-to-viewport (z \u2248 0.6-0.9) renders 1.6px strokes as\n sub-pixel and they visually disappear. */\n vector-effect: non-scaling-stroke;\n transition: stroke 260ms, opacity 260ms;\n}\n.ft-edge--off { stroke: var(--ft-line); stroke-width: 1; opacity: 0.55; }\n.ft-edge--on {\n stroke: var(--ft-tier-orange);\n /* Verbatim restore of the reference design (local-docs/styles.css\n line 133-140). The 4px dash + 5px gap reads as continuous\n marching-ant flow \u2014 every frame, dash edges visibly sweep across\n the path because the gap (5px) is shorter than the dash itself.\n This is what gives the focused branches their \"alive\" feel; the\n wider gap variants (1/12 in 1.30.1, 0.1/9 in 1.30.0) read as\n isolated dots and look static at typical fit-zoom levels. */\n stroke-width: 1.6;\n stroke-dasharray: 4 5;\n opacity: 1;\n animation: ftDashFlow 1.4s linear infinite;\n /* Visibility-under-zoom fix from 1.29.1 \u2014 without this, fit-zoom\n transforms (z \u2248 0.4-0.7) render the 1.6px stroke as sub-pixel\n and the line becomes invisible. Keeps stroke-width and\n dasharray in screen pixels regardless of the SVG transform.\n Not in the reference because the reference demo runs at z=1. */\n vector-effect: non-scaling-stroke;\n}\n@keyframes ftDashFlow {\n /* -36 == 4 \u00D7 (4+5) so the pattern advances exactly four cycles\n per period at 1.4s \u2014 perceptibly fast flow without strobing. */\n to { stroke-dashoffset: -36; }\n}\n@media (prefers-reduced-motion: reduce) {\n /* a11y improvement not in the reference \u2014 users who suppress\n motion get a clean solid line instead of a static frozen dash. */\n .ft-edge--on {\n animation: none;\n stroke-dasharray: none;\n }\n}\n\n/* card */\n.ft-card {\n --tier-local: var(--tier, var(--ft-line-strong));\n width: 100%;\n height: 100%;\n display: grid;\n grid-template-columns: 1fr auto;\n gap: 0;\n align-items: stretch;\n background: oklch(0.21 0.008 80);\n border: 1px solid var(--ft-line);\n border-left: 3px solid var(--tier-local);\n border-radius: 2px;\n transition:\n background 260ms cubic-bezier(.2,.8,.2,1),\n border-color 260ms, box-shadow 260ms,\n transform 260ms cubic-bezier(.2,.8,.2,1),\n filter 260ms, opacity 260ms, color 260ms;\n overflow: visible;\n animation: ftCardIn 320ms cubic-bezier(.2,.8,.2,1) backwards;\n}\n@keyframes ftCardIn {\n from { opacity: 0; transform: translateX(-6px); }\n to { opacity: 1; transform: translateX(0); }\n}\n.ft-card__main {\n display: grid;\n grid-template-columns: auto 1fr auto;\n gap: 10px;\n align-items: center;\n padding: 0 10px 0 12px;\n background: transparent;\n border: none;\n color: inherit;\n font-family: var(--ft-sans);\n font-size: 13px;\n text-align: left;\n cursor: pointer;\n min-width: 0;\n}\n.ft-card__main:hover { background: oklch(0.23 0.01 80 / 0.6); }\n.ft-card__icon {\n width: 24px;\n height: 24px;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n color: var(--tier-local);\n border: 1px solid var(--ft-line-strong);\n background: oklch(0.17 0.008 80);\n flex-shrink: 0;\n}\n.ft-card__body { display: flex; flex-direction: column; min-width: 0; gap: 1px; }\n.ft-card__label {\n font-family: var(--ft-serif);\n font-size: 15px;\n line-height: 1.15;\n color: var(--ft-fg);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n display: flex;\n align-items: center;\n gap: 5px;\n}\n.ft-card__sub {\n font-family: var(--ft-mono);\n font-size: 9.5px;\n letter-spacing: 0.02em;\n color: var(--ft-muted-fg);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n.ft-card__lock { color: var(--ft-muted-fg); display: inline-flex; }\n.ft-card__caret {\n width: 18px;\n height: 18px;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n font-family: var(--ft-mono);\n font-size: 12px;\n color: var(--ft-muted-fg);\n border: 1px solid var(--ft-line);\n}\n.ft-card--active .ft-card__caret {\n color: var(--tier-local);\n border-color: var(--tier-local);\n}\n\n.ft-card__rail {\n display: flex;\n flex-direction: column;\n border-left: 1px solid var(--ft-line);\n background: oklch(0.19 0.008 80);\n}\n.ft-card__mini {\n flex: 1;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 28px;\n min-height: 20px;\n background: transparent;\n border: none;\n color: var(--ft-muted-fg);\n cursor: pointer;\n transition: background 150ms, color 150ms;\n border-bottom: 1px solid var(--ft-line);\n padding: 0;\n text-decoration: none;\n}\n.ft-card__mini:last-child { border-bottom: none; }\n.ft-card__mini:hover { background: oklch(0.23 0.01 80); color: var(--tier-local); }\n.ft-card__mini.is-on { color: var(--tier-local); background: oklch(0.23 0.01 80); }\n\n/* states */\n.ft-card--active {\n background: oklch(0.25 0.015 60);\n box-shadow: 0 0 0 1px var(--tier-local), 0 14px 34px -16px oklch(0.5 0.18 50 / 0.55);\n transform: scale(1.02);\n}\n.ft-card--dim {\n filter: grayscale(0.85) brightness(0.82);\n opacity: 0.7;\n transform: scale(0.88);\n transform-origin: center left;\n}\n.ft-card--dim .ft-card__label { color: var(--ft-dim-fg); }\n.ft-card--dim:hover {\n filter: grayscale(0.3) brightness(0.96);\n opacity: 1;\n transform: scale(0.94);\n}\n.ft-card--cta {\n border-left-color: var(--ft-tier-orange);\n background: linear-gradient(180deg, oklch(0.23 0.02 55) 0%, oklch(0.2 0.015 60) 100%);\n}\n.ft-card--root {\n border-left-color: var(--ft-tier-orange);\n background: oklch(0.26 0.015 55);\n}\n.ft-card--root .ft-card__icon {\n color: var(--ft-tier-orange);\n border-color: var(--ft-tier-orange);\n}\n\n/* detail pop */\n.ft-detail {\n position: relative;\n margin-top: 0;\n padding: 16px 18px 14px;\n background: oklch(0.16 0.008 80);\n border: 1px solid var(--ft-line-strong);\n border-left: 2px solid var(--ft-tier-orange);\n border-radius: 3px;\n animation: ftDetailIn 220ms cubic-bezier(.2,.8,.2,1) backwards;\n color: var(--ft-fg);\n width: 320px;\n box-shadow: 0 18px 40px -8px rgba(0,0,0,0.6), 0 2px 8px rgba(0,0,0,0.4);\n}\n.ft-detail__head {\n display: flex;\n align-items: center;\n /* Clear room for the two stacked rail buttons in the top-right\n (expand + close). Bumped from 28px \u2192 58px to fit both. */\n margin: -2px 58px 10px 0;\n}\n.ft-detail__title {\n font-family: var(--ft-mono);\n font-size: 10px;\n letter-spacing: 0.14em;\n text-transform: uppercase;\n color: var(--ft-muted-fg);\n}\n.ft-detail__close,\n.ft-detail__expand {\n position: absolute;\n top: 8px;\n width: 22px;\n height: 22px;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n background: transparent;\n border: 1px solid var(--ft-line);\n border-radius: 2px;\n color: var(--ft-muted-fg);\n cursor: pointer;\n padding: 0;\n transition: color 120ms, border-color 120ms, background 120ms;\n}\n.ft-detail__close { right: 8px; }\n/* Expand button sits immediately to the left of close. */\n.ft-detail__expand { right: 36px; }\n.ft-detail__close:hover,\n.ft-detail__expand:hover {\n color: var(--ft-fg);\n border-color: var(--ft-tier-orange);\n background: oklch(0.22 0.008 80);\n}\n@keyframes ftDetailIn {\n from { opacity: 0; transform: translateY(-4px); }\n to { opacity: 1; transform: translateY(0); }\n}\n.ft-detail__lead {\n /* Inter (sans) at slightly larger size + medium weight reads\n dramatically better than serif italic on dark stages, while still\n looking distinct from the body paragraph. The orange accent\n border on the left preserves the \"pull-quote\" rhythm. */\n font-family: var(--ft-sans);\n font-size: 14.5px;\n line-height: 1.45;\n font-style: normal;\n font-weight: 500;\n color: var(--ft-fg);\n padding-left: 10px;\n border-left: 2px solid var(--ft-tier-orange);\n margin-bottom: 12px;\n}\n.ft-detail__body {\n margin: 0 0 10px;\n font-size: 12px;\n color: var(--ft-muted-fg);\n line-height: 1.5;\n}\n.ft-detail__bullets {\n margin: 0 0 10px;\n padding-left: 16px;\n font-size: 12px;\n color: var(--ft-fg);\n}\n.ft-detail__bullets li { margin-bottom: 3px; }\n.ft-detail__meta {\n margin: 0 0 10px;\n padding: 0;\n display: flex;\n flex-direction: column;\n gap: 4px;\n}\n.ft-detail__meta-row {\n display: grid;\n grid-template-columns: 96px 1fr;\n gap: 8px;\n font-size: 11px;\n}\n.ft-detail__meta-row dt {\n font-family: var(--ft-mono);\n font-size: 9.5px;\n letter-spacing: 0.1em;\n text-transform: uppercase;\n color: var(--ft-muted-fg);\n padding-top: 1px;\n}\n.ft-detail__meta-row dd { margin: 0; color: var(--ft-fg); }\n.ft-detail__actions {\n display: flex;\n gap: 6px;\n flex-wrap: wrap;\n margin-top: 8px;\n}\n\n.ft-btn {\n font-family: var(--ft-mono);\n font-size: 10px;\n letter-spacing: 0.1em;\n text-transform: uppercase;\n padding: 7px 10px;\n background: transparent;\n color: var(--ft-fg);\n border: 1px solid var(--ft-line-strong);\n text-decoration: none;\n cursor: pointer;\n display: inline-flex;\n gap: 5px;\n align-items: center;\n transition: border-color 150ms, background 150ms;\n}\n.ft-btn:hover { border-color: var(--ft-tier-orange); }\n.ft-btn--primary {\n background: var(--ft-tier-orange);\n color: oklch(0.18 0.01 50);\n border-color: var(--ft-tier-orange);\n}\n\n@media (max-width: 760px) {\n .ft-header { padding: 16px 18px 14px; }\n .ft-header__title { font-size: 32px; }\n .ft-controls__hint { display: none; }\n .ft-legend { max-width: calc(100% - 24px); left: 10px; bottom: 10px; }\n /* Larger touch targets on phones \u2014 bumps zoom controls from 26px\n to 36px to comfortably clear the 44px Apple HIG / Material 48dp\n minimum once you account for visual padding. */\n .ft-controls { padding: 6px 8px; }\n .ft-controls button { width: 36px; height: 36px; font-size: 16px; }\n .ft-controls__reset { padding: 0 14px !important; height: 36px; }\n /* Inline detail popup buttons are intentionally compact in the\n inline footprint \u2014 but on touch the user can promote to the\n fullscreen overlay which has 28px buttons by default. */\n .ft-detail__close, .ft-detail__expand { width: 28px; height: 28px; }\n .ft-detail__expand { right: 42px; }\n .ft-detail__head { margin-right: 70px; }\n}\n@media (max-width: 480px) {\n /* Phone-sized: shrink card width so 5+ depth levels still fit\n reasonably without forcing the user to scroll horizontally to\n read the labels. Cards still ellipsis-truncate when needed. */\n .ft-card { font-size: 12px; }\n .ft-card__label { font-size: 14px; }\n .ft-card__sub { font-size: 9px; }\n .ft-controls__hint { display: none; }\n}\n\n/* \u2500\u2500\u2500 Fullscreen detail overlay \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n Triggered by the expand button in any inline DetailPop. Renders\n inside .ft-stage as an absolutely-positioned scrim + scrollable\n panel. The inline pop stays mounted (cheaper React tree) but the\n user's focus and the pointer-events both transfer to the overlay\n while it's visible.\n*/\n.ft-detail-overlay {\n position: absolute;\n inset: 0;\n z-index: 20;\n display: flex;\n align-items: stretch;\n justify-content: center;\n /* Translucent backdrop blurs the flow tree behind so the focused\n content reads cleanly without losing the user's \"where am I\"\n spatial anchor. */\n background: oklch(0.12 0.008 80 / 0.78);\n backdrop-filter: blur(6px);\n animation: ftOverlayIn 200ms cubic-bezier(.2,.8,.2,1);\n}\n@keyframes ftOverlayIn {\n from { opacity: 0; }\n to { opacity: 1; }\n}\n.ft-detail-overlay__panel {\n position: relative;\n margin: 36px;\n flex: 1 1 auto;\n max-width: 760px;\n background: oklch(0.18 0.008 80);\n border: 1px solid var(--ft-line-strong);\n border-left: 3px solid var(--ft-tier-orange);\n border-radius: 4px;\n overflow: auto;\n padding: 26px 32px 28px;\n box-shadow: 0 30px 80px -10px oklch(0 0 0 / 0.7);\n animation: ftOverlayPanelIn 240ms cubic-bezier(.2,.8,.2,1);\n}\n@keyframes ftOverlayPanelIn {\n from { opacity: 0; transform: translateY(8px); }\n to { opacity: 1; transform: translateY(0); }\n}\n.ft-detail-overlay__panel .ft-detail__title {\n font-size: 11px;\n}\n.ft-detail-overlay__panel .ft-detail__lead {\n font-size: 18px;\n line-height: 1.5;\n padding-left: 14px;\n}\n.ft-detail-overlay__panel .ft-detail__body {\n font-size: 14px;\n color: var(--ft-fg);\n line-height: 1.65;\n}\n.ft-detail-overlay__panel .ft-detail__bullets {\n font-size: 14px;\n line-height: 1.55;\n padding-left: 20px;\n}\n.ft-detail-overlay__panel .ft-detail__bullets li { margin-bottom: 6px; }\n.ft-detail-overlay__panel .ft-detail__meta-row {\n font-size: 13px;\n grid-template-columns: 140px 1fr;\n}\n.ft-detail-overlay__panel .ft-detail__meta-row dt { font-size: 10.5px; }\n.ft-detail-overlay__panel .ft-btn { font-size: 11px; padding: 9px 14px; }\n.ft-detail-overlay__head {\n display: flex;\n align-items: center;\n margin: 0 0 14px;\n padding-right: 70px;\n}\n.ft-detail-overlay__title {\n font-family: var(--ft-mono);\n font-size: 11px;\n letter-spacing: 0.18em;\n text-transform: uppercase;\n color: var(--ft-tier-orange);\n}\n.ft-detail-overlay__close,\n.ft-detail-overlay__collapse {\n position: absolute;\n top: 16px;\n width: 28px;\n height: 28px;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n background: transparent;\n border: 1px solid var(--ft-line-strong);\n border-radius: 2px;\n color: var(--ft-fg);\n cursor: pointer;\n padding: 0;\n transition: color 120ms, border-color 120ms, background 120ms;\n}\n.ft-detail-overlay__close { right: 16px; }\n.ft-detail-overlay__collapse { right: 52px; }\n.ft-detail-overlay__close:hover,\n.ft-detail-overlay__collapse:hover {\n color: var(--ft-tier-orange);\n border-color: var(--ft-tier-orange);\n background: oklch(0.22 0.008 80);\n}\n\n@media (max-width: 760px) {\n .ft-detail-overlay__panel {\n margin: 12px;\n padding: 18px 18px 22px;\n }\n .ft-detail-overlay__panel .ft-detail__lead { font-size: 16px; }\n}\n";
5296
+ declare const FLOW_TREE_CSS = "\n@import url(\"https://fonts.googleapis.com/css2?family=Instrument+Serif:ital@0;1&family=Inter:wght@400;500;600&family=JetBrains+Mono:wght@400;500&display=swap\");\n\n.ft-shell {\n --ft-bg: oklch(0.165 0.008 80);\n --ft-panel: oklch(0.21 0.008 80);\n --ft-panel-2: oklch(0.25 0.01 80);\n --ft-fg: oklch(0.96 0.005 85);\n --ft-muted-fg: oklch(0.68 0.008 80);\n --ft-dim-fg: oklch(0.5 0.008 80);\n --ft-line: oklch(0.28 0.008 80);\n --ft-line-strong: oklch(0.4 0.008 80);\n --ft-grid-strong: oklch(0.24 0.008 80);\n --ft-tier-orange: #f16c25;\n --ft-tier-teal: #5fb7b8;\n --ft-tier-blue: oklch(0.72 0.12 240);\n --ft-tier-amber: oklch(0.8 0.14 75);\n --ft-tier-green: oklch(0.74 0.14 155);\n --ft-accent: var(--ft-tier-orange);\n --ft-serif: \"Instrument Serif\", Georgia, serif;\n --ft-sans: \"Inter\", system-ui, sans-serif;\n --ft-mono: \"JetBrains Mono\", ui-monospace, Menlo, monospace;\n\n /* Defensive shell sizing \u2014 fills flex parents (flex: 1) and block\n parents with definite dimensions (width/height: 100%). */\n flex: 1 1 auto;\n width: 100%;\n height: 100%;\n min-height: 420px;\n display: flex;\n flex-direction: column;\n background: var(--ft-bg);\n border: 1px solid var(--ft-line);\n border-radius: 2px;\n overflow: hidden;\n color: var(--ft-fg);\n font-family: var(--ft-sans);\n font-size: 14px;\n line-height: 1.5;\n -webkit-font-smoothing: antialiased;\n box-shadow: 0 30px 60px -30px oklch(0 0 0 / 0.5);\n}\n.ft-shell * { box-sizing: border-box; }\n.ft-shell .ft-mono {\n font-family: var(--ft-mono);\n font-size: 11px;\n letter-spacing: 0.02em;\n}\n\n.ft-header {\n padding: 22px 28px 20px;\n border-bottom: 1px solid var(--ft-line);\n background: linear-gradient(180deg, oklch(0.21 0.01 60) 0%, oklch(0.19 0.008 70) 100%);\n display: flex;\n flex-direction: column;\n gap: 6px;\n}\n.ft-header__eyebrow {\n font-family: var(--ft-mono);\n font-size: 10.5px;\n letter-spacing: 0.22em;\n text-transform: uppercase;\n color: var(--ft-tier-orange);\n}\n.ft-header__title {\n margin: 0;\n font-family: var(--ft-serif);\n font-weight: 400;\n font-size: 44px;\n line-height: 1;\n letter-spacing: -0.015em;\n color: var(--ft-fg);\n}\n.ft-header__tagline {\n margin: 6px 0 0;\n max-width: 76ch;\n color: var(--ft-muted-fg);\n font-size: 13px;\n}\n\n.ft-stage {\n position: relative;\n flex: 1;\n min-height: 0;\n overflow: hidden;\n background:\n radial-gradient(1200px 700px at 15% -10%, oklch(0.22 0.012 60), transparent 60%),\n radial-gradient(900px 600px at 110% 110%, oklch(0.2 0.02 200 / 0.5), transparent 65%);\n}\n\n.ft-svg {\n display: block;\n width: 100%;\n height: 100%;\n background: transparent;\n cursor: grab;\n touch-action: none;\n user-select: none;\n}\n.ft-svg.is-dragging { cursor: grabbing; }\n\n.ft-controls {\n position: absolute;\n top: 14px;\n right: 14px;\n z-index: 5;\n display: flex;\n align-items: center;\n gap: 6px;\n background: oklch(0.2 0.008 80 / 0.94);\n border: 1px solid var(--ft-line-strong);\n padding: 5px 8px;\n backdrop-filter: blur(8px);\n border-radius: 2px;\n}\n.ft-controls button {\n font-family: var(--ft-mono);\n font-size: 12px;\n width: 26px;\n height: 26px;\n background: transparent;\n border: 1px solid var(--ft-line);\n color: var(--ft-fg);\n cursor: pointer;\n padding: 0;\n}\n.ft-controls button:hover { border-color: var(--ft-tier-orange); }\n.ft-controls__reset {\n width: auto !important;\n padding: 0 10px !important;\n font-size: 9.5px !important;\n letter-spacing: 0.1em;\n text-transform: uppercase;\n}\n.ft-controls__hint {\n font-family: var(--ft-mono);\n font-size: 9.5px;\n color: var(--ft-muted-fg);\n letter-spacing: 0.04em;\n padding-left: 8px;\n margin-left: 2px;\n border-left: 1px solid var(--ft-line);\n}\n\n.ft-legend {\n position: absolute;\n left: 18px;\n bottom: 14px;\n z-index: 5;\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: 6px;\n font-family: var(--ft-mono);\n font-size: 10px;\n color: var(--ft-muted-fg);\n background: oklch(0.2 0.008 80 / 0.88);\n border: 1px solid var(--ft-line);\n padding: 6px 10px;\n backdrop-filter: blur(6px);\n max-width: calc(100% - 220px);\n}\n.ft-legend__chip {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 2px 6px;\n margin: -2px 0;\n background: transparent;\n border: none;\n color: inherit;\n font: inherit;\n letter-spacing: inherit;\n cursor: pointer;\n border-radius: 2px;\n transition: background 120ms, color 120ms;\n}\n.ft-legend__chip:hover {\n background: oklch(0.24 0.01 80);\n color: var(--ft-fg);\n}\n.ft-legend__chip:disabled {\n cursor: default;\n color: var(--ft-fg);\n}\n.ft-legend__chip:disabled:hover { background: transparent; }\n.ft-legend__dot {\n width: 5px;\n height: 5px;\n border-radius: 50%;\n background: var(--ft-tier-orange);\n flex-shrink: 0;\n}\n.ft-legend__sep {\n color: var(--ft-line-strong);\n margin: 0 2px;\n pointer-events: none;\n user-select: none;\n}\n\n/* edges */\n.ft-edge {\n fill: none;\n /* Keep stroke widths crisp under the SVG <g scale(z)> pan/zoom transform.\n Without this, fit-to-viewport (z \u2248 0.6-0.9) renders 1.6px strokes as\n sub-pixel and they visually disappear. */\n vector-effect: non-scaling-stroke;\n transition: stroke 260ms, opacity 260ms;\n}\n.ft-edge--off { stroke: var(--ft-line); stroke-width: 1; opacity: 0.55; }\n.ft-edge--on {\n stroke: var(--ft-tier-orange);\n /* Verbatim restore of the reference design (local-docs/styles.css\n line 133-140). The 4px dash + 5px gap reads as continuous\n marching-ant flow \u2014 every frame, dash edges visibly sweep across\n the path because the gap (5px) is shorter than the dash itself.\n This is what gives the focused branches their \"alive\" feel; the\n wider gap variants (1/12 in 1.30.1, 0.1/9 in 1.30.0) read as\n isolated dots and look static at typical fit-zoom levels. */\n stroke-width: 1.6;\n stroke-dasharray: 4 5;\n opacity: 1;\n animation: ftDashFlow 1.4s linear infinite;\n /* Visibility-under-zoom fix from 1.29.1 \u2014 without this, fit-zoom\n transforms (z \u2248 0.4-0.7) render the 1.6px stroke as sub-pixel\n and the line becomes invisible. Keeps stroke-width and\n dasharray in screen pixels regardless of the SVG transform.\n Not in the reference because the reference demo runs at z=1. */\n vector-effect: non-scaling-stroke;\n}\n@keyframes ftDashFlow {\n /* -36 == 4 \u00D7 (4+5) so the pattern advances exactly four cycles\n per period at 1.4s \u2014 perceptibly fast flow without strobing. */\n to { stroke-dashoffset: -36; }\n}\n@media (prefers-reduced-motion: reduce) {\n /* a11y improvement not in the reference \u2014 users who suppress motion\n get the marching dashes frozen in place. The 4/5 dash pattern is\n fully readable without animation (it still reads as a directional\n \"this connects\" cue), so we keep the dasharray and only stop the\n animation. 1.30.1 dropped the dasharray entirely here, which\n silently regressed the reduced-motion path to look like a plain\n solid orange line \u2014 the s182 fix restores dash visibility. */\n .ft-edge--on {\n animation: none;\n }\n}\n\n/* card */\n.ft-card {\n --tier-local: var(--tier, var(--ft-line-strong));\n width: 100%;\n height: 100%;\n display: grid;\n grid-template-columns: 1fr auto;\n gap: 0;\n align-items: stretch;\n background: oklch(0.21 0.008 80);\n border: 1px solid var(--ft-line);\n border-left: 3px solid var(--tier-local);\n border-radius: 2px;\n transition:\n background 260ms cubic-bezier(.2,.8,.2,1),\n border-color 260ms, box-shadow 260ms,\n transform 260ms cubic-bezier(.2,.8,.2,1),\n filter 260ms, opacity 260ms, color 260ms;\n overflow: visible;\n animation: ftCardIn 320ms cubic-bezier(.2,.8,.2,1) backwards;\n}\n@keyframes ftCardIn {\n from { opacity: 0; transform: translateX(-6px); }\n to { opacity: 1; transform: translateX(0); }\n}\n.ft-card__main {\n display: grid;\n grid-template-columns: auto 1fr auto;\n gap: 10px;\n align-items: center;\n padding: 0 10px 0 12px;\n background: transparent;\n border: none;\n color: inherit;\n font-family: var(--ft-sans);\n font-size: 13px;\n text-align: left;\n cursor: pointer;\n min-width: 0;\n}\n.ft-card__main:hover { background: oklch(0.23 0.01 80 / 0.6); }\n.ft-card__icon {\n width: 24px;\n height: 24px;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n color: var(--tier-local);\n border: 1px solid var(--ft-line-strong);\n background: oklch(0.17 0.008 80);\n flex-shrink: 0;\n}\n.ft-card__body { display: flex; flex-direction: column; min-width: 0; gap: 1px; }\n.ft-card__label {\n font-family: var(--ft-serif);\n font-size: 15px;\n line-height: 1.15;\n color: var(--ft-fg);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n display: flex;\n align-items: center;\n gap: 5px;\n}\n.ft-card__sub {\n font-family: var(--ft-mono);\n font-size: 9.5px;\n letter-spacing: 0.02em;\n color: var(--ft-muted-fg);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n.ft-card__lock { color: var(--ft-muted-fg); display: inline-flex; }\n.ft-card__caret {\n width: 18px;\n height: 18px;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n font-family: var(--ft-mono);\n font-size: 12px;\n color: var(--ft-muted-fg);\n border: 1px solid var(--ft-line);\n}\n.ft-card--active .ft-card__caret {\n color: var(--tier-local);\n border-color: var(--tier-local);\n}\n\n.ft-card__rail {\n display: flex;\n flex-direction: column;\n border-left: 1px solid var(--ft-line);\n background: oklch(0.19 0.008 80);\n}\n.ft-card__mini {\n flex: 1;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 28px;\n min-height: 20px;\n background: transparent;\n border: none;\n color: var(--ft-muted-fg);\n cursor: pointer;\n transition: background 150ms, color 150ms;\n border-bottom: 1px solid var(--ft-line);\n padding: 0;\n text-decoration: none;\n}\n.ft-card__mini:last-child { border-bottom: none; }\n.ft-card__mini:hover { background: oklch(0.23 0.01 80); color: var(--tier-local); }\n.ft-card__mini.is-on { color: var(--tier-local); background: oklch(0.23 0.01 80); }\n\n/* states */\n.ft-card--active {\n background: oklch(0.25 0.015 60);\n box-shadow: 0 0 0 1px var(--tier-local), 0 14px 34px -16px oklch(0.5 0.18 50 / 0.55);\n transform: scale(1.02);\n}\n.ft-card--dim {\n filter: grayscale(0.85) brightness(0.82);\n opacity: 0.7;\n transform: scale(0.88);\n transform-origin: center left;\n}\n.ft-card--dim .ft-card__label { color: var(--ft-dim-fg); }\n.ft-card--dim:hover {\n filter: grayscale(0.3) brightness(0.96);\n opacity: 1;\n transform: scale(0.94);\n}\n.ft-card--cta {\n border-left-color: var(--ft-tier-orange);\n background: linear-gradient(180deg, oklch(0.23 0.02 55) 0%, oklch(0.2 0.015 60) 100%);\n}\n.ft-card--root {\n border-left-color: var(--ft-tier-orange);\n background: oklch(0.26 0.015 55);\n}\n.ft-card--root .ft-card__icon {\n color: var(--ft-tier-orange);\n border-color: var(--ft-tier-orange);\n}\n\n/* detail pop */\n.ft-detail {\n position: relative;\n margin-top: 0;\n padding: 16px 18px 14px;\n background: oklch(0.16 0.008 80);\n border: 1px solid var(--ft-line-strong);\n border-left: 2px solid var(--ft-tier-orange);\n border-radius: 3px;\n animation: ftDetailIn 220ms cubic-bezier(.2,.8,.2,1) backwards;\n color: var(--ft-fg);\n width: 320px;\n box-shadow: 0 18px 40px -8px rgba(0,0,0,0.6), 0 2px 8px rgba(0,0,0,0.4);\n}\n.ft-detail__head {\n display: flex;\n align-items: center;\n /* Clear room for the two stacked rail buttons in the top-right\n (expand + close). Bumped from 28px \u2192 58px to fit both. */\n margin: -2px 58px 10px 0;\n}\n.ft-detail__title {\n font-family: var(--ft-mono);\n font-size: 10px;\n letter-spacing: 0.14em;\n text-transform: uppercase;\n color: var(--ft-muted-fg);\n}\n.ft-detail__close,\n.ft-detail__expand {\n position: absolute;\n top: 8px;\n width: 22px;\n height: 22px;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n background: transparent;\n border: 1px solid var(--ft-line);\n border-radius: 2px;\n color: var(--ft-muted-fg);\n cursor: pointer;\n padding: 0;\n transition: color 120ms, border-color 120ms, background 120ms;\n}\n.ft-detail__close { right: 8px; }\n/* Expand button sits immediately to the left of close. */\n.ft-detail__expand { right: 36px; }\n.ft-detail__close:hover,\n.ft-detail__expand:hover {\n color: var(--ft-fg);\n border-color: var(--ft-tier-orange);\n background: oklch(0.22 0.008 80);\n}\n@keyframes ftDetailIn {\n from { opacity: 0; transform: translateY(-4px); }\n to { opacity: 1; transform: translateY(0); }\n}\n.ft-detail__lead {\n /* Inter (sans) at slightly larger size + medium weight reads\n dramatically better than serif italic on dark stages, while still\n looking distinct from the body paragraph. The orange accent\n border on the left preserves the \"pull-quote\" rhythm. */\n font-family: var(--ft-sans);\n font-size: 14.5px;\n line-height: 1.45;\n font-style: normal;\n font-weight: 500;\n color: var(--ft-fg);\n padding-left: 10px;\n border-left: 2px solid var(--ft-tier-orange);\n margin-bottom: 12px;\n}\n.ft-detail__body {\n margin: 0 0 10px;\n font-size: 12px;\n color: var(--ft-muted-fg);\n line-height: 1.5;\n}\n.ft-detail__bullets {\n margin: 0 0 10px;\n padding-left: 16px;\n font-size: 12px;\n color: var(--ft-fg);\n}\n.ft-detail__bullets li { margin-bottom: 3px; }\n.ft-detail__meta {\n margin: 0 0 10px;\n padding: 0;\n display: flex;\n flex-direction: column;\n gap: 4px;\n}\n.ft-detail__meta-row {\n display: grid;\n grid-template-columns: 96px 1fr;\n gap: 8px;\n font-size: 11px;\n}\n.ft-detail__meta-row dt {\n font-family: var(--ft-mono);\n font-size: 9.5px;\n letter-spacing: 0.1em;\n text-transform: uppercase;\n color: var(--ft-muted-fg);\n padding-top: 1px;\n}\n.ft-detail__meta-row dd { margin: 0; color: var(--ft-fg); }\n.ft-detail__actions {\n display: flex;\n gap: 6px;\n flex-wrap: wrap;\n margin-top: 8px;\n}\n\n.ft-btn {\n font-family: var(--ft-mono);\n font-size: 10px;\n letter-spacing: 0.1em;\n text-transform: uppercase;\n padding: 7px 10px;\n background: transparent;\n color: var(--ft-fg);\n border: 1px solid var(--ft-line-strong);\n text-decoration: none;\n cursor: pointer;\n display: inline-flex;\n gap: 5px;\n align-items: center;\n transition: border-color 150ms, background 150ms;\n}\n.ft-btn:hover { border-color: var(--ft-tier-orange); }\n.ft-btn--primary {\n background: var(--ft-tier-orange);\n color: oklch(0.18 0.01 50);\n border-color: var(--ft-tier-orange);\n}\n\n@media (max-width: 760px) {\n .ft-header { padding: 16px 18px 14px; }\n .ft-header__title { font-size: 32px; }\n .ft-controls__hint { display: none; }\n .ft-legend { max-width: calc(100% - 24px); left: 10px; bottom: 10px; }\n /* Larger touch targets on phones \u2014 bumps zoom controls from 26px\n to 36px to comfortably clear the 44px Apple HIG / Material 48dp\n minimum once you account for visual padding. */\n .ft-controls { padding: 6px 8px; }\n .ft-controls button { width: 36px; height: 36px; font-size: 16px; }\n .ft-controls__reset { padding: 0 14px !important; height: 36px; }\n /* Inline detail popup buttons are intentionally compact in the\n inline footprint \u2014 but on touch the user can promote to the\n fullscreen overlay which has 28px buttons by default. */\n .ft-detail__close, .ft-detail__expand { width: 28px; height: 28px; }\n .ft-detail__expand { right: 42px; }\n .ft-detail__head { margin-right: 70px; }\n}\n@media (max-width: 480px) {\n /* Phone-sized: shrink card width so 5+ depth levels still fit\n reasonably without forcing the user to scroll horizontally to\n read the labels. Cards still ellipsis-truncate when needed. */\n .ft-card { font-size: 12px; }\n .ft-card__label { font-size: 14px; }\n .ft-card__sub { font-size: 9px; }\n .ft-controls__hint { display: none; }\n}\n\n/* \u2500\u2500\u2500 Fullscreen detail overlay \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n Triggered by the expand button in any inline DetailPop. Renders\n inside .ft-stage as an absolutely-positioned scrim + scrollable\n panel. The inline pop stays mounted (cheaper React tree) but the\n user's focus and the pointer-events both transfer to the overlay\n while it's visible.\n*/\n.ft-detail-overlay {\n position: absolute;\n inset: 0;\n z-index: 20;\n display: flex;\n align-items: stretch;\n justify-content: center;\n /* Translucent backdrop blurs the flow tree behind so the focused\n content reads cleanly without losing the user's \"where am I\"\n spatial anchor. */\n background: oklch(0.12 0.008 80 / 0.78);\n backdrop-filter: blur(6px);\n animation: ftOverlayIn 200ms cubic-bezier(.2,.8,.2,1);\n}\n@keyframes ftOverlayIn {\n from { opacity: 0; }\n to { opacity: 1; }\n}\n.ft-detail-overlay__panel {\n position: relative;\n margin: 36px;\n flex: 1 1 auto;\n max-width: 760px;\n background: oklch(0.18 0.008 80);\n border: 1px solid var(--ft-line-strong);\n border-left: 3px solid var(--ft-tier-orange);\n border-radius: 4px;\n overflow: auto;\n padding: 26px 32px 28px;\n box-shadow: 0 30px 80px -10px oklch(0 0 0 / 0.7);\n animation: ftOverlayPanelIn 240ms cubic-bezier(.2,.8,.2,1);\n}\n@keyframes ftOverlayPanelIn {\n from { opacity: 0; transform: translateY(8px); }\n to { opacity: 1; transform: translateY(0); }\n}\n.ft-detail-overlay__panel .ft-detail__title {\n font-size: 11px;\n}\n.ft-detail-overlay__panel .ft-detail__lead {\n font-size: 18px;\n line-height: 1.5;\n padding-left: 14px;\n}\n.ft-detail-overlay__panel .ft-detail__body {\n font-size: 14px;\n color: var(--ft-fg);\n line-height: 1.65;\n}\n.ft-detail-overlay__panel .ft-detail__bullets {\n font-size: 14px;\n line-height: 1.55;\n padding-left: 20px;\n}\n.ft-detail-overlay__panel .ft-detail__bullets li { margin-bottom: 6px; }\n.ft-detail-overlay__panel .ft-detail__meta-row {\n font-size: 13px;\n grid-template-columns: 140px 1fr;\n}\n.ft-detail-overlay__panel .ft-detail__meta-row dt { font-size: 10.5px; }\n.ft-detail-overlay__panel .ft-btn { font-size: 11px; padding: 9px 14px; }\n.ft-detail-overlay__head {\n display: flex;\n align-items: center;\n margin: 0 0 14px;\n padding-right: 70px;\n}\n.ft-detail-overlay__title {\n font-family: var(--ft-mono);\n font-size: 11px;\n letter-spacing: 0.18em;\n text-transform: uppercase;\n color: var(--ft-tier-orange);\n}\n.ft-detail-overlay__close,\n.ft-detail-overlay__collapse {\n position: absolute;\n top: 16px;\n width: 28px;\n height: 28px;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n background: transparent;\n border: 1px solid var(--ft-line-strong);\n border-radius: 2px;\n color: var(--ft-fg);\n cursor: pointer;\n padding: 0;\n transition: color 120ms, border-color 120ms, background 120ms;\n}\n.ft-detail-overlay__close { right: 16px; }\n.ft-detail-overlay__collapse { right: 52px; }\n.ft-detail-overlay__close:hover,\n.ft-detail-overlay__collapse:hover {\n color: var(--ft-tier-orange);\n border-color: var(--ft-tier-orange);\n background: oklch(0.22 0.008 80);\n}\n\n@media (max-width: 760px) {\n .ft-detail-overlay__panel {\n margin: 12px;\n padding: 18px 18px 22px;\n }\n .ft-detail-overlay__panel .ft-detail__lead { font-size: 16px; }\n}\n";
5297
5297
 
5298
5298
  type GameTimerMode = "countdown" | "countup";
5299
5299
  type GameTimerThemePreset = "green" | "red" | "blue" | "amber" | "purple" | "pink" | "teal";
package/dist/index.js CHANGED
@@ -36124,11 +36124,15 @@ var FLOW_TREE_CSS = `
36124
36124
  to { stroke-dashoffset: -36; }
36125
36125
  }
36126
36126
  @media (prefers-reduced-motion: reduce) {
36127
- /* a11y improvement not in the reference \u2014 users who suppress
36128
- motion get a clean solid line instead of a static frozen dash. */
36127
+ /* a11y improvement not in the reference \u2014 users who suppress motion
36128
+ get the marching dashes frozen in place. The 4/5 dash pattern is
36129
+ fully readable without animation (it still reads as a directional
36130
+ "this connects" cue), so we keep the dasharray and only stop the
36131
+ animation. 1.30.1 dropped the dasharray entirely here, which
36132
+ silently regressed the reduced-motion path to look like a plain
36133
+ solid orange line \u2014 the s182 fix restores dash visibility. */
36129
36134
  .ft-edge--on {
36130
36135
  animation: none;
36131
- stroke-dasharray: none;
36132
36136
  }
36133
36137
  }
36134
36138
 
@@ -36750,39 +36754,63 @@ function NodeIconSlot({
36750
36754
  }
36751
36755
  function DetailBody({
36752
36756
  node,
36753
- resolveHref
36757
+ resolveHref,
36758
+ onNodeOpen
36754
36759
  }) {
36755
36760
  const d = node.detail;
36756
36761
  if (!d) return null;
36762
+ const subtitleAsMeta = node.subtitle ? [{ k: "Path", v: node.subtitle }] : [];
36763
+ const metaRows = (() => {
36764
+ const fromDetail = d.meta ?? [];
36765
+ const merged = [...subtitleAsMeta, ...fromDetail];
36766
+ return merged.length > 0 ? merged : void 0;
36767
+ })();
36768
+ const linkAction = node.href ? {
36769
+ label: node.auth ? "Sign in & open" : "Open page",
36770
+ href: node.href,
36771
+ primary: true
36772
+ } : null;
36773
+ const allActions = [
36774
+ ...linkAction ? [linkAction] : [],
36775
+ ...d.actions ?? []
36776
+ ];
36757
36777
  return /* @__PURE__ */ (0, import_jsx_runtime120.jsxs)(import_jsx_runtime120.Fragment, { children: [
36758
36778
  d.lead ? /* @__PURE__ */ (0, import_jsx_runtime120.jsx)("div", { className: "ft-detail__lead", children: d.lead }) : null,
36759
36779
  d.body ? /* @__PURE__ */ (0, import_jsx_runtime120.jsx)("p", { className: "ft-detail__body", children: d.body }) : null,
36760
36780
  d.bullets ? /* @__PURE__ */ (0, import_jsx_runtime120.jsx)("ul", { className: "ft-detail__bullets", children: d.bullets.map((b, i) => /* @__PURE__ */ (0, import_jsx_runtime120.jsx)("li", { children: b }, i)) }) : null,
36761
- d.meta ? /* @__PURE__ */ (0, import_jsx_runtime120.jsx)("dl", { className: "ft-detail__meta", children: d.meta.map((m, i) => /* @__PURE__ */ (0, import_jsx_runtime120.jsxs)("div", { className: "ft-detail__meta-row", children: [
36781
+ metaRows ? /* @__PURE__ */ (0, import_jsx_runtime120.jsx)("dl", { className: "ft-detail__meta", children: metaRows.map((m, i) => /* @__PURE__ */ (0, import_jsx_runtime120.jsxs)("div", { className: "ft-detail__meta-row", children: [
36762
36782
  /* @__PURE__ */ (0, import_jsx_runtime120.jsx)("dt", { children: m.k }),
36763
36783
  /* @__PURE__ */ (0, import_jsx_runtime120.jsx)("dd", { children: m.v })
36764
36784
  ] }, i)) }) : null,
36765
- d.actions ? /* @__PURE__ */ (0, import_jsx_runtime120.jsx)("div", { className: "ft-detail__actions", children: d.actions.map((a, i) => /* @__PURE__ */ (0, import_jsx_runtime120.jsxs)(
36766
- "a",
36767
- {
36768
- className: `ft-btn ${a.primary ? "ft-btn--primary" : ""}`,
36769
- href: resolveHref(a.href),
36770
- target: "_blank",
36771
- rel: "noreferrer",
36772
- children: [
36773
- a.label,
36774
- " \u2192"
36775
- ]
36776
- },
36777
- i
36778
- )) }) : null
36785
+ allActions.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime120.jsx)("div", { className: "ft-detail__actions", children: allActions.map((a, i) => {
36786
+ const isAuto = linkAction !== null && i === 0;
36787
+ return /* @__PURE__ */ (0, import_jsx_runtime120.jsxs)(
36788
+ "a",
36789
+ {
36790
+ className: `ft-btn ${a.primary ? "ft-btn--primary" : ""}`,
36791
+ href: resolveHref(a.href),
36792
+ target: "_blank",
36793
+ rel: "noreferrer",
36794
+ onClick: isAuto && onNodeOpen ? (e) => {
36795
+ e.stopPropagation();
36796
+ onNodeOpen({ ...node, href: a.href });
36797
+ } : void 0,
36798
+ children: [
36799
+ a.label,
36800
+ " \u2192"
36801
+ ]
36802
+ },
36803
+ i
36804
+ );
36805
+ }) }) : null
36779
36806
  ] });
36780
36807
  }
36781
36808
  function DetailPop({
36782
36809
  node,
36783
36810
  resolveHref,
36784
36811
  onClose,
36785
- onExpand
36812
+ onExpand,
36813
+ onNodeOpen
36786
36814
  }) {
36787
36815
  const d = node.detail;
36788
36816
  if (!d) return null;
@@ -36834,14 +36862,22 @@ function DetailPop({
36834
36862
  }
36835
36863
  ),
36836
36864
  /* @__PURE__ */ (0, import_jsx_runtime120.jsx)("div", { className: "ft-detail__head", children: /* @__PURE__ */ (0, import_jsx_runtime120.jsx)("span", { className: "ft-detail__title", children: node.label }) }),
36837
- /* @__PURE__ */ (0, import_jsx_runtime120.jsx)(DetailBody, { node, resolveHref })
36865
+ /* @__PURE__ */ (0, import_jsx_runtime120.jsx)(
36866
+ DetailBody,
36867
+ {
36868
+ node,
36869
+ resolveHref,
36870
+ onNodeOpen
36871
+ }
36872
+ )
36838
36873
  ] });
36839
36874
  }
36840
36875
  function DetailOverlay({
36841
36876
  node,
36842
36877
  resolveHref,
36843
36878
  onCollapse,
36844
- onClose
36879
+ onClose,
36880
+ onNodeOpen
36845
36881
  }) {
36846
36882
  if (!node.detail) return null;
36847
36883
  return /* @__PURE__ */ (0, import_jsx_runtime120.jsx)(
@@ -36896,7 +36932,14 @@ function DetailOverlay({
36896
36932
  }
36897
36933
  ),
36898
36934
  /* @__PURE__ */ (0, import_jsx_runtime120.jsx)("div", { className: "ft-detail-overlay__head", children: /* @__PURE__ */ (0, import_jsx_runtime120.jsx)("span", { className: "ft-detail-overlay__title", children: node.label }) }),
36899
- /* @__PURE__ */ (0, import_jsx_runtime120.jsx)(DetailBody, { node, resolveHref })
36935
+ /* @__PURE__ */ (0, import_jsx_runtime120.jsx)(
36936
+ DetailBody,
36937
+ {
36938
+ node,
36939
+ resolveHref,
36940
+ onNodeOpen
36941
+ }
36942
+ )
36900
36943
  ] })
36901
36944
  }
36902
36945
  );
@@ -37602,7 +37645,8 @@ function FlowTree({
37602
37645
  node: n.data,
37603
37646
  resolveHref,
37604
37647
  onClose: () => closeDetail(n.data.id),
37605
- onExpand: () => expandDetail(n.data.id)
37648
+ onExpand: () => expandDetail(n.data.id),
37649
+ onNodeOpen
37606
37650
  }
37607
37651
  )
37608
37652
  }
@@ -37622,7 +37666,8 @@ function FlowTree({
37622
37666
  node: overlayNode,
37623
37667
  resolveHref,
37624
37668
  onCollapse: collapseOverlay,
37625
- onClose: () => closeDetail(overlayNode.id)
37669
+ onClose: () => closeDetail(overlayNode.id),
37670
+ onNodeOpen
37626
37671
  }
37627
37672
  ) : null,
37628
37673
  !hideLegend ? /* @__PURE__ */ (0, import_jsx_runtime120.jsx)("div", { className: "ft-legend ft-mono", children: focusedPath.map((id, i) => {