backpack-viewer 0.7.4 → 0.7.6

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.
@@ -0,0 +1 @@
1
+ *{margin:0;padding:0;box-sizing:border-box}:root{--bg: #141414;--bg-surface: #1a1a1a;--bg-hover: #222222;--bg-active: #2a2a2a;--bg-elevated: #1e1e1e;--bg-inset: #111111;--border: #2a2a2a;--text: #d4d4d4;--text-strong: #e5e5e5;--text-muted: #737373;--text-dim: #525252;--accent: #d4a27f;--accent-hover: #e8b898;--badge-text: #141414;--glass-bg: rgba(20, 20, 20, .85);--glass-border: rgba(255, 255, 255, .08);--chip-bg: rgba(42, 42, 42, .7);--chip-bg-active: rgba(42, 42, 42, .9);--chip-bg-hover: rgba(50, 50, 50, .9);--chip-border-active: rgba(255, 255, 255, .06);--shadow: rgba(0, 0, 0, .6);--shadow-strong: rgba(0, 0, 0, .5);--z-canvas-overlay: 20;--z-panel: 30;--z-floating: 40;--z-panel-fullscreen: 45;--z-floating-primary: 50;--z-popup: 55;--z-modal: 60;--z-toast: 70;--canvas-edge: rgba(255, 255, 255, .08);--canvas-edge-highlight: rgba(212, 162, 127, .5);--canvas-edge-dim: rgba(255, 255, 255, .03);--canvas-edge-label: rgba(255, 255, 255, .2);--canvas-edge-label-highlight: rgba(212, 162, 127, .7);--canvas-edge-label-dim: rgba(255, 255, 255, .05);--canvas-arrow: rgba(255, 255, 255, .12);--canvas-arrow-highlight: rgba(212, 162, 127, .5);--canvas-node-label: #a3a3a3;--canvas-node-label-dim: rgba(212, 212, 212, .2);--canvas-type-badge: rgba(115, 115, 115, .5);--canvas-type-badge-dim: rgba(115, 115, 115, .15);--canvas-selection-border: #d4d4d4;--canvas-node-border: rgba(255, 255, 255, .15);--canvas-walk-edge: #e8d5c4}[data-theme=light]{--bg: #f5f5f4;--bg-surface: #fafaf9;--bg-hover: #f0efee;--bg-active: #e7e5e4;--bg-elevated: #f0efee;--bg-inset: #e7e5e4;--border: #d6d3d1;--text: #292524;--text-strong: #1c1917;--text-muted: #78716c;--text-dim: #a8a29e;--accent: #c17856;--accent-hover: #b07a5e;--badge-text: #fafaf9;--glass-bg: rgba(250, 250, 249, .85);--glass-border: rgba(0, 0, 0, .08);--chip-bg: rgba(214, 211, 209, .5);--chip-bg-active: rgba(214, 211, 209, .8);--chip-bg-hover: rgba(200, 197, 195, .8);--chip-border-active: rgba(0, 0, 0, .08);--shadow: rgba(0, 0, 0, .1);--shadow-strong: rgba(0, 0, 0, .15);--canvas-edge: rgba(0, 0, 0, .1);--canvas-edge-highlight: rgba(193, 120, 86, .6);--canvas-edge-dim: rgba(0, 0, 0, .03);--canvas-edge-label: rgba(0, 0, 0, .25);--canvas-edge-label-highlight: rgba(193, 120, 86, .8);--canvas-edge-label-dim: rgba(0, 0, 0, .06);--canvas-arrow: rgba(0, 0, 0, .15);--canvas-arrow-highlight: rgba(193, 120, 86, .6);--canvas-node-label: #57534e;--canvas-node-label-dim: rgba(87, 83, 78, .2);--canvas-type-badge: rgba(87, 83, 78, .5);--canvas-type-badge-dim: rgba(87, 83, 78, .15);--canvas-selection-border: #292524;--canvas-node-border: rgba(0, 0, 0, .1);--canvas-walk-edge: #1a1a1a}body{font-family:system-ui,-apple-system,sans-serif;background:var(--bg);color:var(--text);overflow:hidden}#app{display:flex;height:100vh;width:100vw}#sidebar{width:280px;min-width:280px;background:var(--bg-surface);border-right:1px solid var(--border);border-left:3px solid var(--backpack-color, transparent);display:flex;flex-direction:column;padding:16px;overflow-y:auto}#sidebar.sidebar-collapsed{width:0;min-width:0;padding:0;overflow:hidden;border-right:none}.sidebar-heading-row{display:flex;align-items:center;justify-content:space-between;margin-bottom:14px}.sidebar-heading-row h2{margin-bottom:0}.sidebar-collapse-btn{background:none;border:1px solid var(--border);border-radius:6px;color:var(--text-dim);cursor:pointer;padding:4px 6px;line-height:1;transition:color .15s,border-color .15s}.sidebar-collapse-btn:hover{color:var(--text);border-color:var(--text-muted)}#sidebar h2{font-size:13px;font-weight:600;text-transform:uppercase;letter-spacing:.05em;color:var(--text-muted);margin-bottom:14px}#sidebar input{width:100%;padding:8px 12px;border:1px solid var(--border);border-radius:6px;background:var(--bg);color:var(--text);font-size:13px;outline:none;margin-bottom:12px}#sidebar input:focus{border-color:var(--accent)}#sidebar input::placeholder{color:var(--text-dim)}#ontology-list{list-style:none;display:flex;flex-direction:column;gap:2px}.ontology-item{padding:10px 12px;border-radius:6px;cursor:pointer;transition:background .15s}.ontology-item:hover{background:var(--bg-hover)}.ontology-item.active{background:var(--bg-active)}.ontology-item .name{display:block;font-size:13px;font-weight:500;color:var(--text)}.ontology-item .stats{display:block;font-size:11px;color:var(--text-dim);margin-top:2px}.sidebar-edit-btn{position:absolute;right:8px;top:10px;background:none;border:none;color:var(--text-dim);font-size:11px;cursor:pointer;opacity:0;transition:opacity .1s}.ontology-item{position:relative}.ontology-item:hover .sidebar-edit-btn{opacity:.7}.sidebar-section-heading{font-size:10px;font-weight:600;color:var(--text-dim);letter-spacing:.08em;margin:16px 12px 6px}.remote-list{list-style:none;padding:0;margin:0}.ontology-item-remote .name{display:inline}.remote-name-row{display:flex;align-items:center;gap:8px}.remote-badge{font-size:9px;font-weight:600;color:var(--text-dim);background:var(--bg-hover);padding:1px 6px;border-radius:4px;text-transform:uppercase;letter-spacing:.04em;border:1px solid var(--border)}.remote-source{display:block;font-size:10px;color:var(--text-dim);margin-top:1px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.sidebar-edit-btn:hover{opacity:1!important;color:var(--text)}.sidebar-rename-input{background:transparent;border:none;border-bottom:1px solid var(--accent);color:var(--text);font:inherit;font-size:13px;font-weight:500;outline:none;width:100%;padding:0}.sidebar-branch{font-size:10px;color:var(--accent);opacity:.7;display:block;margin-top:2px}.sidebar-branch:hover{opacity:1}.sidebar-stale-banner{background:#fff3cd;color:#5c3a00;border:1px solid #e6c263;border-radius:6px;padding:10px 12px;margin-bottom:10px;font-size:11px}.sidebar-stale-banner-title{font-weight:600;margin-bottom:2px}.sidebar-stale-banner-subtitle{opacity:.85;margin-bottom:6px}.sidebar-stale-banner-hint{background:#00000014;border-radius:4px;padding:6px 8px;font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;font-size:10px;line-height:1.4;margin:0;white-space:pre-wrap;word-break:break-all}.backpack-picker-container{position:relative;margin-bottom:10px}.backpack-picker-pill{display:flex;align-items:center;gap:6px;width:100%;padding:6px 10px;background:var(--bg-base);border:1px solid var(--border);border-radius:6px;color:var(--fg);font-size:11px;font-family:inherit;cursor:pointer;text-align:left}.backpack-picker-pill:hover{border-color:var(--backpack-color, var(--accent))}.backpack-picker-dot{display:inline-block;width:8px;height:8px;border-radius:50%;background:var(--backpack-color, var(--accent));flex-shrink:0}.backpack-picker-name{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-weight:500}.backpack-picker-caret{opacity:.6;font-size:10px}.backpack-picker-dropdown{position:absolute;top:calc(100% + 4px);left:0;right:0;background:var(--bg-surface);border:1px solid var(--border);border-radius:8px;box-shadow:0 4px 16px var(--shadow);z-index:50;max-height:300px;overflow-y:auto;padding:4px}.backpack-picker-item{display:flex;align-items:center;gap:6px;width:100%;padding:6px 8px;background:transparent;border:none;border-radius:4px;color:var(--fg);font-family:inherit;font-size:11px;cursor:pointer;text-align:left}.backpack-picker-item:hover{background:var(--bg-hover)}.backpack-picker-item.active{background:var(--bg-hover);font-weight:600}.backpack-picker-item-dot{display:inline-block;width:8px;height:8px;border-radius:50%;background:var(--backpack-color, var(--accent));flex-shrink:0}.backpack-picker-item-name{flex-shrink:0}.backpack-picker-item-path{flex:1;opacity:.55;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:9px;text-align:right}.backpack-picker-divider{height:1px;background:var(--border);margin:4px 0}.backpack-picker-add{opacity:.75;font-style:italic}.sidebar-lock-badge{font-size:10px;color:#c08c00;display:none;margin-top:2px}.sidebar-lock-badge.active{display:block}.sidebar-lock-badge.active:before{content:"● ";color:#c08c00}.branch-picker{background:var(--bg-surface);border:1px solid var(--border);border-radius:8px;padding:4px;margin-top:4px;box-shadow:0 4px 16px var(--shadow);z-index:50}.branch-picker-item{display:flex;align-items:center;justify-content:space-between;padding:6px 8px;font-size:12px;color:var(--text);border-radius:4px;cursor:pointer}.branch-picker-item:hover{background:var(--bg-hover)}.branch-picker-active{color:var(--accent);font-weight:600;cursor:default}.branch-picker-active:hover{background:none}.branch-picker-delete{background:none;border:none;color:var(--text-dim);cursor:pointer;font-size:14px;padding:0 4px}.sidebar-snippets{margin-top:4px;padding-left:8px}.sidebar-snippet{display:flex;align-items:center;justify-content:space-between;padding:2px 4px;border-radius:4px;cursor:pointer}.sidebar-snippet:hover{background:var(--bg-hover)}.sidebar-snippet-label{font-size:10px;color:var(--text-dim);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.sidebar-snippet-delete{background:none;border:none;color:var(--text-dim);font-size:12px;cursor:pointer;padding:0 2px;opacity:0}.sidebar-snippet:hover .sidebar-snippet-delete{opacity:1}.branch-picker-delete:hover{color:var(--danger, #e55)}.branch-picker-create{color:var(--accent);font-size:11px;border-top:1px solid var(--border);margin-top:4px;padding-top:8px}.sidebar-footer{margin-top:auto;padding-top:16px;border-top:1px solid var(--border);text-align:center}.sidebar-footer a{display:block;font-size:12px;font-weight:500;color:var(--accent);text-decoration:none;margin-bottom:4px}.sidebar-footer a:hover{color:var(--accent-hover)}.sidebar-footer span{display:block;font-size:10px;color:var(--text-dim)}.sidebar-version{font-size:9px;color:var(--text-dim);opacity:.5;margin-top:4px}.canvas-top-bar{position:absolute;top:16px;left:16px;right:16px;display:flex;justify-content:space-between;align-items:flex-start;pointer-events:none}.canvas-top-left,.canvas-top-right{position:relative;z-index:var(--z-floating);pointer-events:auto;display:flex;align-items:center;gap:4px}.canvas-top-center{position:relative;z-index:var(--z-floating-primary);pointer-events:auto;display:flex;align-items:center;gap:4px}.canvas-top-left{flex-shrink:0;min-width:var(--tools-width, 264px)}.canvas-top-center{flex:1;justify-content:center}.canvas-bottom-bar{position:absolute;bottom:16px;left:16px;right:16px;display:flex;justify-content:space-between;align-items:flex-end;pointer-events:none;gap:8px}.canvas-bottom-left,.canvas-bottom-center,.canvas-bottom-right{display:flex;align-items:center;gap:4px;pointer-events:auto;position:relative;z-index:var(--z-floating)}.canvas-bottom-center{flex:1;justify-content:center}.focus-indicator{display:flex;align-items:center;gap:2px;background:var(--bg-surface);border:1px solid rgba(212,162,127,.4);border-radius:8px;padding:4px 6px 4px 10px;box-shadow:0 2px 8px var(--shadow)}.focus-indicator-label{font-size:11px;color:var(--accent);font-weight:500;white-space:nowrap;margin-right:4px}.focus-indicator-hops{font-size:11px;color:var(--text-muted);font-family:monospace;min-width:12px;text-align:center}.focus-indicator-btn{background:none;border:none;color:var(--text-muted);font-size:14px;cursor:pointer;padding:2px 4px;line-height:1;border-radius:4px;transition:color .15s,background .15s}.focus-indicator-btn:hover:not(:disabled){color:var(--text);background:var(--bg-hover)}.focus-indicator-btn:disabled{color:var(--text-dim);cursor:default;opacity:.3}.focus-indicator-exit{font-size:16px;margin-left:2px}.focus-indicator-exit:hover{color:#ef4444!important}.info-focus-btn{font-size:14px}.theme-toggle{background:var(--bg-surface);border:1px solid var(--border);border-radius:8px;color:var(--text-muted);font-size:18px;cursor:pointer;padding:6px 10px;line-height:1;transition:color .15s,border-color .15s,background .15s;box-shadow:0 2px 8px var(--shadow)}.theme-toggle:hover{color:var(--text);border-color:var(--text-muted);background:var(--bg-hover)}.zoom-controls{display:flex;gap:4px}.zoom-btn{background:var(--bg-surface);border:1px solid var(--border);border-radius:8px;color:var(--text-muted);font-size:18px;cursor:pointer;padding:6px 10px;line-height:1;transition:color .15s,border-color .15s,background .15s;box-shadow:0 2px 8px var(--shadow)}.zoom-btn:hover{color:var(--text);border-color:var(--text-muted);background:var(--bg-hover)}.node-tooltip{position:absolute;pointer-events:none;background:var(--bg);color:var(--text);border:1px solid var(--border);border-radius:6px;padding:4px 8px;font-size:12px;white-space:nowrap;z-index:20;box-shadow:0 2px 8px #00000026;opacity:.95}#canvas-container{flex:1;position:relative;overflow:hidden;touch-action:none}#graph-canvas{position:absolute;top:0;left:0;touch-action:none;width:100%;height:100%;cursor:grab}#graph-canvas:active{cursor:grabbing}.search-overlay{position:relative;display:flex;flex-direction:column;align-items:center;gap:8px;max-height:calc(100vh - 48px);pointer-events:none}.search-overlay>*{pointer-events:auto}.search-overlay.hidden{display:none}.search-input-wrap{position:relative;display:flex;align-items:center;gap:6px;width:380px;max-width:calc(100vw - 340px)}.search-input{flex:1;min-width:0;padding:10px 36px 10px 16px;border:1px solid var(--glass-border);border-radius:10px;background:var(--glass-bg);backdrop-filter:blur(12px);-webkit-backdrop-filter:blur(12px);color:var(--text);font-size:14px;outline:none;transition:border-color .15s,box-shadow .15s}.search-input:focus{border-color:#d4a27f66;box-shadow:0 0 0 3px #d4a27f1a}.search-input::placeholder{color:var(--text-dim)}.search-kbd{position:absolute;right:10px;top:50%;transform:translateY(-50%);padding:2px 7px;border:1px solid var(--border);border-radius:4px;background:var(--bg-surface);color:var(--text-dim);font-size:11px;font-family:monospace;pointer-events:none}.search-kbd.hidden{display:none}.search-results{list-style:none;width:380px;max-width:calc(100vw - 340px);background:var(--glass-bg);backdrop-filter:blur(12px);-webkit-backdrop-filter:blur(12px);border:1px solid var(--border);border-radius:10px;overflow:hidden;box-shadow:0 8px 32px var(--shadow-strong)}.search-results.hidden{display:none}.search-result-item{display:flex;align-items:center;gap:8px;padding:8px 14px;cursor:pointer;transition:background .1s}.search-result-item:hover,.search-result-active{background:var(--bg-hover)}.search-result-dot{width:8px;height:8px;border-radius:50%;flex-shrink:0}.search-result-label{font-size:13px;color:var(--text);flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.search-result-type{font-size:11px;color:var(--text-dim);flex-shrink:0}.chip-toggle{flex-shrink:0;display:flex;align-items:center;justify-content:center;width:36px;height:36px;border:1px solid var(--glass-border);border-radius:10px;background:var(--glass-bg);backdrop-filter:blur(12px);-webkit-backdrop-filter:blur(12px);color:var(--text-dim);cursor:pointer;transition:border-color .15s,color .15s;pointer-events:auto}.chip-toggle:hover{border-color:#d4a27f4d;color:var(--text)}.chip-toggle.active{border-color:#d4a27f66;color:var(--accent)}.type-chips{display:flex;flex-wrap:wrap;gap:4px;justify-content:center;max-width:500px;max-height:200px;overflow-y:auto;padding:4px;border-radius:10px}.type-chips.hidden{display:none}.type-chip{display:flex;align-items:center;gap:4px;padding:3px 10px;border:1px solid transparent;border-radius:12px;background:var(--chip-bg);color:var(--text-dim);font-size:11px;cursor:pointer;transition:all .15s;white-space:nowrap}.type-chip.active{background:var(--chip-bg-active);color:var(--text-muted);border-color:var(--chip-border-active)}.type-chip:hover{background:var(--chip-bg-hover)}.type-chip-dot{width:6px;height:6px;border-radius:50%;flex-shrink:0}.type-chip:not(.active) .type-chip-dot{opacity:.3}.info-panel-content{flex:1;display:flex;flex-direction:column;min-height:0}.info-panel-header{flex-shrink:0;padding:16px 20px 12px;position:relative}.info-panel-body{flex:1;overflow-y:auto;min-height:0;padding:0 20px 20px}.info-connection-link{cursor:pointer;transition:background .15s}.info-connection-link:hover{background:var(--bg-active)}.info-connection-link .info-target{color:var(--accent);text-decoration:underline;text-decoration-color:transparent;transition:text-decoration-color .15s}.info-connection-link:hover .info-target{text-decoration-color:var(--accent)}.info-header{margin-bottom:16px}.info-type-badge{display:inline-block;padding:3px 10px;border-radius:12px;font-size:11px;font-weight:600;color:var(--badge-text);margin-bottom:8px}.info-badge-row{display:flex;flex-wrap:wrap;gap:4px;margin-top:6px}.info-empty-message{font-size:12px;color:var(--text-dim)}.share-list-message{font-size:13px;color:var(--text-dim);text-align:center;padding:12px}.info-label{font-size:18px;font-weight:600;color:var(--text-strong);margin-bottom:4px;word-break:break-word}.info-id{display:block;font-size:11px;color:var(--text-dim);font-family:monospace}.info-section{margin-bottom:16px}.info-section-title{font-size:11px;font-weight:600;text-transform:uppercase;letter-spacing:.05em;color:var(--text-muted);margin-bottom:8px;padding-bottom:4px;border-bottom:1px solid var(--border)}.info-props{display:grid;grid-template-columns:auto 1fr;gap:4px 12px}.info-props dt{font-size:12px;color:var(--text-muted);padding-top:2px}.info-props dd{font-size:12px;color:var(--text);word-break:break-word;display:flex;align-items:center;gap:4px}.info-value{white-space:pre-wrap}.info-array{display:flex;flex-wrap:wrap;gap:4px}.info-tag{display:inline-block;padding:2px 8px;background:var(--bg-hover);border-radius:4px;font-size:11px;color:var(--text-muted)}.info-json{font-size:11px;font-family:monospace;color:var(--text-muted);background:var(--bg-inset);padding:6px 8px;border-radius:4px;overflow-x:auto;white-space:pre}.info-connections{list-style:none;display:flex;flex-direction:column;gap:6px}.info-connection{display:flex;align-items:center;gap:6px;padding:6px 8px;background:var(--bg-elevated);border-radius:6px;font-size:12px;flex-wrap:wrap}.info-connection-active{outline:1.5px solid var(--accent);background:var(--bg-hover)}.info-target-dot{width:8px;height:8px;border-radius:50%;flex-shrink:0}.info-arrow{color:var(--text-dim);font-size:14px;flex-shrink:0}.info-edge-type{color:var(--text-muted);font-size:11px;font-weight:500}.info-target{color:var(--text);font-weight:500}.info-edge-props{width:100%;padding-top:4px;padding-left:20px}.info-edge-prop{display:block;font-size:11px;color:var(--text-dim)}.info-editable{cursor:default;position:relative}.info-inline-edit{background:none;border:none;color:var(--badge-text);opacity:0;font-size:10px;cursor:pointer;margin-left:4px;transition:opacity .15s}.info-editable:hover .info-inline-edit{opacity:.8}.info-inline-edit:hover{opacity:1!important}.info-edit-inline-input{background:transparent;border:none;border-bottom:1px solid var(--accent);color:var(--badge-text);font:inherit;font-size:inherit;outline:none;width:100%;padding:0}.info-edit-input{background:var(--bg-inset);border:1px solid var(--border);border-radius:4px;padding:3px 6px;font-size:12px;font-family:inherit;color:var(--text);flex:1;min-width:0;resize:vertical;overflow:hidden;line-height:1.4;max-height:300px}.info-edit-input:focus{outline:none;border-color:var(--accent)}.info-delete-prop{background:none;border:none;color:var(--text-dim);font-size:14px;cursor:pointer;padding:0 2px;flex-shrink:0;opacity:0;transition:opacity .1s,color .1s}.info-props dd:hover .info-delete-prop{opacity:1}.info-delete-prop:hover{color:#ef4444}.info-add-btn{background:none;border:1px dashed var(--border);border-radius:4px;padding:6px 10px;font-size:12px;color:var(--text-dim);cursor:pointer;width:100%;margin-top:8px;transition:border-color .15s,color .15s}.info-add-btn:hover{border-color:var(--accent);color:var(--text)}.info-add-row{display:flex;gap:4px;margin-top:6px}.info-add-save{background:var(--accent);border:none;border-radius:4px;padding:3px 10px;font-size:12px;color:var(--badge-text);cursor:pointer;flex-shrink:0}.info-add-save:hover{background:var(--accent-hover)}.info-delete-edge{background:none;border:none;color:var(--text-dim);font-size:14px;cursor:pointer;margin-left:auto;padding:0 2px;opacity:0;transition:opacity .1s,color .1s}.info-connection:hover .info-delete-edge{opacity:1}.info-delete-edge:hover{color:#ef4444}.info-danger{margin-top:8px;padding-top:12px;border-top:1px solid var(--border)}.info-delete-node{background:none;border:1px solid rgba(239,68,68,.3);border-radius:6px;padding:6px 12px;font-size:12px;color:#ef4444;cursor:pointer;width:100%;transition:background .15s}.info-delete-node:hover{background:#ef44441a}.tools-pane-toggle{background:var(--bg-surface);border:1px solid var(--border);border-radius:8px;color:var(--text-muted);font-size:18px;cursor:pointer;padding:6px 10px;line-height:1;transition:color .15s,border-color .15s,background .15s;box-shadow:0 2px 8px var(--shadow)}.tools-pane-toggle.hidden{display:none}.tools-pane-toggle:hover{color:var(--text);border-color:var(--text-muted);background:var(--bg-hover)}.tools-pane-toggle.active{color:var(--accent);border-color:#d4a27f66}.tools-pane-content{position:absolute;top:56px;left:16px;bottom:16px;z-index:20;width:var(--tools-width, 264px);box-sizing:border-box;overflow:hidden;display:flex;flex-direction:column;background:var(--bg-surface);border:1px solid var(--border);border-radius:10px;padding:12px;box-shadow:0 8px 32px var(--shadow)}.tools-pane-content.hidden{display:none}.tools-pane-section{margin-bottom:12px}.tools-pane-section:last-child{margin-bottom:0}.tools-pane-heading{font-size:10px;font-weight:600;text-transform:uppercase;letter-spacing:.05em;color:var(--text-dim);margin-bottom:6px}.tools-pane-row{display:flex;align-items:center;gap:6px;padding:3px 0;font-size:12px}.tools-pane-dot{width:6px;height:6px;border-radius:50%;flex-shrink:0}.tools-pane-name{flex:1;color:var(--text);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.tools-pane-count{color:var(--text-dim);font-size:11px;flex-shrink:0}.tools-pane-summary{display:flex;align-items:center;gap:4px;font-size:11px;color:var(--text-muted);padding-bottom:10px;margin-bottom:10px;border-bottom:1px solid var(--border)}.tools-pane-sep{color:var(--text-dim)}.tools-pane-token-card{padding:8px 10px;margin-bottom:10px;border:1px solid var(--border);border-radius:6px;background:var(--bg-hover);font-size:11px}.token-card-label{font-weight:600;color:var(--text);margin-bottom:4px}.token-card-stat{color:var(--text-muted);margin-bottom:4px}.token-card-bar{height:4px;background:var(--border);border-radius:2px;margin:6px 0;overflow:hidden}.token-card-bar-fill{height:100%;background:var(--accent);border-radius:2px;transition:width .3s ease}.tools-pane-clickable{cursor:pointer;border-radius:4px;padding:3px 4px;margin:0 -4px;transition:background .1s}.tools-pane-clickable:hover{background:var(--bg-hover)}.tools-pane-clickable.active{background:var(--bg-hover);outline:1px solid var(--border)}.tools-pane-badge{font-size:9px;color:var(--accent);flex-shrink:0;opacity:.8}.tools-pane-issue .tools-pane-name{color:var(--text-muted)}.tools-pane-more{font-size:10px;color:var(--text-dim);padding:4px 0 0}.tools-pane-edit{background:none;border:none;color:var(--text-dim);font-size:11px;cursor:pointer;padding:0 2px;opacity:0;transition:opacity .1s,color .1s;flex-shrink:0}.tools-pane-row:hover .tools-pane-edit{opacity:1}.tools-pane-edit:hover{color:var(--accent)}.tools-pane-actions{display:flex;gap:6px;padding-top:4px}.tools-pane-action-btn{background:none;border:1px solid var(--border);color:var(--text-muted);font-size:10px;padding:2px 8px;border-radius:3px;cursor:pointer;transition:color .1s,border-color .1s}.tools-pane-action-btn:hover{color:var(--accent);border-color:var(--accent)}.tools-pane-focus-toggle{opacity:.4;font-size:11px}.tools-pane-focus-active{opacity:1!important;color:var(--accent)!important}.tools-pane-focus-clear{margin-top:4px;border-top:1px solid var(--border);padding-top:6px}.tools-pane-editing{background:none!important}.tools-pane-inline-input{width:100%;background:var(--bg);border:1px solid var(--accent);border-radius:4px;color:var(--text);font-size:12px;padding:2px 6px;outline:none}.tools-pane-slider-row{display:flex;align-items:center;gap:6px;padding:4px 0}.tools-pane-slider-label{font-size:11px;color:var(--text-muted);white-space:nowrap;min-width:56px}.tools-pane-slider{flex:1;min-width:0;height:4px;accent-color:var(--accent);cursor:pointer}.tools-pane-slider-value{font-size:10px;color:var(--text-dim);min-width:28px;text-align:right;font-family:monospace}.tools-pane-checkbox{width:14px;height:14px;accent-color:var(--accent);cursor:pointer;flex-shrink:0}.tools-pane-export-row{display:flex;gap:4px;margin-top:6px}.tools-pane-export-btn{flex:1;padding:4px 8px;font-size:11px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text-muted);cursor:pointer;transition:color .15s,border-color .15s}.tools-pane-export-btn:hover{color:var(--text);border-color:var(--text-muted)}.tools-pane-empty{font-size:11px;color:var(--text-dim);text-align:center;padding:8px 0}.tools-pane-tabs{display:flex;gap:2px;margin-bottom:10px;padding-bottom:8px;border-bottom:1px solid var(--border)}.tools-pane-tab{flex:1;padding:4px 0;font-size:10px;font-weight:600;text-transform:uppercase;letter-spacing:.03em;background:none;border:1px solid transparent;border-radius:5px;color:var(--text-dim);cursor:pointer;transition:color .15s,background .15s,border-color .15s}.tools-pane-tab:hover{color:var(--text-muted);background:var(--bg-hover)}.tools-pane-tab-active{color:var(--text);background:var(--bg-hover);border-color:var(--border)}.tools-pane-tab-content{flex:1;overflow-y:auto;overflow-x:hidden;min-height:0}.tools-pane-search{width:100%;padding:4px 8px;font-size:11px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text);outline:none;margin-bottom:8px;box-sizing:border-box}.tools-pane-search:focus{border-color:var(--accent)}.tools-pane-search::placeholder{color:var(--text-dim)}.tools-pane-empty-msg{font-size:11px;color:var(--text-dim);text-align:center;padding:16px 0}.empty-state{position:absolute;top:0;right:0;bottom:0;left:0;display:flex;align-items:center;justify-content:center;z-index:5;pointer-events:none;overflow:hidden}.empty-state.hidden{display:none}.empty-state-bg{position:absolute;top:0;right:0;bottom:0;left:0;overflow:hidden}.empty-state-circle{position:absolute;border-radius:50%;background:var(--accent);opacity:.07}.empty-state-circle.c1{width:80px;height:80px;left:20%;top:15%;animation:float-circle 8s ease-in-out infinite}.empty-state-circle.c2{width:50px;height:50px;right:25%;top:25%;animation:float-circle 6s ease-in-out 1s infinite}.empty-state-circle.c3{width:65px;height:65px;left:55%;bottom:20%;animation:float-circle 7s ease-in-out 2s infinite}.empty-state-circle.c4{width:40px;height:40px;left:15%;bottom:30%;animation:float-circle 9s ease-in-out .5s infinite}.empty-state-circle.c5{width:55px;height:55px;right:15%;bottom:35%;animation:float-circle 7.5s ease-in-out 1.5s infinite}.empty-state-lines{position:absolute;top:0;right:0;bottom:0;left:0;width:100%;height:100%;color:var(--text-dim);animation:float-circle 10s ease-in-out infinite}@keyframes float-circle{0%,to{transform:translateY(0)}50%{transform:translateY(-12px)}}.empty-state-content{text-align:center;max-width:420px;padding:40px 24px;position:relative;z-index:1}.empty-state-icon{color:var(--text-dim);margin-bottom:16px}.empty-state-title{font-size:18px;font-weight:600;color:var(--text);margin-bottom:8px}.empty-state-desc{font-size:13px;color:var(--text-muted);line-height:1.5;margin-bottom:20px}.empty-state-setup{background:var(--bg-surface);border:1px solid var(--border);border-radius:8px;padding:12px 16px;margin-bottom:16px}.empty-state-label{font-size:11px;color:var(--text-dim);margin-bottom:8px}.empty-state-code{display:block;font-size:12px;color:var(--accent);font-family:monospace;word-break:break-all}.empty-state-hint{font-size:11px;color:var(--text-dim)}.empty-state-hint kbd{padding:1px 5px;border:1px solid var(--border);border-radius:3px;background:var(--bg-surface);font-family:monospace;font-size:11px}.shortcuts-overlay{position:fixed;top:0;right:0;bottom:0;left:0;background:#00000080;display:flex;align-items:center;justify-content:center;z-index:100}.shortcuts-overlay.hidden{display:none}.shortcuts-modal{background:var(--bg-surface);border:1px solid var(--border);border-radius:12px;padding:24px;min-width:300px;max-width:400px;box-shadow:0 16px 48px var(--shadow);position:relative}.shortcuts-close{position:absolute;top:12px;right:14px;background:none;border:none;color:var(--text-dim);font-size:20px;cursor:pointer;padding:0 4px;line-height:1}.shortcuts-close:hover{color:var(--text)}.shortcuts-title{font-size:15px;font-weight:600;color:var(--text);margin-bottom:16px}.shortcuts-list{display:flex;flex-direction:column;gap:8px}.shortcuts-row{display:flex;align-items:center;justify-content:space-between;gap:12px}.shortcuts-keys{display:flex;align-items:center;gap:4px}.shortcuts-keys kbd{padding:2px 7px;border:1px solid var(--border);border-radius:4px;background:var(--bg);color:var(--text);font-size:11px;font-family:monospace}.shortcuts-or{font-size:10px;color:var(--text-dim)}.shortcuts-desc{font-size:12px;color:var(--text-muted)}@media(max-width:768px){#app{flex-direction:column}#sidebar{width:100%;min-width:0;max-height:35vh;border-right:none;border-bottom:1px solid var(--border)}.info-panel{top:auto;bottom:72px;right:8px;left:8px;width:auto;max-height:calc(100% - 200px);overflow-y:auto}.info-panel.info-panel-maximized{bottom:0;left:0;right:0}.canvas-top-bar{top:8px;left:8px;right:8px}.canvas-bottom-bar{bottom:8px;left:8px;right:8px}.tools-pane-content{top:48px;left:8px;bottom:80px;width:160px;max-width:calc(100vw - 24px)}.tools-pane-edit{opacity:.6}}.bp-dialog-overlay{position:fixed;top:0;right:0;bottom:0;left:0;background:#00000080;display:flex;align-items:center;justify-content:center;z-index:1000;-webkit-backdrop-filter:blur(2px);backdrop-filter:blur(2px)}.bp-dialog{background:var(--bg-surface);border:1px solid var(--border);border-radius:12px;padding:20px;min-width:280px;max-width:400px;box-shadow:0 16px 48px #0000004d}.bp-dialog-title{font-size:14px;font-weight:600;color:var(--text);margin-bottom:12px}.bp-dialog-message{font-size:13px;color:var(--text-muted);margin-bottom:16px;line-height:1.5}.bp-dialog-input{width:100%;padding:8px 12px;font-size:13px;background:var(--bg);border:1px solid var(--border);border-radius:8px;color:var(--text);outline:none;margin-bottom:16px}.bp-dialog-input:focus{border-color:var(--accent)}.bp-dialog-label{display:block;font-size:11px;color:var(--text-muted);margin-bottom:4px;margin-top:8px;text-transform:uppercase;letter-spacing:.04em}.bp-dialog-path-row{display:flex;gap:8px;margin-bottom:4px}.bp-dialog-path-input{flex:1;margin-bottom:0}.bp-dialog-browse-btn{flex-shrink:0;padding:8px 14px;font-size:12px}.bp-dialog-browse-btn:disabled{opacity:.4;cursor:not-allowed}.bp-dialog-path-input.bp-dialog-drag-over{border-color:var(--accent);background:var(--bg-hover)}.bp-dialog-picker-hint{font-size:11px;color:var(--text-muted);min-height:1em;margin-bottom:8px}.bp-dialog-activate-row{display:flex;align-items:center;gap:8px;margin-top:8px;margin-bottom:12px;font-size:12px;color:var(--text-muted)}.bp-dialog-activate-row input[type=checkbox]{margin:0}.bp-dialog-activate-row label{cursor:pointer}.bp-dialog-buttons{display:flex;justify-content:flex-end;gap:8px}.bp-dialog-btn{padding:6px 16px;font-size:12px;border-radius:6px;border:1px solid var(--border);background:var(--bg);color:var(--text-muted);cursor:pointer;transition:all .15s}.bp-dialog-btn:hover{background:var(--bg-hover);color:var(--text)}.bp-dialog-btn-accent{background:var(--accent);color:#fff;border-color:var(--accent)}.bp-dialog-btn-accent:hover{opacity:.9;color:#fff;background:var(--accent)}.bp-dialog-btn-danger{background:#e55;color:#fff;border-color:#e55}.bp-dialog-btn-danger:hover{opacity:.9;color:#fff;background:#e55}.bp-toast{position:fixed;bottom:24px;left:50%;transform:translate(-50%) translateY(20px);background:var(--bg-surface);border:1px solid var(--border);color:var(--text);padding:8px 20px;border-radius:8px;font-size:12px;z-index:1001;opacity:0;transition:opacity .3s,transform .3s;box-shadow:0 4px 16px var(--shadow)}.bp-toast-visible{opacity:1;transform:translate(-50%) translateY(0)}.context-menu{position:absolute;z-index:100;background:var(--bg-surface);border:1px solid var(--border);border-radius:8px;padding:4px;min-width:180px;box-shadow:0 8px 24px var(--shadow)}.context-menu-item{padding:6px 12px;font-size:12px;color:var(--text);border-radius:4px;cursor:pointer;white-space:nowrap}.context-menu-item:hover{background:var(--bg-hover)}.context-menu-separator{height:1px;background:var(--border);margin:4px 8px}.path-bar{display:flex;align-items:center;gap:4px;background:var(--bg-surface);border:1px solid var(--border);border-radius:8px;padding:6px 12px;box-shadow:0 4px 16px var(--shadow);max-width:80%;overflow-x:auto}.path-bar.hidden{display:none}.path-bar-node{font-size:11px;color:var(--text);padding:2px 8px;border-radius:4px;cursor:pointer;white-space:nowrap;flex-shrink:0}.path-bar-node:hover{background:var(--bg-hover)}.path-bar-edge{font-size:9px;color:var(--text-dim);white-space:nowrap;flex-shrink:0}.path-bar-close{background:none;border:none;color:var(--text-dim);font-size:14px;cursor:pointer;padding:0 4px;margin-left:8px;flex-shrink:0}.path-bar-close:hover{color:var(--text)}.walk-trail-edge{font-size:9px;color:var(--text-dim);padding:1px 0 1px 24px;opacity:.7}.walk-indicator{font-size:10px;color:var(--accent);padding:2px 8px;border:1px solid rgba(212,162,127,.4);border-radius:4px;cursor:pointer;opacity:.4}.walk-indicator.active{opacity:1;background:#d4a27f26;animation:walk-strobe 2s ease-in-out infinite}@keyframes walk-strobe{0%,to{opacity:.6;border-color:#d4a27f4d}50%{opacity:1;border-color:#d4a27fcc}}.copy-prompt-btn{background:var(--bg-surface);border:1px solid var(--border);border-radius:8px;color:var(--text-muted);font-size:12px;cursor:pointer;padding:6px 10px;line-height:1;transition:color .15s,border-color .15s,background .15s;box-shadow:0 2px 8px var(--shadow)}.copy-prompt-btn:hover{color:var(--text);border-color:var(--text-muted);background:var(--bg-hover)}.ext-slot-top-left,.ext-slot-top-right{display:none;align-items:center;gap:4px}.ext-slot-top-left.has-icons,.ext-slot-top-right.has-icons{display:inline-flex}.ext-slot-bottom-left,.ext-slot-bottom-center,.ext-slot-bottom-right{display:none;flex-direction:row;align-items:center;gap:6px;padding:6px;background:var(--bg-surface);border:1px solid var(--border);border-radius:12px;box-shadow:0 4px 16px var(--shadow)}.ext-slot-bottom-left.has-icons,.ext-slot-bottom-center.has-icons,.ext-slot-bottom-right.has-icons{display:flex}.extension-taskbar-icon{display:inline-flex;align-items:center;gap:6px;background:var(--bg-surface);border:1px solid var(--border);border-radius:8px;color:var(--text-muted);font-size:12px;font-weight:500;font-family:inherit;cursor:pointer;padding:6px 10px;line-height:1;box-shadow:0 2px 8px var(--shadow);transition:color .15s,border-color .15s,background .15s}.ext-slot-bottom-left .extension-taskbar-icon,.ext-slot-bottom-center .extension-taskbar-icon,.ext-slot-bottom-right .extension-taskbar-icon{background:transparent;border-color:transparent;box-shadow:none}.extension-taskbar-icon:hover{color:var(--text);border-color:var(--text-muted);background:var(--bg-hover)}.ext-slot-bottom-left .extension-taskbar-icon:hover,.ext-slot-bottom-center .extension-taskbar-icon:hover,.ext-slot-bottom-right .extension-taskbar-icon:hover{border-color:var(--border)}.extension-taskbar-icon-symbol{font-size:11px;opacity:.7}.extension-taskbar-icon-label{font-size:12px}.extension-panel-layer{position:absolute;top:0;right:0;bottom:0;left:0;pointer-events:none}.extension-panel{position:absolute;display:flex;flex-direction:column;background:var(--bg-surface);border:1px solid var(--border);border-radius:12px;box-shadow:0 8px 32px var(--shadow);overflow:hidden;pointer-events:auto;width:380px;max-height:calc(100vh - 120px)}.extension-panel.is-fullscreen{top:0!important;left:0!important;right:0;bottom:0;width:auto;max-height:none;border-radius:0}.extension-panel.is-hidden,#canvas-container.has-fullscreen-panel .canvas-top-left,#canvas-container.has-fullscreen-panel .canvas-top-right,#canvas-container.has-fullscreen-panel .canvas-bottom-bar,#canvas-container.has-fullscreen-panel .ext-slot-top-left,#canvas-container.has-fullscreen-panel .ext-slot-top-right{display:none}#canvas-container.has-fullscreen-panel .canvas-top-bar{top:0}#canvas-container.has-fullscreen-panel .extension-panel.is-fullscreen .extension-panel-header{padding-top:56px}.extension-panel.is-fullscreen{border:none;box-shadow:none}.extension-panel-header{display:flex;align-items:center;gap:6px;padding:8px 10px;border-bottom:1px solid var(--border);background:var(--bg-surface);flex-shrink:0;cursor:grab;-webkit-user-select:none;user-select:none}.extension-panel-header:active{cursor:grabbing}.extension-panel.is-fullscreen .extension-panel-header{cursor:default}.extension-panel-title{flex:1;font-size:13px;font-weight:500;color:var(--text);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.extension-panel-custom-btns{display:flex;gap:4px}.extension-panel-btn{display:inline-flex;align-items:center;justify-content:center;background:none;border:1px solid var(--border);border-radius:6px;color:var(--text-muted);font-size:12px;font-family:inherit;cursor:pointer;padding:3px 8px;line-height:1;min-height:22px;transition:color .15s,background .15s,border-color .15s}.extension-panel-btn:hover:not(:disabled){color:var(--text);background:var(--bg-hover);border-color:var(--text-muted)}.extension-panel-btn:disabled{opacity:.4;cursor:not-allowed}.extension-panel-btn-fullscreen{padding:2px 6px}.extension-panel-btn-fullscreen svg{display:block}.extension-panel-btn-close{font-size:16px;padding:0 7px}.extension-panel-body{flex:1;overflow:hidden;display:flex;flex-direction:column}
@@ -0,0 +1,6 @@
1
+ var Jn=Object.defineProperty;var Kn=(t,e,s)=>e in t?Jn(t,e,{enumerable:!0,configurable:!0,writable:!0,value:s}):t[e]=s;var At=(t,e,s)=>Kn(t,typeof e!="symbol"?e+"":e,s);(function(){const e=document.createElement("link").relList;if(e&&e.supports&&e.supports("modulepreload"))return;for(const u of document.querySelectorAll('link[rel="modulepreload"]'))l(u);new MutationObserver(u=>{for(const r of u)if(r.type==="childList")for(const d of r.addedNodes)d.tagName==="LINK"&&d.rel==="modulepreload"&&l(d)}).observe(document,{childList:!0,subtree:!0});function s(u){const r={};return u.integrity&&(r.integrity=u.integrity),u.referrerPolicy&&(r.referrerPolicy=u.referrerPolicy),u.crossOrigin==="use-credentials"?r.credentials="include":u.crossOrigin==="anonymous"?r.credentials="omit":r.credentials="same-origin",r}function l(u){if(u.ep)return;u.ep=!0;const r=s(u);fetch(u.href,r)}})();const Zn="modulepreload",Qn=function(t){return"/"+t},hn={},eo=function(e,s,l){let u=Promise.resolve();if(s&&s.length>0){let d=function(g){return Promise.all(g.map(i=>Promise.resolve(i).then(c=>({status:"fulfilled",value:c}),c=>({status:"rejected",reason:c}))))};document.getElementsByTagName("link");const o=document.querySelector("meta[property=csp-nonce]"),n=(o==null?void 0:o.nonce)||(o==null?void 0:o.getAttribute("nonce"));u=d(s.map(g=>{if(g=Qn(g),g in hn)return;hn[g]=!0;const i=g.endsWith(".css"),c=i?'[rel="stylesheet"]':"";if(document.querySelector(`link[href="${g}"]${c}`))return;const T=document.createElement("link");if(T.rel=i?"stylesheet":Zn,i||(T.as="script"),T.crossOrigin="",T.href=g,n&&T.setAttribute("nonce",n),document.head.appendChild(T),i)return new Promise((A,E)=>{T.addEventListener("load",A),T.addEventListener("error",()=>E(new Error(`Unable to preload CSS for ${g}`)))})}))}function r(d){const o=new Event("vite:preloadError",{cancelable:!0});if(o.payload=d,window.dispatchEvent(o),!o.defaultPrevented)throw d}return u.then(d=>{for(const o of d||[])o.status==="rejected"&&r(o.reason);return e().catch(r)})};async function vt(){const t=await fetch("/api/ontologies");return t.ok?t.json():[]}async function Pt(t){const e=await fetch(`/api/ontologies/${encodeURIComponent(t)}`);if(!e.ok)throw new Error(`Failed to load ontology: ${t}`);return e.json()}async function to(){const t=await fetch("/api/remotes");return t.ok?t.json():[]}async function no(t){const e=await fetch(`/api/remotes/${encodeURIComponent(t)}`);if(!e.ok)throw new Error(`Failed to load remote graph: ${t}`);return e.json()}async function zt(t,e){if(!(await fetch(`/api/ontologies/${encodeURIComponent(t)}`,{method:"PUT",headers:{"Content-Type":"application/json"},body:JSON.stringify(e)})).ok)throw new Error(`Failed to save ontology: ${t}`)}async function oo(t,e){if(!(await fetch(`/api/ontologies/${encodeURIComponent(t)}/rename`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({name:e})})).ok)throw new Error(`Failed to rename ontology: ${t}`)}async function so(t){const e=await fetch(`/api/graphs/${encodeURIComponent(t)}/branches`);return e.ok?e.json():[]}async function fn(t,e,s){const l=await fetch(`/api/graphs/${encodeURIComponent(t)}/branches`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({name:e,from:s})});if(!l.ok){const u=await l.json().catch(()=>({}));throw new Error(u.error||"Failed to create branch")}}async function gn(t,e){const s=await fetch(`/api/graphs/${encodeURIComponent(t)}/branches/switch`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({name:e})});if(!s.ok){const l=await s.json().catch(()=>({}));throw new Error(l.error||"Failed to switch branch")}}async function ao(t,e){const s=await fetch(`/api/graphs/${encodeURIComponent(t)}/branches/${encodeURIComponent(e)}`,{method:"DELETE"});if(!s.ok){const l=await s.json().catch(()=>({}));throw new Error(l.error||"Failed to delete branch")}}async function co(t){const e=await fetch(`/api/graphs/${encodeURIComponent(t)}/snapshots`);return e.ok?e.json():[]}async function io(t,e){const s=await fetch(`/api/graphs/${encodeURIComponent(t)}/snapshots`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({label:e})});if(!s.ok){const l=await s.json().catch(()=>({}));throw new Error(l.error||"Failed to create snapshot")}}async function lo(t,e){const s=await fetch(`/api/graphs/${encodeURIComponent(t)}/rollback`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({version:e})});if(!s.ok){const l=await s.json().catch(()=>({}));throw new Error(l.error||"Failed to rollback")}}async function ro(t){const e=await fetch(`/api/graphs/${encodeURIComponent(t)}/snippets`);return e.ok?e.json():[]}async function yn(t,e,s,l,u){const r=await fetch(`/api/graphs/${encodeURIComponent(t)}/snippets`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({label:e,description:u,nodeIds:s,edgeIds:l})});if(!r.ok)throw new Error("Failed to save snippet");return(await r.json()).id}async function po(t,e){const s=await fetch(`/api/graphs/${encodeURIComponent(t)}/snippets/${encodeURIComponent(e)}`);if(!s.ok)throw new Error("Snippet not found");return s.json()}async function uo(t,e){if(!(await fetch(`/api/graphs/${encodeURIComponent(t)}/snippets/${encodeURIComponent(e)}`,{method:"DELETE"})).ok)throw new Error("Failed to delete snippet")}const Cn="bp-dialog-overlay";function nn(){var e;(e=document.querySelector(`.${Cn}`))==null||e.remove();const t=document.createElement("div");return t.className=Cn,document.body.appendChild(t),t}function on(t,e){const s=document.createElement("div");s.className="bp-dialog";const l=document.createElement("h4");return l.className="bp-dialog-title",l.textContent=e,s.appendChild(l),t.appendChild(s),t.addEventListener("click",u=>{u.target===t&&t.remove()}),s}function sn(t,e){const s=document.createElement("div");s.className="bp-dialog-buttons";for(const l of e){const u=document.createElement("button");u.className="bp-dialog-btn",l.accent&&u.classList.add("bp-dialog-btn-accent"),l.danger&&u.classList.add("bp-dialog-btn-danger"),u.textContent=l.label,u.addEventListener("click",l.onClick),s.appendChild(u)}t.appendChild(s)}function jn(t,e){return new Promise(s=>{var d;const l=nn(),u=on(l,t),r=document.createElement("p");r.className="bp-dialog-message",r.textContent=e,u.appendChild(r),sn(u,[{label:"Cancel",onClick:()=>{l.remove(),s(!1)}},{label:"Confirm",accent:!0,onClick:()=>{l.remove(),s(!0)}}]),(d=u.querySelector(".bp-dialog-btn-accent"))==null||d.focus()})}function Dt(t,e,s){return new Promise(l=>{const u=nn(),r=on(u,t),d=document.createElement("input");d.type="text",d.className="bp-dialog-input",d.placeholder=e??"",d.value="",r.appendChild(d);const o=()=>{const n=d.value.trim();u.remove(),l(n||null)};d.addEventListener("keydown",n=>{n.key==="Enter"&&o(),n.key==="Escape"&&(u.remove(),l(null))}),sn(r,[{label:"Cancel",onClick:()=>{u.remove(),l(null)}},{label:"OK",accent:!0,onClick:o}]),d.focus(),d.select()})}function mo(){return new Promise(t=>{const e=nn(),s=on(e,"Add Backpack"),l=document.createElement("p");l.className="bp-dialog-message",l.textContent="Enter the absolute path to a directory that should become a backpack. It will be shown in the sidebar using the last segment of the path as its display name.",s.appendChild(l);const u=document.createElement("label");u.className="bp-dialog-label",u.textContent="Path",s.appendChild(u);const r=document.createElement("div");r.className="bp-dialog-path-row",s.appendChild(r);const d=document.createElement("input");d.type="text",d.className="bp-dialog-input bp-dialog-path-input",d.placeholder="/Users/you/OneDrive/work",r.appendChild(d);const o=document.createElement("button");o.type="button",o.className="bp-dialog-btn bp-dialog-browse-btn",o.textContent="Browse...",r.appendChild(o),typeof window.showDirectoryPicker=="function"||(o.disabled=!0,o.title="Browser doesn't support native folder picker — paste the path manually"),o.addEventListener("click",async E=>{E.preventDefault();try{const F=await window.showDirectoryPicker({mode:"read"});g.textContent=`Picked "${F.name}" — paste the absolute path to it below.`,d.focus()}catch{}});const g=document.createElement("div");g.className="bp-dialog-picker-hint",s.appendChild(g);const i=document.createElement("div");i.className="bp-dialog-activate-row";const c=document.createElement("input");c.type="checkbox",c.id="bp-dialog-activate",c.checked=!0;const T=document.createElement("label");T.htmlFor="bp-dialog-activate",T.textContent="Switch to this backpack after registering",i.appendChild(c),i.appendChild(T),s.appendChild(i),d.addEventListener("dragover",E=>{E.preventDefault(),d.classList.add("bp-dialog-drag-over")}),d.addEventListener("dragleave",()=>{d.classList.remove("bp-dialog-drag-over")}),d.addEventListener("drop",E=>{var V,_,X;E.preventDefault(),d.classList.remove("bp-dialog-drag-over");const F=(V=E.dataTransfer)==null?void 0:V.items;if(!F||F.length===0)return;const W=(X=(_=F[0]).webkitGetAsEntry)==null?void 0:X.call(_);W!=null&&W.isDirectory&&(g.textContent=`Dropped "${W.name}" — paste the absolute path to it below.`)});const A=()=>{const E=d.value.trim();E&&(e.remove(),t({path:E,activate:c.checked}))};d.addEventListener("keydown",E=>{E.key==="Enter"&&A(),E.key==="Escape"&&(e.remove(),t(null))}),sn(s,[{label:"Cancel",onClick:()=>{e.remove(),t(null)}},{label:"Register",accent:!0,onClick:A}]),d.focus()})}function kt(t,e=3e3){const s=document.querySelector(".bp-toast");s&&s.remove();const l=document.createElement("div");l.className="bp-toast",l.textContent=t,document.body.appendChild(l),setTimeout(()=>l.classList.add("bp-toast-visible"),10),setTimeout(()=>{l.classList.remove("bp-toast-visible"),setTimeout(()=>l.remove(),300)},e)}const bn="http://www.w3.org/2000/svg";function at(t,e){const s=document.createElementNS(bn,"svg"),l=t.size??16;s.setAttribute("width",String(l)),s.setAttribute("height",String(l)),s.setAttribute("viewBox",t.viewBox??"0 0 24 24"),s.setAttribute("fill","none"),s.setAttribute("stroke","currentColor"),s.setAttribute("stroke-width",String(t.strokeWidth??2)),t.strokeLinecap&&s.setAttribute("stroke-linecap",t.strokeLinecap),t.strokeLinejoin&&s.setAttribute("stroke-linejoin",t.strokeLinejoin),t.className&&s.setAttribute("class",t.className);for(const u of e){const r=document.createElementNS(bn,u.tag);for(const[d,o]of Object.entries(u.attrs))r.setAttribute(d,String(o));s.appendChild(r)}return s}function ho(t){return Array.from(t.childNodes).map(e=>e.cloneNode(!0))}function fo(t,e){t.replaceChildren(...e)}function vn(t){return t>=1e3?`${(t/1e3).toFixed(1)}k tokens`:`${t} tokens`}function xn(t,e){return t*50+e*25+50}function go(t,e){const s=typeof e=="function"?{onSelect:e}:e,l=document.createElement("h2");l.textContent="Backpack Viewer";const u=document.createElement("input");u.type="text",u.placeholder="Filter...",u.id="filter";const r=document.createElement("ul");r.id="ontology-list";const d=document.createElement("h3");d.className="sidebar-section-heading",d.textContent="REMOTE GRAPHS",d.hidden=!0;const o=document.createElement("ul");o.id="remote-list",o.className="remote-list",o.hidden=!0;const n=document.createElement("div");n.className="sidebar-footer";const g=document.createElement("a");g.href="mailto:support@backpackontology.com",g.textContent="support@backpackontology.com";const i=document.createElement("span");i.textContent="Feedback & support";const c=document.createElement("span");c.className="sidebar-version",c.textContent="v0.7.6",n.append(g,i,c);const T=document.createElement("button");T.className="sidebar-collapse-btn",T.title="Toggle sidebar (Tab)",T.appendChild(at({size:14},[{tag:"polyline",attrs:{points:"11 17 6 12 11 7"}},{tag:"polyline",attrs:{points:"18 17 13 12 18 7"}}]));let A=!1;function E(){A=!A,t.classList.toggle("sidebar-collapsed",A),ye.classList.toggle("hidden",!A)}T.addEventListener("click",E);const F=document.createElement("div");F.className="sidebar-heading-row",F.appendChild(l),F.appendChild(T),t.appendChild(F);const W=document.createElement("div");W.className="sidebar-stale-banner",W.hidden=!0,t.appendChild(W);const V=document.createElement("button");V.className="backpack-picker-pill",V.type="button",V.setAttribute("aria-haspopup","listbox"),V.setAttribute("aria-expanded","false");const _=document.createElement("span");_.className="backpack-picker-dot";const X=document.createElement("span");X.className="backpack-picker-name",X.textContent="...";const Y=document.createElement("span");Y.className="backpack-picker-caret",Y.textContent="▾",V.appendChild(_),V.appendChild(X),V.appendChild(Y);const K=document.createElement("div");K.className="backpack-picker-dropdown",K.hidden=!0,K.setAttribute("role","listbox");const q=document.createElement("div");q.className="backpack-picker-container",q.appendChild(V),q.appendChild(K),t.appendChild(q);let me=!1;function U(){me=!1,K.hidden=!0,V.setAttribute("aria-expanded","false")}function pe(){me=!0,K.hidden=!1,V.setAttribute("aria-expanded","true")}V.addEventListener("click",p=>{p.stopPropagation(),me?U():pe()}),document.addEventListener("click",p=>{q.contains(p.target)||U()});let Ee=[],te=null;function G(){K.replaceChildren();for(const C of Ee){const m=document.createElement("button");m.className="backpack-picker-item",m.type="button",m.setAttribute("role","option"),C.active&&m.classList.add("active");const v=document.createElement("span");v.className="backpack-picker-item-dot",v.style.setProperty("--backpack-color",C.color);const S=document.createElement("span");S.className="backpack-picker-item-name",S.textContent=C.name;const h=document.createElement("span");h.className="backpack-picker-item-path",h.textContent=C.path,m.appendChild(v),m.appendChild(S),m.appendChild(h),m.addEventListener("click",I=>{I.stopPropagation(),U(),!C.active&&s.onBackpackSwitch&&s.onBackpackSwitch(C.name)}),K.appendChild(m)}const p=document.createElement("div");p.className="backpack-picker-divider",K.appendChild(p);const y=document.createElement("button");y.className="backpack-picker-item backpack-picker-add",y.type="button",y.textContent="+ Add new backpack…",y.addEventListener("click",async C=>{if(C.stopPropagation(),U(),!s.onBackpackRegister)return;const m=await mo();m&&s.onBackpackRegister(m.path,m.activate)}),K.appendChild(y)}const ye=document.createElement("button");ye.className="tools-pane-toggle hidden",ye.title="Show sidebar (Tab)",ye.appendChild(at({size:14},[{tag:"polyline",attrs:{points:"13 7 18 12 13 17"}},{tag:"polyline",attrs:{points:"6 7 11 12 6 17"}}])),ye.addEventListener("click",E),t.appendChild(u),t.appendChild(r),t.appendChild(d),t.appendChild(o),t.appendChild(n);let Ce=[],se=[],ge="";return u.addEventListener("input",()=>{const p=u.value.toLowerCase();for(const y of Ce){const C=y.dataset.name??"";y.style.display=C.includes(p)?"":"none"}for(const y of se){const C=y.dataset.name??"";y.style.display=C.includes(p)?"":"none"}}),{setStaleVersionBanner(p,y){W.replaceChildren();const C=document.createElement("div");C.className="sidebar-stale-banner-title",C.textContent=`Viewer ${p} is out of date`;const m=document.createElement("div");m.className="sidebar-stale-banner-subtitle",m.textContent=`Latest is ${y}. Your version is stuck because of an npx cache.`;const v=document.createElement("pre");v.className="sidebar-stale-banner-hint",v.textContent=`npm cache clean --force
2
+ npx backpack-viewer@latest`,W.appendChild(C),W.appendChild(m),W.appendChild(v),W.hidden=!1},setBackpacks(p){Ee=p.slice();const y=p.find(C=>C.active)??null;te=y,y&&(X.textContent=y.name,_.style.setProperty("--backpack-color",y.color),t.style.setProperty("--backpack-color",y.color)),G()},setActiveBackpack(p){te=p,Ee=Ee.map(y=>({...y,active:y.name===p.name})),Ee.some(y=>y.name===p.name)||Ee.push({...p,active:!0}),X.textContent=p.name,_.style.setProperty("--backpack-color",p.color),t.style.setProperty("--backpack-color",p.color),G()},getActiveBackpack(){return te},setSummaries(p){r.replaceChildren();const y=fetch("/api/locks").then(C=>C.json()).catch(()=>({}));Ce=p.map(C=>{const m=document.createElement("li");m.className="ontology-item",m.dataset.name=C.name;const v=document.createElement("span");v.className="name",v.textContent=C.name;const S=document.createElement("span");S.className="stats";const h=xn(C.nodeCount,C.edgeCount);S.textContent=`${C.nodeCount} nodes, ${C.edgeCount} edges · ~${vn(h)}`;const I=document.createElement("span");I.className="sidebar-branch",I.dataset.graph=C.name;const w=document.createElement("span");if(w.className="sidebar-lock-badge",w.dataset.graph=C.name,y.then(N=>{if(!w.isConnected)return;const L=N[C.name];L&&typeof L=="object"&&L.author&&(w.textContent=`editing: ${L.author}`,w.title=`Last activity: ${L.lastActivity??""}`,w.classList.add("active"))}),m.appendChild(v),m.appendChild(S),m.appendChild(w),m.appendChild(I),s.onRename){const N=document.createElement("button");N.className="sidebar-edit-btn",N.textContent="✎",N.title="Rename";const L=s.onRename;N.addEventListener("click",b=>{b.stopPropagation();const M=document.createElement("input");M.type="text",M.className="sidebar-rename-input",M.value=C.name,v.textContent="",v.appendChild(M),N.style.display="none",M.focus(),M.select();const $=()=>{const Q=M.value.trim();Q&&Q!==C.name?L(C.name,Q):(v.textContent=C.name,N.style.display="")};M.addEventListener("blur",$),M.addEventListener("keydown",Q=>{Q.key==="Enter"&&M.blur(),Q.key==="Escape"&&(M.value=C.name,M.blur())})}),m.appendChild(N)}return m.addEventListener("click",()=>s.onSelect(C.name)),r.appendChild(m),m}),ge&&this.setActive(ge)},setActive(p){ge=p;for(const y of Ce)y.classList.toggle("active",y.dataset.name===p);for(const y of se)y.classList.toggle("active",y.dataset.name===p)},setRemotes(p){o.replaceChildren(),se=p.map(C=>{const m=document.createElement("li");m.className="ontology-item ontology-item-remote",m.dataset.name=C.name;const v=document.createElement("div");v.className="remote-name-row";const S=document.createElement("span");S.className="name",S.textContent=C.name;const h=document.createElement("span");h.className="remote-badge",h.textContent=C.pinned?"remote · pinned":"remote",h.title=`Source: ${C.source??C.url}`,v.appendChild(S),v.appendChild(h);const I=document.createElement("span");I.className="stats";const w=xn(C.nodeCount,C.edgeCount);I.textContent=`${C.nodeCount} nodes, ${C.edgeCount} edges · ~${vn(w)}`;const N=document.createElement("span");return N.className="remote-source",N.textContent=C.source??new URL(C.url).hostname,N.title=C.url,m.appendChild(v),m.appendChild(I),m.appendChild(N),m.addEventListener("click",()=>s.onSelect(C.name)),o.appendChild(m),m});const y=p.length>0;d.hidden=!y,o.hidden=!y,ge&&this.setActive(ge)},setActiveBranch(p,y,C){const m=r.querySelectorAll(`.sidebar-branch[data-graph="${p}"]`);for(const v of m){v.textContent=`/ ${y}`,v.title="Click to switch branch",v.style.cursor="pointer";const S=v.cloneNode(!0);v.replaceWith(S),S.addEventListener("click",h=>{h.stopPropagation(),be(p,S,C??[])})}},setSnippets(p,y){var v;const C=Ce.find(S=>S.dataset.name===p);if(!C||((v=C.querySelector(".sidebar-snippets"))==null||v.remove(),y.length===0))return;const m=document.createElement("div");m.className="sidebar-snippets";for(const S of y){const h=document.createElement("div");h.className="sidebar-snippet";const I=document.createElement("span");I.className="sidebar-snippet-label",I.textContent=`◆ ${S.label}`,I.title=`${S.nodeCount} nodes — click to load`;const w=document.createElement("button");w.className="sidebar-snippet-delete",w.textContent="×",w.title="Delete snippet",w.addEventListener("click",N=>{var L;N.stopPropagation(),(L=s.onSnippetDelete)==null||L.call(s,p,S.id)}),h.appendChild(I),h.appendChild(w),h.addEventListener("click",N=>{var L;N.stopPropagation(),(L=s.onSnippetLoad)==null||L.call(s,p,S.id)}),m.appendChild(h)}C.appendChild(m)},toggle:E,expandBtn:ye};function be(p,y,C){const m=t.querySelector(".branch-picker");m&&m.remove();const v=document.createElement("div");v.className="branch-picker";for(const h of C){const I=document.createElement("div");I.className="branch-picker-item",h.active&&I.classList.add("branch-picker-active");const w=document.createElement("span");if(w.textContent=h.name,I.appendChild(w),!h.active&&s.onBranchDelete){const N=document.createElement("button");N.className="branch-picker-delete",N.textContent="×",N.title=`Delete ${h.name}`,N.addEventListener("click",L=>{L.stopPropagation(),jn("Delete branch",`Delete branch "${h.name}"?`).then(b=>{b&&(s.onBranchDelete(p,h.name),v.remove())})}),I.appendChild(N)}h.active||I.addEventListener("click",()=>{var N;(N=s.onBranchSwitch)==null||N.call(s,p,h.name),v.remove()}),v.appendChild(I)}if(s.onBranchCreate){const h=document.createElement("div");h.className="branch-picker-item branch-picker-create",h.textContent="+ New branch",h.addEventListener("click",()=>{Dt("New branch","Branch name").then(I=>{I&&(s.onBranchCreate(p,I),v.remove())})}),v.appendChild(h)}y.after(v);const S=h=>{v.contains(h.target)||(v.remove(),document.removeEventListener("click",S))};setTimeout(()=>document.addEventListener("click",S),0)}}function Zt(t,e,s,l){return{x0:t,y0:e,x1:s,y1:l,cx:0,cy:0,mass:0,children:[null,null,null,null],body:null}}function En(t,e,s){const l=(t.x0+t.x1)/2,u=(t.y0+t.y1)/2;return(e<l?0:1)+(s<u?0:2)}function wn(t,e){const s=(t.x0+t.x1)/2,l=(t.y0+t.y1)/2;switch(e){case 0:return[t.x0,t.y0,s,l];case 1:return[s,t.y0,t.x1,l];case 2:return[t.x0,l,s,t.y1];default:return[s,l,t.x1,t.y1]}}function Qt(t,e){if(t.mass===0&&t.body===null){t.body=e,t.cx=e.x,t.cy=e.y,t.mass=1;return}if(t.body!==null){const u=t.body;t.body=null,u.x===e.x&&u.y===e.y&&(e.x+=(Math.random()-.5)*.1,e.y+=(Math.random()-.5)*.1);const r=En(t,u.x,u.y);if(t.children[r]===null){const[d,o,n,g]=wn(t,r);t.children[r]=Zt(d,o,n,g)}Qt(t.children[r],u)}const s=En(t,e.x,e.y);if(t.children[s]===null){const[u,r,d,o]=wn(t,s);t.children[s]=Zt(u,r,d,o)}Qt(t.children[s],e);const l=t.mass+1;t.cx=(t.cx*t.mass+e.x)/l,t.cy=(t.cy*t.mass+e.y)/l,t.mass=l}function yo(t){if(t.length===0)return null;let e=1/0,s=1/0,l=-1/0,u=-1/0;for(const i of t)i.x<e&&(e=i.x),i.y<s&&(s=i.y),i.x>l&&(l=i.x),i.y>u&&(u=i.y);const r=Math.max(l-e,u-s)*.1+50,d=(e+l)/2,o=(s+u)/2,n=Math.max(l-e,u-s)/2+r,g=Zt(d-n,o-n,d+n,o+n);for(const i of t)Qt(g,i);return g}function Co(t,e,s,l,u,r){zn(t,e,s,l,u,r)}function zn(t,e,s,l,u,r){if(t.mass===0)return;const d=t.cx-e.x,o=t.cy-e.y,n=d*d+o*o;if(t.body!==null){if(t.body!==e){let i=Math.sqrt(n);i<r&&(i=r);const c=l*u/(i*i),T=d/i*c,A=o/i*c;e.vx-=T,e.vy-=A}return}const g=t.x1-t.x0;if(g*g/n<s*s){let i=Math.sqrt(n);i<r&&(i=r);const c=l*t.mass*u/(i*i),T=d/i*c,A=o/i*c;e.vx-=T,e.vy-=A;return}for(let i=0;i<4;i++)t.children[i]!==null&&zn(t.children[i],e,s,l,u,r)}const _n={clusterStrength:.08,spacing:1.5},kn=6e3,bo=12e3,vo=.004,Hn=140,Yn=350,Sn=.9,Nn=.01,xt=30,_t=50;let Ze={..._n};function lt(t){t.clusterStrength!==void 0&&(Ze.clusterStrength=t.clusterStrength),t.spacing!==void 0&&(Ze.spacing=t.spacing)}function wt(){return{...Ze}}function xo(t){if(t<=30)return{..._n};const e=Math.log2(t/30);return{clusterStrength:Math.min(.5,.08+.06*e),spacing:Math.min(15,1.5+1.2*e)}}function Eo(t,e){for(const s of Object.values(t))if(typeof s=="string")return s;return e}function Ln(t,e,s){const l=new Set(e);let u=new Set(e);for(let r=0;r<s;r++){const d=new Set;for(const o of t.edges)u.has(o.sourceId)&&!l.has(o.targetId)&&d.add(o.targetId),u.has(o.targetId)&&!l.has(o.sourceId)&&d.add(o.sourceId);for(const o of d)l.add(o);if(u=d,d.size===0)break}return{nodes:t.nodes.filter(r=>l.has(r.id)),edges:t.edges.filter(r=>l.has(r.sourceId)&&l.has(r.targetId)),metadata:t.metadata}}function Ht(t){const e=new Map,s=[...new Set(t.nodes.map(n=>n.type))],l=Math.sqrt(s.length)*Yn*.6*Math.max(1,Ze.spacing),u=new Map,r=new Map;for(const n of t.nodes)r.set(n.type,(r.get(n.type)??0)+1);const d=t.nodes.map(n=>{const g=s.indexOf(n.type),i=2*Math.PI*g/Math.max(s.length,1),c=Math.cos(i)*l,T=Math.sin(i)*l,A=u.get(n.type)??0;u.set(n.type,A+1);const E=r.get(n.type)??1,F=2*Math.PI*A/E,W=Hn*.6,V={id:n.id,x:c+Math.cos(F)*W,y:T+Math.sin(F)*W,vx:0,vy:0,label:Eo(n.properties,n.id),type:n.type};return e.set(n.id,V),V}),o=t.edges.map(n=>({sourceId:n.sourceId,targetId:n.targetId,type:n.type}));return{nodes:d,edges:o,nodeMap:e}}const wo=.7,ko=80;function So(t,e){const{nodes:s,edges:l,nodeMap:u}=t,r=bo*Ze.spacing;if(s.length>=ko){const o=yo(s);if(o)for(const g of s)Co(o,g,wo,r,e,xt);const n=r-kn;if(n>0){const g=new Map;for(const i of s){let c=g.get(i.type);c||(c=[],g.set(i.type,c)),c.push(i)}for(const i of g.values())for(let c=0;c<i.length;c++)for(let T=c+1;T<i.length;T++){const A=i[c],E=i[T];let F=E.x-A.x,W=E.y-A.y,V=Math.sqrt(F*F+W*W);V<xt&&(V=xt);const _=n*e/(V*V),X=F/V*_,Y=W/V*_;A.vx+=X,A.vy+=Y,E.vx-=X,E.vy-=Y}}}else for(let o=0;o<s.length;o++)for(let n=o+1;n<s.length;n++){const g=s[o],i=s[n];let c=i.x-g.x,T=i.y-g.y,A=Math.sqrt(c*c+T*T);A<xt&&(A=xt);const F=(g.type===i.type?kn:r)*e/(A*A),W=c/A*F,V=T/A*F;g.vx-=W,g.vy-=V,i.vx+=W,i.vy+=V}for(const o of l){const n=u.get(o.sourceId),g=u.get(o.targetId);if(!n||!g)continue;const i=g.x-n.x,c=g.y-n.y,T=Math.sqrt(i*i+c*c);if(T===0)continue;const A=n.type===g.type?Hn*Ze.spacing:Yn*Ze.spacing,E=vo*(T-A)*e,F=i/T*E,W=c/T*E;n.vx+=F,n.vy+=W,g.vx-=F,g.vy-=W}for(const o of s)o.vx-=o.x*Nn*e,o.vy-=o.y*Nn*e;const d=new Map;for(const o of s){const n=d.get(o.type)??{x:0,y:0,count:0};n.x+=o.x,n.y+=o.y,n.count++,d.set(o.type,n)}for(const o of d.values())o.x/=o.count,o.y/=o.count;for(const o of s){const n=d.get(o.type);o.vx+=(n.x-o.x)*Ze.clusterStrength*e,o.vy+=(n.y-o.y)*Ze.clusterStrength*e}for(const o of s){if(o.pinned){o.vx=0,o.vy=0;continue}o.vx*=Sn,o.vy*=Sn;const n=Math.sqrt(o.vx*o.vx+o.vy*o.vy);n>_t&&(o.vx=o.vx/n*_t,o.vy=o.vy/n*_t),o.x+=o.vx,o.y+=o.vy}return e*.995}const In=["#d4a27f","#c17856","#b07a5e","#d4956b","#a67c5a","#cc9e7c","#c4866a","#cb8e6c","#b8956e","#a88a70","#d9b08c","#c4a882","#e8b898","#b5927a","#a8886e","#d1a990"],Mn=new Map;function Ae(t){const e=Mn.get(t);if(e)return e;let s=0;for(let u=0;u<t.length;u++)s=(s<<5)-s+t.charCodeAt(u)|0;const l=In[Math.abs(s)%In.length];return Mn.set(t,l),l}class No{constructor(e){At(this,"cells",new Map);At(this,"cellSize");At(this,"invCell");this.cellSize=e,this.invCell=1/e}key(e,s){const l=e+32768|0,u=s+32768|0;return l*73856093^u*19349663}clear(){this.cells.clear()}insert(e){const s=Math.floor(e.x*this.invCell),l=Math.floor(e.y*this.invCell),u=this.key(s,l),r=this.cells.get(u);r?r.push(e):this.cells.set(u,[e])}rebuild(e){this.cells.clear();for(const s of e)this.insert(s)}query(e,s,l){const u=l*l,r=Math.floor((e-l)*this.invCell),d=Math.floor((e+l)*this.invCell),o=Math.floor((s-l)*this.invCell),n=Math.floor((s+l)*this.invCell);let g=null,i=u;for(let c=r;c<=d;c++)for(let T=o;T<=n;T++){const A=this.cells.get(this.key(c,T));if(A)for(const E of A){const F=E.x-e,W=E.y-s,V=F*F+W*W;V<=i&&(i=V,g=E)}}return g}}const pt=new Map,Lo=2e3;function Io(t,e,s){return`${t}|${e}|${s}`}const Mo=new OffscreenCanvas(1,1),Tn=Mo.getContext("2d");function To(t,e,s){Tn.font=e;const l=Tn.measureText(t),u=Math.ceil(l.width)+2,r=Math.ceil(l.actualBoundingBoxAscent+l.actualBoundingBoxDescent)+4,d=new OffscreenCanvas(u,r),o=d.getContext("2d");return o.font=e,o.fillStyle=s,o.textAlign="left",o.textBaseline="top",o.fillText(t,1,1),{canvas:d,width:u,height:r}}function An(t,e,s,l,u,r,d){const o=Io(e,u,r);let n=pt.get(o);if(!n){if(pt.size>=Lo){const c=pt.keys().next().value;c!==void 0&&pt.delete(c)}n=To(e,u,r),pt.set(o,n)}const g=s-n.width/2,i=d==="top"?l:l-n.height;t.drawImage(n.canvas,g,i)}function Ao(){pt.clear()}function we(t){return getComputedStyle(document.documentElement).getPropertyValue(t).trim()}const Ue=20,Yt=.001,Po={hideBadges:.4,hideLabels:.25,hideEdgeLabels:.35,smallNodes:.2,hideArrows:.15,dotNodes:.1,hullsOnly:.05},Ro={zoomFactor:1.3,zoomMin:.05,zoomMax:10,panAnimationMs:300};function Rt(t,e,s,l,u,r=100){const d=(t-s.x)*s.scale,o=(e-s.y)*s.scale;return d>=-r&&d<=l+r&&o>=-r&&o<=u+r}function Bo(t,e,s,l){const u={...Po,...(l==null?void 0:l.lod)??{}},r={...Ro,...(l==null?void 0:l.navigation)??{}},d={pulseSpeed:.02,...(l==null?void 0:l.walk)??{}},o=t.querySelector("canvas"),n=o.getContext("2d"),g=window.devicePixelRatio||1;let i={x:0,y:0,scale:1},c=null,T=1,A=0,E=new Set,F=null,W=!0,V=!0,_=!0,X=!0,Y="idle",K=[],q=0,me=0,U=null,pe=new Set;const Ee=5;let te=null,G=null,ye=1,Ce=null,se=null,ge=null,be=!1,p=[],y=0,C=0;const m=400,v=new No(Ue*2);let S=0;function h(){ce(),S||(S=requestAnimationFrame(()=>{S=0,Xe()}))}const I=150;let w=null,N=!1;function L(){if(!w)try{w=new Worker(new URL("/assets/layout-worker-4xak23M6.js",import.meta.url),{type:"module"}),w.onmessage=b,w.onerror=()=>{N=!1,w=null,j()}}catch{return N=!1,null}return w}function b(f){const k=f.data;if(k.type==="tick"&&c){const B=k.positions,D=c.nodes;for(let H=0;H<D.length;H++)D[H].x=B[H*4],D[H].y=B[H*4+1],D[H].vx=B[H*4+2],D[H].vy=B[H*4+3];T=k.alpha,v.rebuild(D),Xe()}k.type==="settled"&&(T=0,be&&p.length>0&&!a&&(a=requestAnimationFrame(x)))}let M=null,$=null,Q=!0;function ce(){Q=!0}let re=null,ue=null;const ve=r.panAnimationMs;function $e(){o.width=o.clientWidth*g,o.height=o.clientHeight*g,ce(),h()}const Qe=new ResizeObserver($e);Qe.observe(t),$e();function Re(f,k){return[f/i.scale+i.x,k/i.scale+i.y]}function et(f,k){if(!c)return null;const[B,D]=Re(f,k);return v.query(B,D,Ue)}function ct(){if(!U)return;n.save();const f=Math.min(U.x1,U.x2),k=Math.max(U.x1,U.x2),B=Math.min(U.y1,U.y2),D=Math.max(U.y1,U.y2);n.strokeStyle=we("--accent")||"#d4a27f",n.fillStyle=we("--accent")||"#d4a27f",n.globalAlpha=.12,n.fillRect(f,B,k-f,D-B),n.globalAlpha=.8,n.lineWidth=1/Math.max(i.scale,.5),n.setLineDash([6/Math.max(i.scale,.5),4/Math.max(i.scale,.5)]),n.strokeRect(f,B,k-f,D-B),n.setLineDash([]),n.restore()}function Ot(){if(!c)return;y+=d.pulseSpeed;const f=new Set(p);n.save(),n.setTransform(g,0,0,g,0,0),M&&(n.clearRect(0,0,o.clientWidth,o.clientHeight),n.drawImage(M,0,0,o.clientWidth,o.clientHeight)),n.save(),n.translate(-i.x*i.scale,-i.y*i.scale),n.scale(i.scale,i.scale);const k=we("--canvas-walk-edge")||"#1a1a1a",B=[];for(const z of c.edges){if(!f.has(z.sourceId)||!f.has(z.targetId)||z.sourceId===z.targetId)continue;const O=c.nodeMap.get(z.sourceId),J=c.nodeMap.get(z.targetId);!O||!J||B.push(O.x,O.y,J.x,J.y)}if(B.length>0){n.beginPath();for(let z=0;z<B.length;z+=4)n.moveTo(B[z],B[z+1]),n.lineTo(B[z+2],B[z+3]);n.strokeStyle=k,n.lineWidth=3,n.globalAlpha=.5+.5*Math.sin(y),n.stroke(),n.globalAlpha=1}const D=i.scale<u.smallNodes?Ue*.5:Ue,H=we("--accent")||"#d4a27f";for(const z of p){const O=c.nodeMap.get(z);if(!O||!Rt(O.x,O.y,i,o.clientWidth,o.clientHeight))continue;const J=z===p[p.length-1],Z=.5+.5*Math.sin(y);n.strokeStyle=H,n.lineWidth=J?3:2,n.globalAlpha=J?.5+.5*Z:.3+.4*Z,n.beginPath(),n.arc(O.x,O.y,D+(J?6:4),0,Math.PI*2),n.stroke()}n.globalAlpha=1,ct(),n.restore(),X&&c.nodes.length>1&&Wt(),n.restore()}function Xe(){var ln;if(!c){n.clearRect(0,0,o.width,o.height);return}if(!Q&&M&&be&&p.length>0&&T<Yt){Ot();return}const f=T<Yt&&be&&p.length>0;be&&p.length>0&&(y+=d.pulseSpeed);const k=be&&!f?new Set(p):null,B=we("--canvas-edge"),D=we("--canvas-edge-highlight"),H=we("--canvas-edge-dim"),z=we("--canvas-edge-label"),O=we("--canvas-edge-label-highlight"),J=we("--canvas-edge-label-dim"),Z=we("--canvas-arrow"),le=we("--canvas-arrow-highlight"),fe=we("--canvas-node-label"),ke=we("--canvas-node-label-dim"),Se=we("--canvas-type-badge"),Te=we("--canvas-type-badge-dim"),Be=we("--canvas-selection-border"),je=we("--canvas-node-border");if(n.save(),n.setTransform(g,0,0,g,0,0),n.clearRect(0,0,o.clientWidth,o.clientHeight),n.save(),n.translate(-i.x*i.scale,-i.y*i.scale),n.scale(i.scale,i.scale),_&&i.scale>=u.smallNodes){const ee=new Map;for(const Pe of c.nodes){if(F!==null&&!F.has(Pe.id))continue;const Oe=ee.get(Pe.type)??[];Oe.push(Pe),ee.set(Pe.type,Oe)}for(const[Pe,Oe]of ee){if(Oe.length<2)continue;const st=Ae(Pe),nt=Ue*2.5;let He=1/0,qe=1/0,Fe=-1/0,Ke=-1/0;for(const We of Oe)We.x<He&&(He=We.x),We.y<qe&&(qe=We.y),We.x>Fe&&(Fe=We.x),We.y>Ke&&(Ke=We.y);n.beginPath();const oe=(Fe-He)/2+nt,Ie=(Ke-qe)/2+nt,Ne=(He+Fe)/2,ze=(qe+Ke)/2;n.ellipse(Ne,ze,oe,Ie,0,0,Math.PI*2),n.fillStyle=st,n.globalAlpha=.05,n.fill(),n.strokeStyle=st,n.globalAlpha=.12,n.lineWidth=1,n.setLineDash([4,4]),n.stroke(),n.setLineDash([]),n.globalAlpha=1}}let Ye=null;if(E.size>0){Ye=new Set;for(const ee of c.edges)E.has(ee.sourceId)&&Ye.add(ee.targetId),E.has(ee.targetId)&&Ye.add(ee.sourceId)}const tt=we("--accent")||"#d4a27f",_e=we("--canvas-walk-edge")||"#1a1a1a",it=i.scale>=u.hideArrows,Mt=V&&i.scale>=u.hideEdgeLabels;if(W){const ee=[],Pe=[],Oe=[],st=[],nt=[],He=[];for(const oe of c.edges){const Ie=c.nodeMap.get(oe.sourceId),Ne=c.nodeMap.get(oe.targetId);if(!Ie||!Ne||!Rt(Ie.x,Ie.y,i,o.clientWidth,o.clientHeight,200)&&!Rt(Ne.x,Ne.y,i,o.clientWidth,o.clientHeight,200))continue;const ze=F===null||F.has(oe.sourceId),We=F===null||F.has(oe.targetId),rn=ze&&We;if(F!==null&&!ze&&!We)continue;const jt=E.size>0&&(E.has(oe.sourceId)||E.has(oe.targetId))||F!==null&&rn,dn=F!==null&&!rn,pn=k!==null&&k.has(oe.sourceId)&&k.has(oe.targetId),un=ge?te==null?void 0:te.edges.find(Tt=>Tt.sourceId===oe.sourceId&&Tt.targetId===oe.targetId||Tt.targetId===oe.sourceId&&Tt.sourceId===oe.targetId):null,mn=!!(ge&&un&&ge.edgeIds.has(un.id));if(oe.sourceId===oe.targetId){St(Ie,oe.type,jt,B,D,z,O);continue}(mn?nt:pn?st:jt?Pe:dn?Oe:ee).push(Ie.x,Ie.y,Ne.x,Ne.y),(it||Mt)&&He.push({sx:Ie.x,sy:Ie.y,tx:Ne.x,ty:Ne.y,type:oe.type,highlighted:jt,edgeDimmed:dn,isPathEdge:mn,isWalkEdge:pn})}const qe=it?1.5:1,Ke=[{lines:ee,color:B,width:qe,alpha:1},{lines:Oe,color:H,width:qe,alpha:1},{lines:Pe,color:D,width:it?2.5:1,alpha:1},{lines:nt,color:tt,width:3,alpha:1},{lines:st,color:_e,width:3,alpha:.5+.5*Math.sin(y)}];for(const oe of Ke)if(oe.lines.length!==0){n.beginPath();for(let Ie=0;Ie<oe.lines.length;Ie+=4)n.moveTo(oe.lines[Ie],oe.lines[Ie+1]),n.lineTo(oe.lines[Ie+2],oe.lines[Ie+3]);n.strokeStyle=oe.color,n.lineWidth=oe.width,n.globalAlpha=oe.alpha,n.stroke()}n.globalAlpha=1;for(const oe of He)if(it&&ut(oe.sx,oe.sy,oe.tx,oe.ty,oe.highlighted||oe.isPathEdge,Z,le),Mt){const Ie=(oe.sx+oe.tx)/2,Ne=(oe.sy+oe.ty)/2;n.fillStyle=oe.highlighted?O:oe.edgeDimmed?J:z,n.font="9px system-ui, sans-serif",n.textAlign="center",n.textBaseline="bottom",n.fillText(oe.type,Ie,Ne-4)}}const Ut=performance.now()-C,Le=Math.min(1,Ut/m),Ve=1-(1-Le)*(1-Le),Je=Le<1,cn=i.scale<u.hullsOnly,Vn=!cn&&i.scale<u.dotNodes;if(!cn)for(const ee of c.nodes){if(!Rt(ee.x,ee.y,i,o.clientWidth,o.clientHeight))continue;const Pe=Ae(ee.type);if(Vn){const Ne=F!==null&&!F.has(ee.id);n.fillStyle=Pe;const ze=Ne?.1:.8;n.globalAlpha=Je?ze*Ve:ze,n.fillRect(ee.x-2,ee.y-2,4,4);continue}const Oe=E.has(ee.id),st=Ye!==null&&Ye.has(ee.id),nt=F!==null&&!F.has(ee.id),He=nt||E.size>0&&!Oe&&!st,qe=i.scale<u.smallNodes?Ue*.5:Ue,Fe=Je?qe*Ve:qe;if(k!=null&&k.has(ee.id)){const Ne=p[p.length-1]===ee.id,ze=.5+.5*Math.sin(y),We=we("--accent")||"#d4a27f";n.save(),n.strokeStyle=We,n.lineWidth=Ne?3:2,n.globalAlpha=Ne?.5+.5*ze:.3+.4*ze,n.beginPath(),n.arc(ee.x,ee.y,Fe+(Ne?6:4),0,Math.PI*2),n.stroke(),n.restore()}Oe&&(n.save(),n.shadowColor=Pe,n.shadowBlur=20,n.beginPath(),n.arc(ee.x,ee.y,Fe+3,0,Math.PI*2),n.fillStyle=Pe,n.globalAlpha=.3,n.fill(),n.restore()),n.beginPath(),n.arc(ee.x,ee.y,Fe,0,Math.PI*2),n.fillStyle=Pe;const Ke=nt?.1:He?.3:1;n.globalAlpha=Je?Ke*Ve:Ke,n.fill(),n.strokeStyle=Oe?Be:je,n.lineWidth=Oe?3:1.5,n.stroke(),n.globalAlpha=1,ee.pinned&&(n.save(),n.strokeStyle=je,n.globalAlpha=.55,n.lineWidth=1,n.setLineDash([3,3]),n.beginPath(),n.arc(ee.x,ee.y,Fe+4,0,Math.PI*2),n.stroke(),n.setLineDash([]),n.restore()),ge&&ge.nodeIds.has(ee.id)&&!Oe&&(n.save(),n.shadowColor=we("--accent")||"#d4a27f",n.shadowBlur=15,n.beginPath(),n.arc(ee.x,ee.y,Fe+2,0,Math.PI*2),n.strokeStyle=we("--accent")||"#d4a27f",n.globalAlpha=.5,n.lineWidth=2,n.stroke(),n.restore());const oe=te==null?void 0:te.nodes.find(Ne=>Ne.id===ee.id);if(((ln=oe==null?void 0:oe.properties)==null?void 0:ln._starred)===!0&&(n.fillStyle="#ffd700",n.font="10px system-ui, sans-serif",n.textAlign="left",n.textBaseline="bottom",n.fillText("★",ee.x+Fe-2,ee.y-Fe+2)),i.scale>=u.hideLabels){const Ne=ee.label.length>24?ee.label.slice(0,22)+"...":ee.label,ze=He?ke:fe;An(n,Ne,ee.x,ee.y+Fe+4,"11px system-ui, sans-serif",ze,"top")}if(i.scale>=u.hideBadges){const Ne=He?Te:Se;An(n,ee.type,ee.x,ee.y-Fe-3,"9px system-ui, sans-serif",Ne,"bottom")}n.globalAlpha=1}if(n.restore(),n.restore(),f){const ee=o.width,Pe=o.height;(!M||M.width!==ee||M.height!==Pe)&&(M=new OffscreenCanvas(ee,Pe),$=M.getContext("2d")),$&&($.clearRect(0,0,ee,Pe),$.drawImage(o,0,0),Q=!1),Ot();return}X&&c.nodes.length>1&&Wt(),U&&(n.save(),n.setTransform(g,0,0,g,0,0),n.translate(-i.x*i.scale,-i.y*i.scale),n.scale(i.scale,i.scale),ct(),n.restore())}function Wt(){if(!c)return;const f=140,k=100,B=8,D=o.clientWidth-f-16,H=o.clientHeight-k-16;let z=1/0,O=1/0,J=-1/0,Z=-1/0;for(const Le of c.nodes)Le.x<z&&(z=Le.x),Le.y<O&&(O=Le.y),Le.x>J&&(J=Le.x),Le.y>Z&&(Z=Le.y);const le=J-z||1,fe=Z-O||1,ke=Math.min((f-B*2)/le,(k-B*2)/fe),Se=D+B+(f-B*2-le*ke)/2,Te=H+B+(k-B*2-fe*ke)/2;n.save(),n.setTransform(g,0,0,g,0,0),n.fillStyle=we("--bg-surface")||"#1a1a1a",n.globalAlpha=.85,n.beginPath(),n.roundRect(D,H,f,k,8),n.fill(),n.strokeStyle=we("--border")||"#2a2a2a",n.globalAlpha=1,n.lineWidth=1,n.stroke(),n.globalAlpha=.15,n.strokeStyle=we("--canvas-edge")||"#555",n.lineWidth=.5;for(const Le of c.edges){const Ve=c.nodeMap.get(Le.sourceId),Je=c.nodeMap.get(Le.targetId);!Ve||!Je||Le.sourceId===Le.targetId||(n.beginPath(),n.moveTo(Se+(Ve.x-z)*ke,Te+(Ve.y-O)*ke),n.lineTo(Se+(Je.x-z)*ke,Te+(Je.y-O)*ke),n.stroke())}n.globalAlpha=.8;for(const Le of c.nodes){const Ve=Se+(Le.x-z)*ke,Je=Te+(Le.y-O)*ke;n.beginPath(),n.arc(Ve,Je,2,0,Math.PI*2),n.fillStyle=Ae(Le.type),n.fill()}const Be=i.x,je=i.y,Ye=i.x+o.clientWidth/i.scale,tt=i.y+o.clientHeight/i.scale,_e=Se+(Be-z)*ke,it=Te+(je-O)*ke,Mt=(Ye-Be)*ke,Ut=(tt-je)*ke;n.globalAlpha=.3,n.strokeStyle=we("--accent")||"#d4a27f",n.lineWidth=1.5,n.strokeRect(Math.max(D,Math.min(_e,D+f)),Math.max(H,Math.min(it,H+k)),Math.min(Mt,f),Math.min(Ut,k)),n.globalAlpha=1,n.restore()}function ut(f,k,B,D,H,z,O){const J=Math.atan2(D-k,B-f),Z=B-Math.cos(J)*Ue,le=D-Math.sin(J)*Ue,fe=8;n.beginPath(),n.moveTo(Z,le),n.lineTo(Z-fe*Math.cos(J-.4),le-fe*Math.sin(J-.4)),n.lineTo(Z-fe*Math.cos(J+.4),le-fe*Math.sin(J+.4)),n.closePath(),n.fillStyle=H?O:z,n.fill()}function St(f,k,B,D,H,z,O){const J=f.x+Ue+15,Z=f.y-Ue-15;n.beginPath(),n.arc(J,Z,15,0,Math.PI*2),n.strokeStyle=B?H:D,n.lineWidth=B?2.5:1.5,n.stroke(),V&&(n.fillStyle=B?O:z,n.font="9px system-ui, sans-serif",n.textAlign="center",n.fillText(k,J,Z-18))}function mt(){if(!re||!ue)return;const f=performance.now()-ue.time,k=Math.min(f/ve,1),B=1-Math.pow(1-k,3);i.x=ue.x+(re.x-ue.x)*B,i.y=ue.y+(re.y-ue.y)*B,ce(),Xe(),k<1?requestAnimationFrame(mt):(re=null,ue=null)}let a=0;function x(){if(!be||p.length===0){a=0;return}Xe(),a=requestAnimationFrame(x)}function R(){if(!c||c.nodes.length===0)return;let f=1/0,k=1/0,B=-1/0,D=-1/0;for(const le of c.nodes)le.x<f&&(f=le.x),le.y<k&&(k=le.y),le.x>B&&(B=le.x),le.y>D&&(D=le.y);const H=Ue*4,z=B-f+H*2,O=D-k+H*2,J=o.clientWidth/Math.max(z,1),Z=o.clientHeight/Math.max(O,1);i.scale=Math.min(J,Z,2),i.x=(f+B)/2-o.clientWidth/(2*i.scale),i.y=(k+D)/2-o.clientHeight/(2*i.scale),h()}function j(){if(!c||T<Yt){A=0,be&&p.length>0&&!a&&(a=requestAnimationFrame(x));return}T=So(c,T),v.rebuild(c.nodes),Xe(),A=requestAnimationFrame(j)}let ne=!1,de=0,ie=0,he=0,Me=0;o.addEventListener("mousedown",f=>{Y="pending",ne=!1,de=f.clientX,ie=f.clientY,he=f.clientX,Me=f.clientY;const k=o.getBoundingClientRect(),B=f.clientX-k.left,D=f.clientY-k.top,H=et(B,D);if(H&&!be){if(K=[],E.has(H.id)&&E.size>1)for(const J of E){const Z=c==null?void 0:c.nodeMap.get(J);Z&&K.push({node:Z,startX:Z.x,startY:Z.y})}else K.push({node:H,startX:H.x,startY:H.y});const[z,O]=Re(B,D);q=z,me=O}else if(!H&&f.shiftKey){const[z,O]=Re(B,D);U={x1:z,y1:O,x2:z,y2:O}}}),o.addEventListener("mousemove",f=>{if(Y==="idle")return;const k=f.clientX-de,B=f.clientY-ie,D=Math.abs(f.clientX-he),H=Math.abs(f.clientY-Me);if(Y==="pending"&&(D>Ee||H>Ee)&&(ne=!0,K.length>0?(Y="nodeDrag",N&&w&&w.postMessage({type:"stop"})):U?Y="rubberBand":Y="pan"),Y==="nodeDrag"){const z=o.getBoundingClientRect(),O=f.clientX-z.left,J=f.clientY-z.top,[Z,le]=Re(O,J),fe=Z-q,ke=le-me;for(const Se of K)Se.node.x=Se.startX+fe,Se.node.y=Se.startY+ke,Se.node.vx=0,Se.node.vy=0,Se.node.pinned=!0,pe.add(Se.node.id);v.rebuild((c==null?void 0:c.nodes)??[]),h()}else if(Y==="rubberBand"&&U){const z=o.getBoundingClientRect(),O=f.clientX-z.left,J=f.clientY-z.top,[Z,le]=Re(O,J);U.x2=Z,U.y2=le,h()}else Y==="pan"&&(i.x-=k/i.scale,i.y-=B/i.scale,h());de=f.clientX,ie=f.clientY}),o.addEventListener("mouseup",f=>{const k=Y==="nodeDrag",B=Y==="rubberBand";if(K.map(Z=>Z.node.id),k){if(N&&w&&c){const Z=K.map(le=>({id:le.node.id,x:le.node.x,y:le.node.y}));w.postMessage({type:"pin",updates:Z}),w.postMessage({type:"resume",alpha:.5})}else T=Math.max(T,.5),A||j();Y="idle",K=[],h();return}if(B&&U&&c){const Z=Math.min(U.x1,U.x2),le=Math.max(U.x1,U.x2),fe=Math.min(U.y1,U.y2),ke=Math.max(U.y1,U.y2);f.shiftKey||E.clear();for(const Te of c.nodes)Te.x>=Z&&Te.x<=le&&Te.y>=fe&&Te.y<=ke&&E.add(Te.id);const Se=[...E];e==null||e(Se.length>0?Se:null),U=null,Y="idle",h();return}if(Y==="pan"){Y="idle";return}if(Y="idle",U=null,ne)return;const D=o.getBoundingClientRect(),H=f.clientX-D.left,z=f.clientY-D.top,O=et(H,z),J=f.ctrlKey||f.metaKey||f.shiftKey;if(be&&G&&O&&c){const Z=p.length>0?p[p.length-1]:G[0],le=new Set([Z]),fe=[{id:Z,path:[Z]}];let ke=null;for(;fe.length>0;){const{id:je,path:Ye}=fe.shift();if(je===O.id){ke=Ye;break}for(const tt of c.edges){let _e=null;tt.sourceId===je?_e=tt.targetId:tt.targetId===je&&(_e=tt.sourceId),_e&&!le.has(_e)&&(le.add(_e),fe.push({id:_e,path:[...Ye,_e]}))}}if(!ke)return;for(const je of ke.slice(1))p.includes(je)||p.push(je);G=[O.id];const Se=Math.max(1,ye);ye=Se;const Te=Ln(te,[O.id],Se);cancelAnimationFrame(A),w&&w.postMessage({type:"stop"}),c=Ht(Te),v.rebuild(c.nodes),T=1,E=new Set([O.id]),F=null,i={x:0,y:0,scale:1},N=Te.nodes.length>=I;const Be=N?L():null;Be?Be.postMessage({type:"start",data:Te}):(N=!1,j()),setTimeout(()=>{c&&R()},300),s==null||s({seedNodeIds:[O.id],hops:Se,totalNodes:Te.nodes.length}),e==null||e([O.id]);return}if(O){J?E.has(O.id)?E.delete(O.id):E.add(O.id):E.size===1&&E.has(O.id)?E.clear():(E.clear(),E.add(O.id));const Z=[...E];e==null||e(Z.length>0?Z:null)}else E.clear(),e==null||e(null);h()}),o.addEventListener("mouseleave",()=>{if(Y==="nodeDrag")if(N&&w&&K.length>0){const f=K.map(k=>({id:k.node.id,x:k.node.x,y:k.node.y}));w.postMessage({type:"pin",updates:f}),w.postMessage({type:"resume",alpha:.5})}else T=Math.max(T,.5),A||j();Y==="rubberBand"&&(U=null,h()),Y="idle",K=[]}),o.addEventListener("wheel",f=>{f.preventDefault();const k=o.getBoundingClientRect(),B=f.clientX-k.left,D=f.clientY-k.top,[H,z]=Re(B,D),O=f.ctrlKey?1-f.deltaY*.01:f.deltaY>0?.9:1.1;i.scale=Math.max(r.zoomMin,Math.min(r.zoomMax,i.scale*O)),i.x=H-B/i.scale,i.y=z-D/i.scale,h()},{passive:!1});let xe=[],Ge=0,Nt=1,ht=0,Lt=0,ft=!1;o.addEventListener("touchstart",f=>{f.preventDefault(),xe=Array.from(f.touches),xe.length===2?(Ge=an(xe[0],xe[1]),Nt=i.scale):xe.length===1&&(de=xe[0].clientX,ie=xe[0].clientY,ht=xe[0].clientX,Lt=xe[0].clientY,ft=!1)},{passive:!1}),o.addEventListener("touchmove",f=>{f.preventDefault();const k=Array.from(f.touches);if(k.length===2&&xe.length===2){const D=an(k[0],k[1])/Ge;i.scale=Math.max(r.zoomMin,Math.min(r.zoomMax,Nt*D)),h()}else if(k.length===1){const B=k[0].clientX-de,D=k[0].clientY-ie;(Math.abs(k[0].clientX-ht)>10||Math.abs(k[0].clientY-Lt)>10)&&(ft=!0),i.x-=B/i.scale,i.y-=D/i.scale,de=k[0].clientX,ie=k[0].clientY,h()}xe=k},{passive:!1}),o.addEventListener("touchend",f=>{if(f.preventDefault(),ft||f.changedTouches.length!==1)return;const k=f.changedTouches[0],B=o.getBoundingClientRect(),D=k.clientX-B.left,H=k.clientY-B.top,z=et(D,H);if(z){E.size===1&&E.has(z.id)?E.clear():(E.clear(),E.add(z.id));const O=[...E];e==null||e(O.length>0?O:null)}else E.clear(),e==null||e(null);h()},{passive:!1}),o.addEventListener("gesturestart",f=>f.preventDefault()),o.addEventListener("gesturechange",f=>f.preventDefault());function an(f,k){const B=f.clientX-k.clientX,D=f.clientY-k.clientY;return Math.sqrt(B*B+D*D)}const gt=document.createElement("div");gt.className="zoom-controls";const yt=document.createElement("button");yt.className="zoom-btn",yt.textContent="+",yt.title="Zoom in",yt.addEventListener("click",()=>{const f=o.clientWidth/2,k=o.clientHeight/2,[B,D]=Re(f,k);i.scale=Math.min(r.zoomMax,i.scale*r.zoomFactor),i.x=B-f/i.scale,i.y=D-k/i.scale,h()});const Ct=document.createElement("button");Ct.className="zoom-btn",Ct.textContent="−",Ct.title="Zoom out",Ct.addEventListener("click",()=>{const f=o.clientWidth/2,k=o.clientHeight/2,[B,D]=Re(f,k);i.scale=Math.max(r.zoomMin,i.scale/r.zoomFactor),i.x=B-f/i.scale,i.y=D-k/i.scale,h()});const bt=document.createElement("button");bt.className="zoom-btn",bt.textContent="○",bt.title="Reset zoom",bt.addEventListener("click",()=>{if(c){if(i={x:0,y:0,scale:1},c.nodes.length>0){let f=1/0,k=1/0,B=-1/0,D=-1/0;for(const O of c.nodes)O.x<f&&(f=O.x),O.y<k&&(k=O.y),O.x>B&&(B=O.x),O.y>D&&(D=O.y);const H=(f+B)/2,z=(k+D)/2;i.x=H-o.clientWidth/2,i.y=z-o.clientHeight/2}h()}}),gt.appendChild(yt),gt.appendChild(bt),gt.appendChild(Ct),t.appendChild(gt);const De=document.createElement("div");De.className="node-tooltip",De.style.display="none",t.appendChild(De);let It=null,ot=null;return o.addEventListener("mousemove",f=>{if(Y!=="idle"&&Y!=="pending"){De.style.display!=="none"&&(De.style.display="none",It=null);return}const k=o.getBoundingClientRect(),B=f.clientX-k.left,D=f.clientY-k.top,H=et(B,D),z=(H==null?void 0:H.id)??null;z!==It?(It=z,De.style.display="none",ot&&clearTimeout(ot),ot=null,z&&H&&(ot=setTimeout(()=>{if(!c||!te)return;const O=c.edges.filter(J=>J.sourceId===z||J.targetId===z).length;De.textContent=`${H.label} · ${H.type} · ${O} edge${O!==1?"s":""}`,De.style.left=`${f.clientX-k.left+12}px`,De.style.top=`${f.clientY-k.top-8}px`,De.style.display="block"},200))):z&&De.style.display==="block"&&(De.style.left=`${f.clientX-k.left+12}px`,De.style.top=`${f.clientY-k.top-8}px`)}),o.addEventListener("mouseleave",()=>{De.style.display="none",It=null,ot&&clearTimeout(ot),ot=null}),{loadGraph(f){if(cancelAnimationFrame(A),w&&w.postMessage({type:"stop"}),Ao(),te=f,G=null,Ce=null,se=null,C=performance.now(),c=Ht(f),v.rebuild(c.nodes),T=1,E=new Set,F=null,pe.clear(),Y="idle",K=[],U=null,i={x:0,y:0,scale:1},c.nodes.length>0){let B=1/0,D=1/0,H=-1/0,z=-1/0;for(const fe of c.nodes)fe.x<B&&(B=fe.x),fe.y<D&&(D=fe.y),fe.x>H&&(H=fe.x),fe.y>z&&(z=fe.y);const O=(B+H)/2,J=(D+z)/2,Z=o.clientWidth,le=o.clientHeight;i.x=O-Z/2,i.y=J-le/2}N=f.nodes.length>=I;const k=N?L():null;k?k.postMessage({type:"start",data:f}):(N=!1,j())},setFilteredNodeIds(f){F=f,h()},releaseAllPins(){if(!c)return!1;let f=!1;for(const k of c.nodes)k.pinned&&(f=!0,k.pinned=!1);return pe.clear(),Y="idle",K=[],U=null,f&&(N&&w?w.postMessage({type:"unpin",ids:"all"}):(T=Math.max(T,.5),A||j()),h()),f},hasPinnedNodes(){if(!c)return!1;for(const f of c.nodes)if(f.pinned)return!0;return!1},clearSelection(){E.size!==0&&(E.clear(),e==null||e(null),h())},getSelectedNodeIds(){return[...E]},panToNode(f){this.panToNodes([f])},panToNodes(f){if(!c||f.length===0)return;const k=f.map(H=>c.nodeMap.get(H)).filter(Boolean);if(k.length===0)return;E=new Set(f),e==null||e(f);const B=o.clientWidth,D=o.clientHeight;if(k.length===1)ue={x:i.x,y:i.y,time:performance.now()},re={x:k[0].x-B/(2*i.scale),y:k[0].y-D/(2*i.scale)};else{let H=1/0,z=1/0,O=-1/0,J=-1/0;for(const Be of k)Be.x<H&&(H=Be.x),Be.y<z&&(z=Be.y),Be.x>O&&(O=Be.x),Be.y>J&&(J=Be.y);const Z=Ue*4,le=O-H+Z*2,fe=J-z+Z*2,ke=Math.min(B/le,D/fe,i.scale);i.scale=ke;const Se=(H+O)/2,Te=(z+J)/2;ue={x:i.x,y:i.y,time:performance.now()},re={x:Se-B/(2*i.scale),y:Te-D/(2*i.scale)}}mt()},setEdges(f){W=f,h()},setEdgeLabels(f){V=f,h()},setTypeHulls(f){_=f,h()},setMinimap(f){X=f,h()},centerView(){R()},panBy(f,k){i.x+=f/i.scale,i.y+=k/i.scale,h()},zoomBy(f){const k=o.clientWidth/2,B=o.clientHeight/2,[D,H]=Re(k,B);i.scale=Math.max(r.zoomMin,Math.min(r.zoomMax,i.scale*f)),i.x=D-k/i.scale,i.y=H-B/i.scale,h()},reheat(){N&&w?w.postMessage({type:"params",params:wt()}):(T=.5,cancelAnimationFrame(A),j())},exportImage(f){if(!c)return"";const k=o.width,B=o.height;if(f==="png"){const O=document.createElement("canvas");O.width=k,O.height=B;const J=O.getContext("2d");return J.fillStyle=we("--bg")||"#141414",J.fillRect(0,0,k,B),J.drawImage(o,0,0),Gn(J,k,B),O.toDataURL("image/png")}const D=o.toDataURL("image/png"),H=Math.max(16,Math.round(k/80)),z=`<svg xmlns="http://www.w3.org/2000/svg" width="${k}" height="${B}">
3
+ <image href="${D}" width="${k}" height="${B}"/>
4
+ <text x="${k-20}" y="${B-16}" text-anchor="end" font-family="system-ui, sans-serif" font-size="${H}" fill="#ffffff" opacity="0.4">backpackontology.com</text>
5
+ </svg>`;return"data:image/svg+xml;charset=utf-8,"+encodeURIComponent(z)},enterFocus(f,k){if(!te||!c)return;for(const H of c.nodes)H.pinned=!1;pe.clear(),Y="idle",K=[],U=null,G||(Ce=c,se={...i}),G=f,ye=k;const B=Ln(te,f,k);cancelAnimationFrame(A),w&&w.postMessage({type:"stop"}),c=Ht(B),v.rebuild(c.nodes),T=1,E=new Set(f),F=null,i={x:0,y:0,scale:1},N=B.nodes.length>=I;const D=N?L():null;D?D.postMessage({type:"start",data:B}):(N=!1,j()),setTimeout(()=>{!c||!G||R()},300),s==null||s({seedNodeIds:f,hops:k,totalNodes:B.nodes.length})},exitFocus(){if(!(!G||!Ce)){cancelAnimationFrame(A),w&&w.postMessage({type:"stop"}),c=Ce;for(const f of c.nodes)f.pinned=!1;pe.clear(),Y="idle",K=[],U=null,v.rebuild(c.nodes),i=se??{x:0,y:0,scale:1},G=null,Ce=null,se=null,E=new Set,F=null,h(),s==null||s(null)}},isFocused(){return G!==null},getFocusInfo(){return!G||!c?null:{seedNodeIds:G,hops:ye,totalNodes:c.nodes.length}},findPath(f,k){if(!c)return null;const B=new Set([f]),D=[{nodeId:f,path:[f],edges:[]}];for(;D.length>0;){const{nodeId:H,path:z,edges:O}=D.shift();if(H===k)return{nodeIds:z,edgeIds:O};for(const J of c.edges){let Z=null;if(J.sourceId===H?Z=J.targetId:J.targetId===H&&(Z=J.sourceId),Z&&!B.has(Z)){B.add(Z);const le=te==null?void 0:te.edges.find(fe=>fe.sourceId===J.sourceId&&fe.targetId===J.targetId||fe.targetId===J.sourceId&&fe.sourceId===J.targetId);D.push({nodeId:Z,path:[...z,Z],edges:[...O,(le==null?void 0:le.id)??""]})}}}return null},setHighlightedPath(f,k){f&&k?ge={nodeIds:new Set(f),edgeIds:new Set(k)}:ge=null,h()},clearHighlightedPath(){ge=null,h()},setWalkMode(f){be=f,this.releaseAllPins(),f?(p=G?[...G]:[...E],a||(a=requestAnimationFrame(x))):(p=[],a&&(cancelAnimationFrame(a),a=0)),h()},getWalkMode(){return be},getWalkTrail(){return[...p]},getFilteredNodeIds(){return F},removeFromWalkTrail(f){p=p.filter(k=>k!==f),h()},nodeAtScreen(f,k){return et(f,k)},getNodeIds(){if(!c)return[];if(G){const f=new Set(G),k=c.nodes.filter(D=>f.has(D.id)).map(D=>D.id),B=c.nodes.filter(D=>!f.has(D.id)).map(D=>D.id);return[...k,...B]}return c.nodes.map(f=>f.id)},destroy(){cancelAnimationFrame(A),S&&(cancelAnimationFrame(S),S=0),a&&(cancelAnimationFrame(a),a=0),w&&(w.terminate(),w=null),M=null,$=null,Qe.disconnect()}};function Gn(f,k,B){const D=Math.max(16,Math.round(k/80));f.save(),f.font=`${D}px system-ui, sans-serif`,f.fillStyle="rgba(255, 255, 255, 0.4)",f.textAlign="right",f.textBaseline="bottom",f.fillText("backpackontology.com",k-20,B-16),f.restore()}}function rt(t){for(const e of Object.values(t.properties))if(typeof e=="string")return e;return t.id}const $o="✎";function Fo(t,e,s,l,u){const r=document.createElement("div");r.className="info-panel-content";let d=[],o=-1,n=!1,g=null,i=[],c=!1,T=[],A=-1;const E=e.mount("info",r,{title:"Node info",persistKey:"info-panel",hideOnClose:!0,onClose:()=>{d=[],o=-1}});E.setVisible(!1);function F(){E.setVisible(!1),d=[],o=-1}function W(q){!g||!l||(o<d.length-1&&(d=d.slice(0,o+1)),d.push(q),o=d.length-1,n=!0,l(q),n=!1)}function V(){if(o<=0||!g)return;o--,n=!0;const q=d[o];l==null||l(q),Y(q,g),n=!1}function _(){if(o>=d.length-1||!g)return;o++,n=!0;const q=d[o];l==null||l(q),Y(q,g),n=!1}function X(){const q=[{label:"Back",iconText:"←",onClick:V,disabled:o<=0},{label:"Forward",iconText:"→",onClick:_,disabled:o>=d.length-1}];u&&i.length>0&&q.push({label:"Focus",iconText:"◎",onClick:()=>{c||u(i)},disabled:c}),E.setHeaderButtons(q)}function Y(q,me){const U=me.nodes.find(h=>h.id===q);if(!U)return;const pe=me.edges.filter(h=>h.sourceId===q||h.targetId===q);T=pe.map(h=>h.sourceId===q?h.targetId:h.sourceId),A=-1,r.replaceChildren(),E.setTitle(rt(U)),X(),E.setVisible(!0);const Ee=document.createElement("div");Ee.className="info-panel-header";const te=document.createElement("div");te.className="info-header";const G=document.createElement("span");if(G.className="info-type-badge",G.textContent=U.type,G.style.backgroundColor=Ae(U.type),s){G.classList.add("info-editable");const h=document.createElement("button");h.className="info-inline-edit",h.textContent=$o,h.addEventListener("click",I=>{I.stopPropagation();const w=document.createElement("input");w.type="text",w.className="info-edit-inline-input",w.value=U.type,G.textContent="",G.appendChild(w),w.focus(),w.select();const N=()=>{const L=w.value.trim();L&&L!==U.type?s.onChangeNodeType(q,L):(G.textContent=U.type,G.appendChild(h))};w.addEventListener("blur",N),w.addEventListener("keydown",L=>{L.key==="Enter"&&w.blur(),L.key==="Escape"&&(w.value=U.type,w.blur())})}),G.appendChild(h)}const ye=document.createElement("h3");ye.className="info-label",ye.textContent=rt(U);const Ce=document.createElement("span");Ce.className="info-id",Ce.textContent=U.id,te.appendChild(G),te.appendChild(ye),te.appendChild(Ce),Ee.appendChild(te),r.appendChild(Ee);const se=document.createElement("div");se.className="info-panel-body";const ge=Object.keys(U.properties),be=Et("Properties");if(ge.length>0){const h=document.createElement("dl");h.className="info-props";for(const I of ge){const w=document.createElement("dt");w.textContent=I;const N=document.createElement("dd");if(s){const L=qt(U.properties[I]),b=document.createElement("textarea");b.className="info-edit-input",b.value=L,b.rows=1,b.addEventListener("input",()=>Pn(b)),b.addEventListener("keydown",$=>{$.key==="Enter"&&!$.shiftKey&&($.preventDefault(),b.blur())}),b.addEventListener("blur",()=>{const $=b.value;$!==L&&s.onUpdateNode(q,{[I]:Oo($)})}),N.appendChild(b),requestAnimationFrame(()=>Pn(b));const M=document.createElement("button");M.className="info-delete-prop",M.textContent="×",M.title=`Remove ${I}`,M.addEventListener("click",()=>{const $={...U.properties};delete $[I],s.onUpdateNode(q,$)}),N.appendChild(M)}else N.appendChild(Do(U.properties[I]));h.appendChild(w),h.appendChild(N)}be.appendChild(h)}if(s){const h=document.createElement("button");h.className="info-add-btn",h.textContent="+ Add property",h.addEventListener("click",()=>{const I=document.createElement("div");I.className="info-add-row";const w=document.createElement("input");w.type="text",w.className="info-edit-input",w.placeholder="key";const N=document.createElement("input");N.type="text",N.className="info-edit-input",N.placeholder="value";const L=document.createElement("button");L.className="info-add-save",L.textContent="Add",L.addEventListener("click",()=>{w.value&&s.onAddProperty(q,w.value,N.value)}),I.appendChild(w),I.appendChild(N),I.appendChild(L),be.appendChild(I),w.focus()}),be.appendChild(h)}if(se.appendChild(be),pe.length>0){const h=Et(`Connections (${pe.length})`),I=document.createElement("ul");I.className="info-connections";for(const w of pe){const N=w.sourceId===q,L=N?w.targetId:w.sourceId,b=me.nodes.find(ve=>ve.id===L),M=b?rt(b):L,$=document.createElement("li");if($.className="info-connection",l&&b&&($.classList.add("info-connection-link"),$.addEventListener("click",ve=>{ve.target.closest(".info-delete-edge")||W(L)})),b){const ve=document.createElement("span");ve.className="info-target-dot",ve.style.backgroundColor=Ae(b.type),$.appendChild(ve)}const Q=document.createElement("span");Q.className="info-arrow",Q.textContent=N?"→":"←";const ce=document.createElement("span");ce.className="info-edge-type",ce.textContent=w.type;const re=document.createElement("span");re.className="info-target",re.textContent=M,$.appendChild(Q),$.appendChild(ce),$.appendChild(re);const ue=Object.keys(w.properties);if(ue.length>0){const ve=document.createElement("div");ve.className="info-edge-props";for(const $e of ue){const Qe=document.createElement("span");Qe.className="info-edge-prop",Qe.textContent=`${$e}: ${qt(w.properties[$e])}`,ve.appendChild(Qe)}$.appendChild(ve)}if(s){const ve=document.createElement("button");ve.className="info-delete-edge",ve.textContent="×",ve.title="Remove connection",ve.addEventListener("click",$e=>{$e.stopPropagation(),s.onDeleteEdge(w.id)}),$.appendChild(ve)}I.appendChild($)}h.appendChild(I),se.appendChild(h)}const p=Et("Timestamps"),y=document.createElement("dl");y.className="info-props";const C=document.createElement("dt");C.textContent="created";const m=document.createElement("dd");m.textContent=Rn(U.createdAt);const v=document.createElement("dt");v.textContent="updated";const S=document.createElement("dd");if(S.textContent=Rn(U.updatedAt),y.appendChild(C),y.appendChild(m),y.appendChild(v),y.appendChild(S),p.appendChild(y),se.appendChild(p),s){const h=document.createElement("div");h.className="info-section info-danger";const I=document.createElement("button");I.className="info-delete-node",I.textContent="Delete node",I.addEventListener("click",()=>{s.onDeleteNode(q),F()}),h.appendChild(I),se.appendChild(h)}r.appendChild(se)}function K(q,me){const U=new Set(q),pe=me.nodes.filter(p=>U.has(p.id));if(pe.length===0)return;const Ee=me.edges.filter(p=>U.has(p.sourceId)&&U.has(p.targetId));r.replaceChildren(),E.setTitle(`${pe.length} nodes selected`),X(),E.setVisible(!0);const te=document.createElement("div");te.className="info-header";const G=document.createElement("h3");G.className="info-label",G.textContent=`${pe.length} nodes selected`,te.appendChild(G);const ye=document.createElement("div");ye.className="info-badge-row";const Ce=new Map;for(const p of pe)Ce.set(p.type,(Ce.get(p.type)??0)+1);for(const[p,y]of Ce){const C=document.createElement("span");C.className="info-type-badge",C.style.backgroundColor=Ae(p),C.textContent=y>1?`${p} (${y})`:p,ye.appendChild(C)}te.appendChild(ye),r.appendChild(te);const se=Et("Selected Nodes"),ge=document.createElement("ul");ge.className="info-connections";for(const p of pe){const y=document.createElement("li");y.className="info-connection",l&&(y.classList.add("info-connection-link"),y.addEventListener("click",()=>{W(p.id)}));const C=document.createElement("span");C.className="info-target-dot",C.style.backgroundColor=Ae(p.type);const m=document.createElement("span");m.className="info-target",m.textContent=rt(p);const v=document.createElement("span");v.className="info-edge-type",v.textContent=p.type,y.appendChild(C),y.appendChild(m),y.appendChild(v),ge.appendChild(y)}se.appendChild(ge),r.appendChild(se);const be=Et(Ee.length>0?`Connections Between Selected (${Ee.length})`:"Connections Between Selected");if(Ee.length===0){const p=document.createElement("p");p.className="info-empty-message",p.textContent="No direct connections between selected nodes",be.appendChild(p)}else{const p=document.createElement("ul");p.className="info-connections";for(const y of Ee){const C=me.nodes.find($=>$.id===y.sourceId),m=me.nodes.find($=>$.id===y.targetId),v=C?rt(C):y.sourceId,S=m?rt(m):y.targetId,h=document.createElement("li");if(h.className="info-connection",C){const $=document.createElement("span");$.className="info-target-dot",$.style.backgroundColor=Ae(C.type),h.appendChild($)}const I=document.createElement("span");I.className="info-target",I.textContent=v;const w=document.createElement("span");w.className="info-arrow",w.textContent="→";const N=document.createElement("span");N.className="info-edge-type",N.textContent=y.type;const L=document.createElement("span");if(L.className="info-arrow",L.textContent="→",h.appendChild(I),h.appendChild(w),h.appendChild(N),h.appendChild(L),m){const $=document.createElement("span");$.className="info-target-dot",$.style.backgroundColor=Ae(m.type),h.appendChild($)}const b=document.createElement("span");b.className="info-target",b.textContent=S,h.appendChild(b);const M=Object.keys(y.properties);if(M.length>0){const $=document.createElement("div");$.className="info-edge-props";for(const Q of M){const ce=document.createElement("span");ce.className="info-edge-prop",ce.textContent=`${Q}: ${qt(y.properties[Q])}`,$.appendChild(ce)}h.appendChild($)}p.appendChild(h)}be.appendChild(p)}r.appendChild(be)}return{show(q,me){if(g=me,i=q,q.length===1&&!n){const U=q[0];d[o]!==U&&(o<d.length-1&&(d=d.slice(0,o+1)),d.push(U),o=d.length-1)}q.length===1?Y(q[0],me):q.length>1&&K(q,me)},hide:F,goBack:V,goForward:_,cycleConnection(q){if(T.length===0)return null;A===-1?A=q===1?0:T.length-1:(A+=q,A>=T.length&&(A=0),A<0&&(A=T.length-1));const me=r.querySelectorAll(".info-connection");return me.forEach((U,pe)=>{U.classList.toggle("info-connection-active",pe===A)}),A>=0&&me[A]&&me[A].scrollIntoView({block:"nearest"}),T[A]??null},setFocusDisabled(q){c=q,X()},get visible(){return E.isVisible()}}}function Et(t){const e=document.createElement("div");e.className="info-section";const s=document.createElement("h4");return s.className="info-section-title",s.textContent=t,e.appendChild(s),e}function Do(t){if(Array.isArray(t)){const s=document.createElement("div");s.className="info-array";for(const l of t){const u=document.createElement("span");u.className="info-tag",u.textContent=String(l),s.appendChild(u)}return s}if(t!==null&&typeof t=="object"){const s=document.createElement("pre");return s.className="info-json",s.textContent=JSON.stringify(t,null,2),s}const e=document.createElement("span");return e.className="info-value",e.textContent=String(t??""),e}function qt(t){return Array.isArray(t)?t.map(String).join(", "):t!==null&&typeof t=="object"?JSON.stringify(t):String(t??"")}function Oo(t){const e=t.trim();if(e==="true")return!0;if(e==="false")return!1;if(e!==""&&!isNaN(Number(e)))return Number(e);if(e.startsWith("[")&&e.endsWith("]")||e.startsWith("{")&&e.endsWith("}"))try{return JSON.parse(e)}catch{return t}return t}function Pn(t){t.style.height="auto",t.style.height=t.scrollHeight+"px"}function Rn(t){try{return new Date(t).toLocaleString()}catch{return t}}const en=30,Wo=39,Uo=45,Bn=380,jo=70,zo=16,$n=80,qn="backpack-viewer:panel:",_o="has-fullscreen-panel";let Bt=en;function dt(t){Bt++,Bt>Wo&&(document.querySelectorAll(".extension-panel").forEach(e=>{e.style.zIndex=String(en+1)}),Bt=en+2),t.style.zIndex=String(Bt)}let $t=0;function Ft(t,e){const s=t.id==="canvas-container"?t:t.closest("#canvas-container")??t;e?$t++:$t=Math.max(0,$t-1),s.classList.toggle(_o,$t>0)}function Xt(t){try{const e=localStorage.getItem(qn+t);if(!e)return null;const s=JSON.parse(e);if(s&&typeof s=="object")return s}catch{}return null}function Fn(t,e){try{localStorage.setItem(qn+t,JSON.stringify(e))}catch{}}function Dn(){return at({size:13,strokeWidth:1.8,strokeLinecap:"round",strokeLinejoin:"round"},[{tag:"polyline",attrs:{points:"4 9 4 4 9 4"}},{tag:"polyline",attrs:{points:"20 9 20 4 15 4"}},{tag:"polyline",attrs:{points:"4 15 4 20 9 20"}},{tag:"polyline",attrs:{points:"20 15 20 20 15 20"}}])}function Ho(){return at({size:13,strokeWidth:1.8,strokeLinecap:"round",strokeLinejoin:"round"},[{tag:"polyline",attrs:{points:"9 4 9 9 4 9"}},{tag:"polyline",attrs:{points:"15 4 15 9 20 9"}},{tag:"polyline",attrs:{points:"9 20 9 15 4 15"}},{tag:"polyline",attrs:{points:"15 20 15 15 20 15"}}])}function Yo(t){const e=document.createElement("div");e.className="extension-panel-layer",t.appendChild(e);function s(){const r=t.getBoundingClientRect();return{left:Math.max(0,r.width-Bn-zo),top:jo}}function l(r,d){const o=t.getBoundingClientRect(),n=$n-d.width,g=o.width-$n,i=0,c=o.height-40;return{left:Math.max(n,Math.min(g,r.left)),top:Math.max(i,Math.min(c,r.top))}}function u(r,d,o={}){const n=o.persistKey??r,g=Xt(n),i=document.createElement("aside");i.className="extension-panel",i.dataset.panel=n;const c=document.createElement("div");c.className="extension-panel-header";const T=document.createElement("span");T.className="extension-panel-title",T.textContent=o.title??r,c.appendChild(T);const A=document.createElement("div");A.className="extension-panel-custom-btns",c.appendChild(A);function E(m){A.replaceChildren();for(const v of m){const S=document.createElement("button");S.className="extension-panel-btn",S.title=v.label,S.setAttribute("aria-label",v.label),S.textContent=v.iconText??v.label,v.disabled&&(S.disabled=!0),S.addEventListener("click",h=>{h.stopPropagation();try{v.onClick()}catch(I){console.error(`[backpack-viewer] panel header button "${v.label}" threw:`,I)}}),S.addEventListener("mousedown",h=>h.stopPropagation()),A.appendChild(S)}}E(o.headerButtons??[]);let F=!1,W=null,V=null;o.showFullscreenButton!==!1&&(W=document.createElement("button"),W.className="extension-panel-btn extension-panel-btn-fullscreen",W.title="Toggle fullscreen",W.setAttribute("aria-label","Toggle fullscreen"),V=Dn(),W.appendChild(V),W.addEventListener("click",m=>{m.stopPropagation(),p(!F)}),W.addEventListener("mousedown",m=>m.stopPropagation()),c.appendChild(W));let _=null;o.showCloseButton!==!1&&(_=document.createElement("button"),_.className="extension-panel-btn extension-panel-btn-close",_.title="Close panel",_.setAttribute("aria-label","Close panel"),_.textContent="×",_.addEventListener("click",m=>{var v;if(m.stopPropagation(),o.hideOnClose){be(!1);try{(v=o.onClose)==null||v.call(o)}catch(S){console.error("[backpack-viewer] panel onClose threw:",S)}}else ge()}),_.addEventListener("mousedown",m=>m.stopPropagation()),c.appendChild(_)),i.appendChild(c);const X=document.createElement("div");X.className="extension-panel-body",X.appendChild(d),i.appendChild(X),e.appendChild(i);const Y=g&&g.left!=null&&g.top!=null?{left:g.left,top:g.top}:o.defaultPosition??s(),q=l(Y,{width:Bn});i.style.left=q.left+"px",i.style.top=q.top+"px",dt(i);let me=0,U=0,pe=0,Ee=0,te=!1;function G(m){if(!te)return;const v=m.clientX-me,S=m.clientY-U,h=l({left:pe+v,top:Ee+S},i.getBoundingClientRect());i.style.left=h.left+"px",i.style.top=h.top+"px"}function ye(){if(!te)return;te=!1,document.removeEventListener("mousemove",G),document.removeEventListener("mouseup",ye);const m=i.getBoundingClientRect(),v=t.getBoundingClientRect();Fn(n,{...Xt(n),left:m.left-v.left,top:m.top-v.top})}c.addEventListener("mousedown",m=>{if(F)return;te=!0,me=m.clientX,U=m.clientY;const v=i.getBoundingClientRect(),S=t.getBoundingClientRect();pe=v.left-S.left,Ee=v.top-S.top,dt(i),document.addEventListener("mousemove",G),document.addEventListener("mouseup",ye),m.preventDefault()}),i.addEventListener("mousedown",()=>{F||dt(i)},{capture:!0});let Ce=!1,se=!0;function ge(){var m;if(!Ce){Ce=!0,document.removeEventListener("mousemove",G),document.removeEventListener("mouseup",ye),F&&(Ft(t,!1),F=!1),i.remove();try{(m=o.onClose)==null||m.call(o)}catch(v){console.error("[backpack-viewer] panel onClose threw:",v)}}}function be(m){m!==se&&(se=m,i.classList.toggle("is-hidden",!se),se?(dt(i),F&&Ft(t,!0)):F&&Ft(t,!1))}function p(m){var v;if(m!==F){F=m,i.classList.toggle("is-fullscreen",F),W&&V&&(V.remove(),V=F?Ho():Dn(),W.appendChild(V)),F?i.style.zIndex=String(Uo):dt(i),Ft(t,F),Fn(n,{...Xt(n),fullscreen:F});try{(v=o.onFullscreenChange)==null||v.call(o,F)}catch(S){console.error("[backpack-viewer] panel onFullscreenChange threw:",S)}}}g!=null&&g.fullscreen&&p(!0);function y(m){T.textContent=m}function C(m){E(m)}return{close:ge,setFullscreen:p,isFullscreen:()=>F,setTitle:y,setHeaderButtons:C,setVisible:be,isVisible:()=>se,bringToFront:()=>dt(i),element:d}}return{mount:u}}function Xn(t){for(const e of Object.values(t.properties))if(typeof e=="string")return e;return t.id}function On(t,e){const s=e.toLowerCase();if(Xn(t).toLowerCase().includes(s)||t.type.toLowerCase().includes(s))return!0;for(const l of Object.values(t.properties))if(typeof l=="string"&&l.toLowerCase().includes(s))return!0;return!1}function qo(t,e){const s=(e==null?void 0:e.maxResults)??8,l=(e==null?void 0:e.debounceMs)??150;let u=null,r=null,d=null,o=null;const n=document.createElement("div");n.className="search-overlay hidden";const g=document.createElement("div");g.className="search-input-wrap";const i=document.createElement("input");i.className="search-input",i.type="text",i.placeholder="Search nodes...",i.setAttribute("autocomplete","off"),i.setAttribute("spellcheck","false");const c=document.createElement("kbd");c.className="search-kbd",c.textContent="/",g.appendChild(i),g.appendChild(c);const T=document.createElement("ul");T.className="search-results hidden",n.appendChild(g),n.appendChild(T),t.appendChild(n);function A(){if(!u)return null;const _=i.value.trim();if(_.length===0)return null;const X=new Set;for(const Y of u.nodes)On(Y,_)&&X.add(Y.id);return X}function E(){const _=A();r==null||r(_),F()}function F(){T.replaceChildren(),W=-1;const _=i.value.trim();if(!u||_.length===0){T.classList.add("hidden");return}const X=[];for(const Y of u.nodes)if(On(Y,_)&&(X.push(Y),X.length>=s))break;if(X.length===0){T.classList.add("hidden");return}for(const Y of X){const K=document.createElement("li");K.className="search-result-item";const q=document.createElement("span");q.className="search-result-dot",q.style.backgroundColor=Ae(Y.type);const me=document.createElement("span");me.className="search-result-label";const U=Xn(Y);me.textContent=U.length>36?U.slice(0,34)+"...":U;const pe=document.createElement("span");pe.className="search-result-type",pe.textContent=Y.type,K.appendChild(q),K.appendChild(me),K.appendChild(pe),K.addEventListener("click",()=>{d==null||d(Y.id),i.value="",T.classList.add("hidden"),E()}),T.appendChild(K)}T.classList.remove("hidden")}i.addEventListener("input",()=>{o&&clearTimeout(o),o=setTimeout(E,l)});let W=-1;function V(){const _=T.querySelectorAll(".search-result-item");_.forEach((X,Y)=>{X.classList.toggle("search-result-active",Y===W)}),W>=0&&_[W]&&_[W].scrollIntoView({block:"nearest"})}return i.addEventListener("keydown",_=>{const X=T.querySelectorAll(".search-result-item");_.key==="ArrowDown"?(_.preventDefault(),X.length>0&&(W=Math.min(W+1,X.length-1),V())):_.key==="ArrowUp"?(_.preventDefault(),X.length>0&&(W=Math.max(W-1,0),V())):_.key==="Enter"?(_.preventDefault(),W>=0&&X[W]?X[W].click():X.length>0&&X[0].click(),i.blur()):_.key==="Escape"&&(i.value="",i.blur(),T.classList.add("hidden"),W=-1,E())}),document.addEventListener("click",_=>{n.contains(_.target)||T.classList.add("hidden")}),i.addEventListener("focus",()=>c.classList.add("hidden")),i.addEventListener("blur",()=>{i.value.length===0&&c.classList.remove("hidden")}),{setLearningGraphData(_){u=_,i.value="",T.classList.add("hidden"),u&&u.nodes.length>0?n.classList.remove("hidden"):n.classList.add("hidden")},onFilterChange(_){r=_},onNodeSelect(_){d=_},clear(){i.value="",T.classList.add("hidden"),r==null||r(null)},focus(){i.focus()}}}function Xo(t,e){let s=null,l=null,u=!0,r=null,d=!0,o=!0,n=!0,g="types",i="",c="",T=[],A=[];const E={types:new Set,nodeIds:new Set};function F(){if(!s)return[];const p=new Set;for(const y of s.nodes)E.types.has(y.type)&&p.add(y.id);for(const y of E.nodeIds)p.add(y);return[...p]}function W(p){if(E.nodeIds.has(p))return!0;const y=s==null?void 0:s.nodes.find(C=>C.id===p);return y?E.types.has(y.type):!1}function V(){return E.types.size===0&&E.nodeIds.size===0}function _(){const p=F();e.onFocusChange(p.length>0?p:null)}const X=document.createElement("button");X.className="tools-pane-toggle hidden",X.title="Graph Inspector",X.appendChild(at({size:16,strokeLinecap:"round",strokeLinejoin:"round"},[{tag:"path",attrs:{d:"M4 7h16"}},{tag:"path",attrs:{d:"M4 12h16"}},{tag:"path",attrs:{d:"M4 17h10"}}]));const Y=document.createElement("div");Y.className="tools-pane-content hidden",t.appendChild(X),t.appendChild(Y),X.addEventListener("click",()=>{var p;u=!u,Y.classList.toggle("hidden",u),X.classList.toggle("active",!u),u||(p=e.onOpen)==null||p.call(e)});function K(){if(Y.replaceChildren(),!l)return;const p=document.createElement("div");p.className="tools-pane-summary";const y=document.createElement("span");y.textContent=`${l.nodeCount} nodes`;const C=document.createElement("span");C.className="tools-pane-sep",C.textContent="·";const m=document.createElement("span");m.textContent=`${l.edgeCount} edges`;const v=document.createElement("span");v.className="tools-pane-sep",v.textContent="·";const S=document.createElement("span");if(S.textContent=`${l.types.length} types`,p.append(y,C,m,v,S),Y.appendChild(p),s&&l.nodeCount>0){const N=Math.ceil(JSON.stringify(s).length/4),L=Math.round(N/l.nodeCount),b=Math.max(10,Math.round(L*.3)*Math.min(5,l.nodeCount)),M=N>b?Math.round((1-b/N)*100):0,$=document.createElement("div");$.className="tools-pane-token-card";const Q=Math.min(100,M),ce=document.createElement("div");ce.className="token-card-label",ce.textContent="Token Efficiency",$.appendChild(ce);const re=document.createElement("div");re.className="token-card-stat",re.textContent=`~${N.toLocaleString()} tokens stored`,$.appendChild(re);const ue=document.createElement("div");ue.className="token-card-bar";const ve=document.createElement("div");ve.className="token-card-bar-fill",ve.style.width=`${Q}%`,ue.appendChild(ve),$.appendChild(ue);const $e=document.createElement("div");$e.className="token-card-stat",$e.textContent=`A search returns ~${b} tokens instead of ~${N.toLocaleString()} (${M}% reduction)`,$.appendChild($e),Y.appendChild($)}const h=document.createElement("div");h.className="tools-pane-tabs";const I=[{id:"types",label:"Types"},{id:"insights",label:"Insights"},{id:"controls",label:"Controls"}];for(const N of I){const L=document.createElement("button");L.className="tools-pane-tab",g===N.id&&L.classList.add("tools-pane-tab-active"),L.textContent=N.label,L.addEventListener("click",()=>{g=N.id,K()}),h.appendChild(L)}Y.appendChild(h),V()||U(),A.length>0&&me(),g==="types"&&l.types.length>5?Y.appendChild(Ee("Filter types...",i,N=>{i=N,q()})):g==="insights"&&l.orphans.length+l.singletons.length+l.emptyNodes.length>5&&Y.appendChild(Ee("Filter issues...",c,L=>{c=L,q()}));const w=document.createElement("div");w.className="tools-pane-tab-content",Y.appendChild(w),q()}function q(){const p=Y.querySelector(".tools-pane-tab-content");p&&(p.replaceChildren(),g==="types"?te(p):g==="insights"?G(p):g==="controls"&&ye(p))}function me(){Y.appendChild(se(`Walk Trail (${A.length})`,p=>{for(let C=0;C<A.length;C++){const m=A[C],v=C===A.length-1;if(m.edgeType){const b=document.createElement("div");b.className="walk-trail-edge",b.textContent=`↓ ${m.edgeType}`,p.appendChild(b)}const S=document.createElement("div");S.className="tools-pane-row tools-pane-clickable",v&&(S.style.fontWeight="600");const h=document.createElement("span");h.className="tools-pane-count",h.style.minWidth="18px",h.textContent=`${C+1}`;const I=document.createElement("span");I.className="tools-pane-dot",I.style.backgroundColor=Ae(m.type);const w=document.createElement("span");w.className="tools-pane-name",w.textContent=m.label;const N=document.createElement("span");N.className="tools-pane-count",N.textContent=m.type;const L=document.createElement("button");L.className="tools-pane-edit",L.style.opacity="1",L.textContent="×",L.title="Remove from trail",L.addEventListener("click",b=>{var M;b.stopPropagation(),(M=e.onWalkTrailRemove)==null||M.call(e,m.id)}),S.appendChild(h),S.appendChild(I),S.appendChild(w),S.appendChild(N),S.appendChild(L),S.addEventListener("click",()=>{e.onNavigateToNode(m.id)}),p.appendChild(S)}const y=document.createElement("div");if(y.className="tools-pane-export-row",e.onWalkIsolate){const C=document.createElement("button");C.className="tools-pane-export-btn",C.textContent="Isolate (I)",C.addEventListener("click",()=>e.onWalkIsolate()),y.appendChild(C)}if(e.onWalkSaveSnippet&&A.length>=2){const C=document.createElement("button");C.className="tools-pane-export-btn",C.textContent="Save snippet",C.addEventListener("click",()=>{Dt("Save snippet","Name for this snippet").then(m=>{m&&e.onWalkSaveSnippet(m)})}),y.appendChild(C)}p.appendChild(y)}))}function U(){if(!l||!s)return;const p=F();Y.appendChild(se("Focused",y=>{for(const S of E.types){const h=l.types.find(M=>M.name===S);if(!h)continue;const I=document.createElement("div");I.className="tools-pane-row tools-pane-clickable";const w=document.createElement("span");w.className="tools-pane-dot",w.style.backgroundColor=Ae(h.name);const N=document.createElement("span");N.className="tools-pane-name",N.textContent=h.name;const L=document.createElement("span");L.className="tools-pane-count",L.textContent=`${h.count} nodes`;const b=document.createElement("button");b.className="tools-pane-edit tools-pane-focus-active",b.style.opacity="1",b.textContent="×",b.title=`Remove ${h.name} from focus`,I.appendChild(w),I.appendChild(N),I.appendChild(L),I.appendChild(b),b.addEventListener("click",M=>{M.stopPropagation(),E.types.delete(h.name),_(),K()}),y.appendChild(I)}for(const S of E.nodeIds){const h=s.nodes.find($=>$.id===S);if(!h)continue;const I=Wn(h.properties)??h.id,w=document.createElement("div");w.className="tools-pane-row tools-pane-clickable";const N=document.createElement("span");N.className="tools-pane-dot",N.style.backgroundColor=Ae(h.type);const L=document.createElement("span");L.className="tools-pane-name",L.textContent=I;const b=document.createElement("span");b.className="tools-pane-count",b.textContent=h.type;const M=document.createElement("button");M.className="tools-pane-edit tools-pane-focus-active",M.style.opacity="1",M.textContent="×",M.title=`Remove ${I} from focus`,w.appendChild(N),w.appendChild(L),w.appendChild(b),w.appendChild(M),w.addEventListener("click",$=>{$.target.closest(".tools-pane-edit")||e.onNavigateToNode(S)}),M.addEventListener("click",$=>{$.stopPropagation(),E.nodeIds.delete(S),_(),K()}),y.appendChild(w)}const C=document.createElement("div");C.className="tools-pane-row tools-pane-clickable tools-pane-focus-clear";const m=document.createElement("span");m.className="tools-pane-name",m.style.color="var(--accent)",m.textContent=`${p.length} total`;const v=document.createElement("span");v.className="tools-pane-badge",v.textContent="clear all",C.appendChild(m),C.appendChild(v),C.addEventListener("click",()=>{E.types.clear(),E.nodeIds.clear(),_(),K()}),y.appendChild(C)}))}function pe(p){const y=document.createElement("div");y.className="tools-pane-row tools-pane-clickable",r===p.name&&y.classList.add("active");const C=document.createElement("span");C.className="tools-pane-dot",C.style.backgroundColor=Ae(p.name);const m=document.createElement("span");m.className="tools-pane-name",m.textContent=p.name;const v=document.createElement("span");v.className="tools-pane-count",v.textContent=String(p.count);const S=document.createElement("button");S.className="tools-pane-edit tools-pane-focus-toggle",E.types.has(p.name)&&S.classList.add("tools-pane-focus-active"),S.textContent="◎",S.title=E.types.has(p.name)?`Remove ${p.name} from focus`:`Add ${p.name} to focus`;const h=document.createElement("button");return h.className="tools-pane-edit",h.textContent="✎",h.title=`Rename all ${p.name} nodes`,y.appendChild(C),y.appendChild(m),y.appendChild(v),y.appendChild(S),y.appendChild(h),y.addEventListener("click",I=>{I.target.closest(".tools-pane-edit")||(r===p.name?(r=null,e.onFilterByType(null)):(r=p.name,e.onFilterByType(p.name)),K())}),S.addEventListener("click",I=>{I.stopPropagation(),E.types.has(p.name)?E.types.delete(p.name):E.types.add(p.name),_(),K()}),h.addEventListener("click",I=>{I.stopPropagation(),ge(y,p.name,w=>{w&&w!==p.name&&e.onRenameNodeType(p.name,w)})}),y}function Ee(p,y,C){const m=document.createElement("input");return m.type="text",m.className="tools-pane-search",m.placeholder=p,m.value=y,m.addEventListener("input",()=>C(m.value)),m}function te(p){if(!l)return;const y=i.toLowerCase();if(l.types.length){const m=l.types.filter(v=>!E.types.has(v.name)).filter(v=>!y||v.name.toLowerCase().includes(y));m.length>0&&p.appendChild(se("Node Types",v=>{for(const S of m)v.appendChild(pe(S))}))}const C=l.edgeTypes.filter(m=>!y||m.name.toLowerCase().includes(y));C.length&&p.appendChild(se("Edge Types",m=>{for(const v of C){const S=document.createElement("div");S.className="tools-pane-row tools-pane-clickable";const h=document.createElement("span");h.className="tools-pane-name",h.textContent=v.name;const I=document.createElement("span");I.className="tools-pane-count",I.textContent=String(v.count);const w=document.createElement("button");w.className="tools-pane-edit",w.textContent="✎",w.title=`Rename all ${v.name} edges`,S.appendChild(h),S.appendChild(I),S.appendChild(w),w.addEventListener("click",N=>{N.stopPropagation(),ge(S,v.name,L=>{L&&L!==v.name&&e.onRenameEdgeType(v.name,L)})}),m.appendChild(S)}}))}function G(p){if(!l)return;const y=c.toLowerCase(),C=l.starred.filter(L=>!y||L.label.toLowerCase().includes(y)||L.type.toLowerCase().includes(y));C.length&&p.appendChild(se("★ Starred",L=>{for(const $ of C){const Q=document.createElement("div");Q.className="tools-pane-row tools-pane-clickable";const ce=document.createElement("span");ce.className="tools-pane-dot",ce.style.backgroundColor=Ae($.type);const re=document.createElement("span");re.className="tools-pane-name",re.textContent=$.label;const ue=document.createElement("button");ue.className="tools-pane-edit tools-pane-focus-toggle",W($.id)&&ue.classList.add("tools-pane-focus-active"),ue.textContent="◎",ue.title=W($.id)?`Remove ${$.label} from focus`:`Add ${$.label} to focus`,Q.appendChild(ce),Q.appendChild(re),Q.appendChild(ue),Q.addEventListener("click",ve=>{ve.target.closest(".tools-pane-edit")||e.onNavigateToNode($.id)}),ue.addEventListener("click",ve=>{ve.stopPropagation(),E.nodeIds.has($.id)?E.nodeIds.delete($.id):E.nodeIds.add($.id),_(),K()}),L.appendChild(Q)}const b=document.createElement("div");b.className="tools-pane-row tools-pane-actions";const M=document.createElement("button");if(M.className="tools-pane-action-btn",M.textContent="Focus all",M.title="Enter focus mode with all starred nodes",M.addEventListener("click",()=>{E.nodeIds.clear(),E.types.clear();for(const $ of l.starred)E.nodeIds.add($.id);_(),K()}),b.appendChild(M),e.onStarredSaveSnippet){const $=document.createElement("button");$.className="tools-pane-action-btn",$.textContent="Save as snippet",$.title="Save starred nodes as a reusable snippet",$.addEventListener("click",async()=>{const Q=await Dt("Snippet name","starred");Q&&e.onStarredSaveSnippet(Q,l.starred.map(ce=>ce.id))}),b.appendChild($)}L.appendChild(b)}));const m=l.mostConnected.filter(L=>!y||L.label.toLowerCase().includes(y)||L.type.toLowerCase().includes(y));m.length&&p.appendChild(se("Most Connected",L=>{for(const b of m){const M=document.createElement("div");M.className="tools-pane-row tools-pane-clickable";const $=document.createElement("span");$.className="tools-pane-dot",$.style.backgroundColor=Ae(b.type);const Q=document.createElement("span");Q.className="tools-pane-name",Q.textContent=b.label;const ce=document.createElement("span");ce.className="tools-pane-count",ce.textContent=`${b.connections}`;const re=document.createElement("button");re.className="tools-pane-edit tools-pane-focus-toggle",W(b.id)&&re.classList.add("tools-pane-focus-active"),re.textContent="◎",re.title=W(b.id)?`Remove ${b.label} from focus`:`Add ${b.label} to focus`,M.appendChild($),M.appendChild(Q),M.appendChild(ce),M.appendChild(re),M.addEventListener("click",ue=>{ue.target.closest(".tools-pane-edit")||e.onNavigateToNode(b.id)}),re.addEventListener("click",ue=>{ue.stopPropagation(),E.nodeIds.has(b.id)?E.nodeIds.delete(b.id):E.nodeIds.add(b.id),_(),K()}),L.appendChild(M)}}));const v=l.orphans.filter(L=>!y||L.label.toLowerCase().includes(y)||L.type.toLowerCase().includes(y)),S=l.singletons.filter(L=>!y||L.name.toLowerCase().includes(y)),h=l.emptyNodes.filter(L=>!y||L.label.toLowerCase().includes(y)||L.type.toLowerCase().includes(y)),I=v.length>0,w=S.length>0,N=h.length>0;if(!I&&!w&&!N){const L=document.createElement("div");L.className="tools-pane-empty-msg",L.textContent="No issues found",p.appendChild(L);return}I&&p.appendChild(se("Orphans",L=>{for(const b of v.slice(0,5)){const M=document.createElement("div");M.className="tools-pane-row tools-pane-clickable tools-pane-issue";const $=document.createElement("span");$.className="tools-pane-dot",$.style.backgroundColor=Ae(b.type);const Q=document.createElement("span");Q.className="tools-pane-name",Q.textContent=b.label;const ce=document.createElement("span");ce.className="tools-pane-badge",ce.textContent="orphan";const re=document.createElement("button");re.className="tools-pane-edit tools-pane-focus-toggle",W(b.id)&&re.classList.add("tools-pane-focus-active"),re.textContent="◎",re.title=W(b.id)?`Remove ${b.label} from focus`:`Add ${b.label} to focus`,M.appendChild($),M.appendChild(Q),M.appendChild(ce),M.appendChild(re),M.addEventListener("click",ue=>{ue.target.closest(".tools-pane-edit")||e.onNavigateToNode(b.id)}),re.addEventListener("click",ue=>{ue.stopPropagation(),E.nodeIds.has(b.id)?E.nodeIds.delete(b.id):E.nodeIds.add(b.id),_(),K()}),L.appendChild(M)}if(v.length>5){const b=document.createElement("div");b.className="tools-pane-more",b.textContent=`+ ${v.length-5} more orphans`,L.appendChild(b)}})),w&&p.appendChild(se("Singletons",L=>{for(const b of S.slice(0,5)){const M=document.createElement("div");M.className="tools-pane-row tools-pane-issue";const $=document.createElement("span");$.className="tools-pane-dot",$.style.backgroundColor=Ae(b.name);const Q=document.createElement("span");Q.className="tools-pane-name",Q.textContent=b.name;const ce=document.createElement("span");ce.className="tools-pane-badge",ce.textContent="1 node",M.appendChild($),M.appendChild(Q),M.appendChild(ce),L.appendChild(M)}})),N&&p.appendChild(se("Empty Nodes",L=>{for(const b of h.slice(0,5)){const M=document.createElement("div");M.className="tools-pane-row tools-pane-issue";const $=document.createElement("span");$.className="tools-pane-dot",$.style.backgroundColor=Ae(b.type);const Q=document.createElement("span");Q.className="tools-pane-name",Q.textContent=b.label;const ce=document.createElement("span");ce.className="tools-pane-badge",ce.textContent="empty",M.appendChild($),M.appendChild(Q),M.appendChild(ce),L.appendChild(M)}if(l.emptyNodes.length>5){const b=document.createElement("div");b.className="tools-pane-more",b.textContent=`+ ${l.emptyNodes.length-5} more empty nodes`,L.appendChild(b)}}))}function ye(p){p.appendChild(se("Display",y=>{const C=document.createElement("div");C.className="tools-pane-row tools-pane-clickable";const m=document.createElement("input");m.type="checkbox",m.checked=d,m.className="tools-pane-checkbox";const v=document.createElement("span");v.className="tools-pane-name",v.textContent="Edge labels",C.appendChild(m),C.appendChild(v),C.addEventListener("click",b=>{b.target!==m&&(m.checked=!m.checked),d=m.checked,e.onToggleEdgeLabels(d)}),y.appendChild(C);const S=document.createElement("div");S.className="tools-pane-row tools-pane-clickable";const h=document.createElement("input");h.type="checkbox",h.checked=o,h.className="tools-pane-checkbox";const I=document.createElement("span");I.className="tools-pane-name",I.textContent="Type regions",S.appendChild(h),S.appendChild(I),S.addEventListener("click",b=>{b.target!==h&&(h.checked=!h.checked),o=h.checked,e.onToggleTypeHulls(o)}),y.appendChild(S);const w=document.createElement("div");w.className="tools-pane-row tools-pane-clickable";const N=document.createElement("input");N.type="checkbox",N.checked=n,N.className="tools-pane-checkbox";const L=document.createElement("span");L.className="tools-pane-name",L.textContent="Minimap",w.appendChild(N),w.appendChild(L),w.addEventListener("click",b=>{b.target!==N&&(N.checked=!N.checked),n=N.checked,e.onToggleMinimap(n)}),y.appendChild(w)})),p.appendChild(se("Layout",y=>{y.appendChild(Ce("Clustering",0,1,.02,.08,C=>{e.onLayoutChange("clusterStrength",C)})),y.appendChild(Ce("Spacing",.5,20,.5,1.5,C=>{e.onLayoutChange("spacing",C)})),y.appendChild(Ce("Pan speed",20,200,10,60,C=>{e.onPanSpeedChange(C)}))})),p.appendChild(se("Export",y=>{const C=document.createElement("div");C.className="tools-pane-export-row";const m=document.createElement("button");m.className="tools-pane-export-btn",m.textContent="Export PNG",m.addEventListener("click",()=>e.onExport("png"));const v=document.createElement("button");v.className="tools-pane-export-btn",v.textContent="Export SVG",v.addEventListener("click",()=>e.onExport("svg")),C.appendChild(m),C.appendChild(v),y.appendChild(C)})),(e.onSnapshot||e.onRollback)&&p.appendChild(se("Versions",y=>{const C=document.createElement("div");C.className="tools-pane-export-row";const m=document.createElement("button");if(m.className="tools-pane-export-btn",m.textContent="Save snapshot",m.addEventListener("click",()=>{Dt("Save snapshot","Label (optional)").then(v=>{var S;(S=e.onSnapshot)==null||S.call(e,v||void 0)})}),C.appendChild(m),y.appendChild(C),T.length>0)for(const v of T){const S=document.createElement("div");S.className="tools-pane-row";const h=document.createElement("span");h.className="tools-pane-name";const I=Go(v.timestamp);h.textContent=v.label?`#${v.version} ${v.label}`:`#${v.version}`,h.title=`${I} — ${v.nodeCount} nodes, ${v.edgeCount} edges`;const w=document.createElement("span");w.className="tools-pane-count",w.textContent=I;const N=document.createElement("button");N.className="tools-pane-edit",N.style.opacity="1",N.textContent="↩",N.title="Restore this snapshot",N.addEventListener("click",()=>{jn("Restore snapshot",`Restore snapshot #${v.version}? Current state will be lost unless you save a snapshot first.`).then(L=>{var b;L&&((b=e.onRollback)==null||b.call(e,v.version))})}),S.appendChild(h),S.appendChild(w),S.appendChild(N),y.appendChild(S)}else{const v=document.createElement("div");v.className="tools-pane-empty-msg",v.textContent="No snapshots yet",y.appendChild(v)}}))}function Ce(p,y,C,m,v,S){const h=document.createElement("div");h.className="tools-pane-slider-row";const I=document.createElement("span");I.className="tools-pane-slider-label",I.textContent=p;const w=document.createElement("input");w.type="range",w.className="tools-pane-slider",w.min=String(y),w.max=String(C),w.step=String(m),w.value=String(v);const N=document.createElement("span");return N.className="tools-pane-slider-value",N.textContent=String(v),w.addEventListener("input",()=>{const L=parseFloat(w.value);N.textContent=L%1===0?String(L):L.toFixed(2),S(L)}),h.appendChild(I),h.appendChild(w),h.appendChild(N),h}function se(p,y){const C=document.createElement("div");C.className="tools-pane-section";const m=document.createElement("div");return m.className="tools-pane-heading",m.textContent=p,C.appendChild(m),y(C),C}function ge(p,y,C){const m=document.createElement("input");m.className="tools-pane-inline-input",m.value=y,m.type="text";const v=ho(p);p.replaceChildren(m),p.classList.add("tools-pane-editing"),m.focus(),m.select();function S(){fo(p,v)}function h(){const I=m.value.trim();p.classList.remove("tools-pane-editing"),I&&I!==y?C(I):S()}m.addEventListener("keydown",I=>{I.key==="Enter"&&(I.preventDefault(),h()),I.key==="Escape"&&(S(),p.classList.remove("tools-pane-editing"))}),m.addEventListener("blur",h)}function be(p){const y=new Map,C=new Map,m=new Map,v=new Set;for(const b of p.nodes)y.set(b.type,(y.get(b.type)??0)+1);for(const b of p.edges)C.set(b.type,(C.get(b.type)??0)+1),m.set(b.sourceId,(m.get(b.sourceId)??0)+1),m.set(b.targetId,(m.get(b.targetId)??0)+1),v.add(b.sourceId),v.add(b.targetId);const S=b=>Wn(b.properties)??b.id,h=p.nodes.filter(b=>b.properties._starred===!0).map(b=>({id:b.id,label:S(b),type:b.type})),I=p.nodes.filter(b=>!v.has(b.id)).map(b=>({id:b.id,label:S(b),type:b.type})),w=[...y.entries()].filter(([,b])=>b===1).map(([b])=>({name:b})),N=p.nodes.filter(b=>Object.keys(b.properties).length===0).map(b=>({id:b.id,label:b.id,type:b.type})),L=p.nodes.map(b=>({id:b.id,label:S(b),type:b.type,connections:m.get(b.id)??0})).filter(b=>b.connections>0).sort((b,M)=>M.connections-b.connections).slice(0,5);return{nodeCount:p.nodes.length,edgeCount:p.edges.length,types:[...y.entries()].sort((b,M)=>M[1]-b[1]).map(([b,M])=>({name:b,count:M})),edgeTypes:[...C.entries()].sort((b,M)=>M[1]-b[1]).map(([b,M])=>({name:b,count:M})),starred:h,orphans:I,singletons:w,emptyNodes:N,mostConnected:L}}return{collapse(){u=!0,Y.classList.add("hidden"),X.classList.remove("active")},addToFocusSet(p){for(const y of p)E.nodeIds.add(y);_(),K()},clearFocusSet(){E.types.clear(),E.nodeIds.clear(),_(),K()},setData(p){s=p,r=null,E.types.clear(),E.nodeIds.clear(),s&&s.nodes.length>0?(l=be(s),X.classList.remove("hidden"),K()):(l=null,X.classList.add("hidden"),Y.classList.add("hidden"))},setSnapshots(p){T=p,g==="controls"&&q()},setWalkTrail(p){A=p,K()}}}function Go(t){const e=Date.now()-new Date(t).getTime(),s=Math.floor(e/6e4);if(s<1)return"just now";if(s<60)return`${s}m ago`;const l=Math.floor(s/60);return l<24?`${l}h ago`:`${Math.floor(l/24)}d ago`}function Wn(t){for(const e of Object.values(t))if(typeof e=="string")return e;return null}function Vo(t,e){const s=e.split("+"),l=s.pop(),u=s.map(n=>n.toLowerCase()),r=u.includes("ctrl")||u.includes("cmd")||u.includes("meta"),d=u.includes("shift"),o=u.includes("alt");return r!==(t.ctrlKey||t.metaKey)||!r&&(t.ctrlKey||t.metaKey)||d&&!t.shiftKey||o!==t.altKey?!1:l.toLowerCase()==="escape"?t.key==="Escape":l.toLowerCase()==="tab"?t.key==="Tab":u.length>0?t.key.toLowerCase()===l.toLowerCase():t.key===l}function Jo(){return{search:"Focus search",searchAlt:"Focus search (alt)",undo:"Undo",redo:"Redo",help:"Toggle help",escape:"Exit focus / close panel",focus:"Focus on selected / exit focus",toggleEdges:"Toggle edges on/off",center:"Center view on graph",nextNode:"Next node in view",prevNode:"Previous node in view",nextConnection:"Next connection",prevConnection:"Previous connection",historyBack:"Node history back",historyForward:"Node history forward",hopsIncrease:"Increase hops",hopsDecrease:"Decrease hops",panLeft:"Pan left",panDown:"Pan down",panUp:"Pan up",panRight:"Pan right",panFastLeft:"Pan fast left",zoomOut:"Zoom out",zoomIn:"Zoom in",panFastRight:"Pan fast right",spacingDecrease:"Decrease spacing",spacingIncrease:"Increase spacing",clusteringDecrease:"Decrease clustering",clusteringIncrease:"Increase clustering",toggleSidebar:"Toggle sidebar",walkMode:"Toggle walk mode (in focus)",walkIsolate:"Isolate walk trail nodes",resetPins:"Release all pinned nodes (reset manual layout)"}}const Ko=[{key:"Click",description:"Select node"},{key:"Shift+Click",description:"Multi-select nodes"},{key:"Drag node",description:"Move & pin node (temporary)"},{key:"Drag selection",description:"Move selected group (temporary)"},{key:"Shift+drag empty",description:"Rubber-band select"},{key:"Drag empty",description:"Pan canvas"},{key:"Scroll",description:"Zoom in/out"}],Zo=["search","searchAlt","undo","redo","help","focus","toggleEdges","center","nextNode","prevNode","nextConnection","prevConnection","historyBack","historyForward","hopsIncrease","hopsDecrease","panLeft","panDown","panUp","panRight","panFastLeft","panFastRight","zoomIn","zoomOut","spacingDecrease","spacingIncrease","clusteringDecrease","clusteringIncrease","toggleSidebar","walkMode","walkIsolate","resetPins","escape"];function Qo(t){return t.split("+").map(e=>e.charAt(0).toUpperCase()+e.slice(1)).join("+")}function es(t,e){const s=Jo(),l=document.createElement("div");l.className="shortcuts-overlay hidden";const u=document.createElement("div");u.className="shortcuts-modal";const r=document.createElement("h3");r.className="shortcuts-title",r.textContent="Keyboard Shortcuts";const d=document.createElement("div");d.className="shortcuts-list";for(const c of Zo){const T=e[c];if(!T)continue;const A=document.createElement("div");A.className="shortcuts-row";const E=document.createElement("div");E.className="shortcuts-keys";const F=document.createElement("kbd");F.textContent=Qo(T),E.appendChild(F);const W=document.createElement("span");W.className="shortcuts-desc",W.textContent=s[c],A.appendChild(E),A.appendChild(W),d.appendChild(A)}for(const c of Ko){const T=document.createElement("div");T.className="shortcuts-row";const A=document.createElement("div");A.className="shortcuts-keys";const E=document.createElement("kbd");E.textContent=c.key,A.appendChild(E);const F=document.createElement("span");F.className="shortcuts-desc",F.textContent=c.description,T.appendChild(A),T.appendChild(F),d.appendChild(T)}const o=document.createElement("button");o.className="shortcuts-close",o.textContent="×",u.appendChild(o),u.appendChild(r),u.appendChild(d),l.appendChild(u),t.appendChild(l);function n(){l.classList.remove("hidden")}function g(){l.classList.add("hidden")}function i(){l.classList.toggle("hidden")}return o.addEventListener("click",g),l.addEventListener("click",c=>{c.target===l&&g()}),{show:n,hide:g,toggle:i}}function ts(t){const e=document.createElement("div");e.className="empty-state";const s=document.createElement("div");s.className="empty-state-bg";for(const A of["c1","c2","c3","c4","c5"]){const E=document.createElement("div");E.className=`empty-state-circle ${A}`,s.appendChild(E)}s.appendChild(at({size:0,viewBox:"0 0 400 300",className:"empty-state-lines"},[{tag:"line",attrs:{x1:80,y1:60,x2:220,y2:140,"stroke-width":"0.5",opacity:"0.15"}},{tag:"line",attrs:{x1:220,y1:140,x2:320,y2:80,"stroke-width":"0.5",opacity:"0.15"}},{tag:"line",attrs:{x1:220,y1:140,x2:160,y2:240,"stroke-width":"0.5",opacity:"0.15"}},{tag:"line",attrs:{x1:160,y1:240,x2:300,y2:220,"stroke-width":"0.5",opacity:"0.15"}}]));const l=s.querySelector(".empty-state-lines");l&&(l.removeAttribute("width"),l.removeAttribute("height"),l.setAttribute("preserveAspectRatio","xMidYMid slice")),e.appendChild(s);const u=document.createElement("div");u.className="empty-state-content";const r=document.createElement("div");r.className="empty-state-icon",r.appendChild(at({size:48,strokeWidth:1.5,strokeLinecap:"round",strokeLinejoin:"round"},[{tag:"path",attrs:{d:"M21 16V8a2 2 0 00-1-1.73l-7-4a2 2 0 00-2 0l-7 4A2 2 0 002 8v8a2 2 0 001 1.73l7 4a2 2 0 002 0l7-4A2 2 0 0022 16z"}},{tag:"polyline",attrs:{points:"3.27 6.96 12 12.01 20.73 6.96"}},{tag:"line",attrs:{x1:12,y1:22.08,x2:12,y2:12}}])),u.appendChild(r);const d=document.createElement("h2");d.className="empty-state-title",d.textContent="No learning graphs yet",u.appendChild(d);const o=document.createElement("p");o.className="empty-state-desc",o.textContent="Connect Backpack to Claude, then start a conversation. Claude will build your first learning graph automatically.",u.appendChild(o);const n=document.createElement("div");n.className="empty-state-setup";const g=document.createElement("div");g.className="empty-state-label",g.textContent="Add Backpack to Claude Code:";const i=document.createElement("code");i.className="empty-state-code",i.textContent="claude mcp add backpack-local -s user -- npx backpack-ontology@latest",n.append(g,i),u.appendChild(n);const c=document.createElement("p");c.className="empty-state-hint",c.append("Press ");const T=document.createElement("kbd");return T.textContent="?",c.appendChild(T),c.append(" for keyboard shortcuts"),u.appendChild(c),e.appendChild(u),t.appendChild(e),{show(){e.classList.remove("hidden")},hide(){e.classList.add("hidden")}}}const ns=30;function os(){let t=[],e=[];return{push(s){t.push(JSON.stringify(s)),t.length>ns&&t.shift(),e=[]},undo(s){return t.length===0?null:(e.push(JSON.stringify(s)),JSON.parse(t.pop()))},redo(s){return e.length===0?null:(t.push(JSON.stringify(s)),JSON.parse(e.pop()))},canUndo(){return t.length>0},canRedo(){return e.length>0},clear(){t=[],e=[]}}}function ss(t,e){let s=null;function l(d,o,n,g,i){u(),s=document.createElement("div"),s.className="context-menu",s.style.left=`${g}px`,s.style.top=`${i}px`;const c=[{label:n?"★ Unstar":"☆ Star",action:()=>e.onStar(d),premium:!1},{label:"◎ Focus on node",action:()=>e.onFocusNode(d),premium:!1},{label:"⑂ Explore in branch",action:()=>e.onExploreInBranch(d),premium:!1},{label:"⎘ Copy ID",action:()=>e.onCopyId(d),premium:!1}];e.onExpand&&c.push({label:"⊕ Expand node",action:()=>e.onExpand(d),premium:!0}),e.onExplainPath&&c.push({label:"↔ Explain path to…",action:()=>e.onExplainPath(d),premium:!0}),e.onEnrich&&c.push({label:"≡ Enrich from web",action:()=>e.onEnrich(d),premium:!0});let T=!1;for(const E of c){if(!T&&E.premium){const W=document.createElement("div");W.className="context-menu-separator",s.appendChild(W),T=!0}const F=document.createElement("div");F.className="context-menu-item",F.textContent=E.label,F.addEventListener("click",()=>{E.action(),u()}),s.appendChild(F)}t.appendChild(s);const A=s.getBoundingClientRect();A.right>window.innerWidth&&(s.style.left=`${g-A.width}px`),A.bottom>window.innerHeight&&(s.style.top=`${i-A.height}px`),setTimeout(()=>document.addEventListener("click",u),0),document.addEventListener("keydown",r)}function u(){s&&(s.remove(),s=null),document.removeEventListener("click",u),document.removeEventListener("keydown",r)}function r(d){d.key==="Escape"&&u()}return{show:l,hide:u}}function as(t){const e=document.createElement("button");return e.className="copy-prompt-btn",e.title="Copy a prompt about the current view to clipboard",e.textContent="Copy Prompt",e.addEventListener("click",async()=>{const s=t();if(!s.graphName||!s.data){kt("No graph loaded");return}const l=cs(s);try{await navigator.clipboard.writeText(l),kt("Prompt copied — paste into Claude")}catch{kt("Failed to copy to clipboard")}}),e}function Un(t){return Object.values(t.properties).find(s=>typeof s=="string")??t.id}function cs(t){const{graphName:e,data:s,selection:l,focus:u}=t,r=[];r.push(`I'm looking at the Backpack learning graph "${e}" in the viewer.`),r.push(`It has ${s.nodes.length} nodes and ${s.edges.length} edges.`);const d=new Map;for(const o of s.nodes)d.set(o.type,(d.get(o.type)??0)+1);if(d.size>0){const o=Array.from(d.entries()).sort((n,g)=>g[1]-n[1]).slice(0,8).map(([n,g])=>`${n} (${g})`).join(", ");r.push(`Node types: ${o}`)}if(u&&u.seedNodeIds.length>0){r.push(""),r.push(`I'm focused on ${u.seedNodeIds.length} seed node(s) at ${u.hops} hop(s):`);for(const o of u.seedNodeIds.slice(0,10)){const n=s.nodes.find(g=>g.id===o);n&&r.push(`- ${Un(n)} (type: ${n.type})`)}}if(l.length>0){r.push(""),r.push(`I have ${l.length} node(s) selected:`);for(const o of l.slice(0,20)){const n=s.nodes.find(i=>i.id===o);if(!n)continue;const g=Object.entries(n.properties).filter(([i])=>!i.startsWith("_")).slice(0,5).map(([i,c])=>`${i}=${JSON.stringify(c)}`).join(", ");r.push(`- ${Un(n)} (type: ${n.type}, id: ${o}${g?`, ${g}`:""})`)}}return r.push(""),r.push("If you have access to the Backpack MCP tools, please use them to answer questions about this graph (backpack_get_node, backpack_get_neighbors, backpack_search, etc)."),r.push(""),r.push("My question: "),r.join(`
6
+ `)}const is=200;let Gt=null,Vt=null;function ls(t){Gt=t,Vt===null&&(Vt=window.setTimeout(async()=>{const e=Gt;if(Gt=null,Vt=null,!!e)try{await fetch("/api/viewer-state",{method:"PUT",headers:{"Content-Type":"application/json"},body:JSON.stringify({...e,updatedAt:new Date().toISOString()})})}catch{}},is))}function rs(){const t=new Map;return{emit(e){const s=t.get(e);if(s)for(const l of s)try{l()}catch(u){console.error(`[backpack-viewer] event handler for ${e} threw:`,u)}},subscribe(e,s){let l=t.get(e);return l||(l=new Set,t.set(e,l)),l.add(s),()=>{const u=t.get(e);u==null||u.delete(s)}}}}const tn="1";function ds(t,e,s,l){function u(){return Date.now().toString(36)+Math.random().toString(36).slice(2,10)}function r(){const d=e.getGraph();if(!d)throw new Error("no graph loaded in viewer");return d}return{name:t,viewerApiVersion:tn,getGraph:()=>e.getGraph(),getGraphName:()=>e.getGraphName(),getSelection:()=>e.getSelection(),getFocus:()=>e.getFocus(),on(d,o){return e.subscribe(d,o)},async addNode(d,o){if(!d)throw new Error("addNode: type is required");const n=r();e.snapshotForUndo();const g=u(),i=new Date().toISOString();return n.nodes.push({id:g,type:d,properties:o,createdAt:i,updatedAt:i}),await e.saveCurrentGraph(),g},async updateNode(d,o){const g=r().nodes.find(i=>i.id===d);if(!g)throw new Error(`updateNode: node not found: ${d}`);e.snapshotForUndo(),g.properties={...g.properties,...o},g.updatedAt=new Date().toISOString(),await e.saveCurrentGraph()},async removeNode(d){const o=r();if(!o.nodes.find(g=>g.id===d))throw new Error(`removeNode: node not found: ${d}`);e.snapshotForUndo(),o.nodes=o.nodes.filter(g=>g.id!==d),o.edges=o.edges.filter(g=>g.sourceId!==d&&g.targetId!==d),await e.saveCurrentGraph()},async addEdge(d,o,n){if(!d||!o||!n)throw new Error("addEdge: sourceId, targetId, and type are required");const g=r();if(!g.nodes.find(c=>c.id===d))throw new Error(`addEdge: source not found: ${d}`);if(!g.nodes.find(c=>c.id===o))throw new Error(`addEdge: target not found: ${o}`);e.snapshotForUndo();const i=u();return g.edges.push({id:i,sourceId:d,targetId:o,type:n}),await e.saveCurrentGraph(),i},async removeEdge(d){const o=r();if(!o.edges.find(g=>g.id===d))throw new Error(`removeEdge: edge not found: ${d}`);e.snapshotForUndo(),o.edges=o.edges.filter(g=>g.id!==d),await e.saveCurrentGraph()},panToNode:d=>e.panToNode(d),focusNodes:(d,o)=>e.focusNodes(d,o),exitFocus:()=>e.exitFocus(),registerTaskbarIcon(d){return s.register(d)},mountPanel(d,o){return l.mount(t,d,o)},settings:{async get(d){const o=`/api/extensions/${encodeURIComponent(t)}/settings`,n=await fetch(o);if(!n.ok)return null;const g=await n.json();return d in g?g[d]:null},async set(d,o){const n=`/api/extensions/${encodeURIComponent(t)}/settings/${encodeURIComponent(d)}`,g=await fetch(n,{method:"PUT",headers:{"Content-Type":"application/json"},body:JSON.stringify({value:o})});if(!g.ok){const i=await g.text().catch(()=>"");throw new Error(`settings.set failed: ${i||g.status}`)}},async remove(d){const o=`/api/extensions/${encodeURIComponent(t)}/settings/${encodeURIComponent(d)}`,n=await fetch(o,{method:"DELETE"});if(!n.ok){const g=await n.text().catch(()=>"");throw new Error(`settings.remove failed: ${g||n.status}`)}}},async fetch(d,o={}){const n=`/api/extensions/${encodeURIComponent(t)}/fetch`,g={};if(o.headers)if(o.headers instanceof Headers)o.headers.forEach((c,T)=>{g[T]=c});else if(Array.isArray(o.headers))for(const[c,T]of o.headers)g[c]=T;else Object.assign(g,o.headers);const i=typeof o.body=="string"||o.body==null?o.body:(()=>{throw new Error("viewer.fetch only supports string bodies in v1")})();return fetch(n,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({url:d,method:o.method??"POST",headers:g,body:i})})}}}const ps="bottom-right";function us(t){const e={"top-left":t.topLeft,"top-right":t.topRight,"bottom-left":t.bottomLeft,"bottom-center":t.bottomCenter,"bottom-right":t.bottomRight},s={"top-left":0,"top-right":0,"bottom-left":0,"bottom-center":0,"bottom-right":0};function l(r){e[r].classList.toggle("has-icons",s[r]>0)}l("top-left"),l("top-right"),l("bottom-left"),l("bottom-center"),l("bottom-right");function u(r){const d=r.position??ps,o=e[d];if(!o)throw new Error(`unknown taskbar position: ${d}`);const n=document.createElement("button");if(n.className="extension-taskbar-icon",n.title=r.label,n.setAttribute("aria-label",r.label),r.iconText){const i=document.createElement("span");i.className="extension-taskbar-icon-symbol",i.textContent=r.iconText,n.appendChild(i)}const g=document.createElement("span");return g.className="extension-taskbar-icon-label",g.textContent=r.label,n.appendChild(g),n.addEventListener("click",()=>{try{r.onClick()}catch(i){console.error(`[backpack-viewer] taskbar icon "${r.label}" onClick threw:`,i)}}),o.appendChild(n),s[d]++,l(d),()=>{n.remove(),s[d]=Math.max(0,s[d]-1),l(d)}}return{register:u}}async function ms(t,e){const s=us(t.taskbarSlots);let l=[];try{const r=await fetch("/api/extensions");if(!r.ok)return console.warn(`[backpack-viewer] /api/extensions returned ${r.status}; no extensions will be loaded`),[];l=await r.json()}catch(r){return console.error(`[backpack-viewer] failed to fetch extensions list: ${r.message}`),[]}const u=[];for(const r of l){if(r.viewerApi!==tn){console.warn(`[backpack-viewer] extension "${r.name}" targets viewerApi "${r.viewerApi}" but this viewer supports "${tn}"; skipping`);continue}if(r.stylesheet)try{hs(r.name,r.stylesheet)}catch(o){console.error(`[backpack-viewer] extension "${r.name}" stylesheet load failed:`,o)}const d=ds(r.name,t,s,e);try{const g=(await import(`/extensions/${encodeURIComponent(r.name)}/${r.entry}`)).activate;if(typeof g!="function"){console.error(`[backpack-viewer] extension "${r.name}" has no exported activate(api) function; skipping`);continue}await g(d),u.push({info:r,api:d}),console.log(`[backpack-viewer] loaded extension "${r.name}" v${r.version}`)}catch(o){console.error(`[backpack-viewer] extension "${r.name}" failed to activate:`,o)}}return u}function hs(t,e){if(e.includes(".."))throw new Error(`stylesheet path "${e}" is invalid`);const s=document.createElement("link");s.rel="stylesheet",s.href=`/extensions/${encodeURIComponent(t)}/${e}`,s.dataset.extension=t,document.head.appendChild(s)}const fs={search:"/",searchAlt:"ctrl+k",undo:"ctrl+z",redo:"ctrl+shift+z",help:"?",escape:"Escape",focus:"f",toggleEdges:"e",center:"c",nextNode:".",prevNode:",",nextConnection:">",prevConnection:"<",historyBack:"(",historyForward:")",hopsIncrease:"=",hopsDecrease:"-",panLeft:"h",panDown:"j",panUp:"k",panRight:"l",panFastLeft:"H",zoomOut:"J",zoomIn:"K",panFastRight:"L",spacingDecrease:"[",spacingIncrease:"]",clusteringDecrease:"{",clusteringIncrease:"}",toggleSidebar:"Tab",walkMode:"w",walkIsolate:"i",resetPins:"r"},gs={host:"127.0.0.1",port:5173},ys={edges:!0,edgeLabels:!0,typeHulls:!0,minimap:!0,theme:"system"},Cs={spacing:1.5,clustering:.08},bs={panSpeed:60,panFastMultiplier:3,zoomFactor:1.3,zoomMin:.05,zoomMax:10,panAnimationMs:300},vs={hideBadges:.4,hideLabels:.25,hideEdgeLabels:.35,smallNodes:.2,hideArrows:.15},xs={pulseSpeed:.02},Es={maxSearchResults:8,maxQualityItems:5,maxMostConnected:5,searchDebounceMs:150},ws={disabled:[],external:[]},ks={keybindings:fs,server:gs,display:ys,layout:Cs,navigation:bs,lod:vs,walk:xs,limits:Es,extensions:ws};let ae="",P=null,Jt=new Set,Kt=!1;async function Ss(){var St,mt;const t=document.getElementById("canvas-container"),e={...ks};try{const a=await fetch("/api/config");if(a.ok){const x=await a.json();Object.assign(e.keybindings,x.keybindings??{}),Object.assign(e.display,x.display??{}),Object.assign(e.layout,x.layout??{}),Object.assign(e.navigation,x.navigation??{}),Object.assign(e.lod,x.lod??{}),Object.assign(e.limits,x.limits??{})}}catch{}const s=e.keybindings,l=window.matchMedia("(prefers-color-scheme: dark)"),u=e.display.theme==="system"?l.matches?"dark":"light":e.display.theme,d=localStorage.getItem("backpack-theme")??u;document.documentElement.setAttribute("data-theme",d);const o=document.createElement("button");o.className="theme-toggle",o.textContent=d==="light"?"☾":"☼",o.title="Toggle light/dark mode",o.addEventListener("click",()=>{const x=document.documentElement.getAttribute("data-theme")==="light"?"dark":"light";document.documentElement.setAttribute("data-theme",x),localStorage.setItem("backpack-theme",x),o.textContent=x==="light"?"☾":"☼"}),t.appendChild(o);const n=os();async function g(){if(!ae||!P)return;P.metadata.updatedAt=new Date().toISOString(),await zt(ae,P),c.loadGraph(P),te.setLearningGraphData(P),G.setData(P);const a=await vt();M.setSummaries(a),pe.emit("graph-changed")}async function i(a){P=a,await zt(ae,P),c.loadGraph(P),te.setLearningGraphData(P),G.setData(P);const x=await vt();M.setSummaries(x)}let c;const T=Yo(t),A=Fo(t,T,{onUpdateNode(a,x){if(!P)return;n.push(P);const R=P.nodes.find(j=>j.id===a);R&&(R.properties={...R.properties,...x},R.updatedAt=new Date().toISOString(),g().then(()=>A.show([a],P)))},onChangeNodeType(a,x){if(!P)return;n.push(P);const R=P.nodes.find(j=>j.id===a);R&&(R.type=x,R.updatedAt=new Date().toISOString(),g().then(()=>A.show([a],P)))},onDeleteNode(a){P&&(n.push(P),P.nodes=P.nodes.filter(x=>x.id!==a),P.edges=P.edges.filter(x=>x.sourceId!==a&&x.targetId!==a),g())},onDeleteEdge(a){var R;if(!P)return;n.push(P);const x=(R=P.edges.find(j=>j.id===a))==null?void 0:R.sourceId;P.edges=P.edges.filter(j=>j.id!==a),g().then(()=>{x&&P&&A.show([x],P)})},onAddProperty(a,x,R){if(!P)return;n.push(P);const j=P.nodes.find(ne=>ne.id===a);j&&(j.properties[x]=R,j.updatedAt=new Date().toISOString(),g().then(()=>A.show([a],P)))}},a=>{c.panToNode(a)},a=>{G.addToFocusSet(a)}),E=window.matchMedia("(max-width: 768px)");let F=[],W=e.display.edges,V=e.navigation.panSpeed,_=-1,X=null;function Y(a){X&&X.remove(),X=document.createElement("div"),X.className="focus-indicator";const x=document.createElement("span");x.className="focus-indicator-label",x.textContent=`Focused: ${a.totalNodes} nodes`;const R=document.createElement("span");R.className="focus-indicator-hops",R.textContent=`${a.hops}`;const j=document.createElement("button");j.className="focus-indicator-btn",j.textContent="−",j.title="Fewer hops",j.disabled=a.hops===0,j.addEventListener("click",()=>{c.enterFocus(a.seedNodeIds,Math.max(0,a.hops-1))});const ne=document.createElement("button");ne.className="focus-indicator-btn",ne.textContent="+",ne.title="More hops",ne.disabled=!1,ne.addEventListener("click",()=>{c.enterFocus(a.seedNodeIds,a.hops+1)});const de=document.createElement("button");de.className="focus-indicator-btn focus-indicator-exit",de.textContent="×",de.title="Exit focus (Esc)",de.addEventListener("click",()=>G.clearFocusSet());const ie=document.createElement("button");ie.className="walk-indicator",c.getWalkMode()&&ie.classList.add("active"),ie.textContent="Walk",ie.title="Toggle walk mode (W) — click nodes to traverse",ie.addEventListener("click",()=>{c.setWalkMode(!c.getWalkMode()),ie.classList.toggle("active",c.getWalkMode())}),X.appendChild(x),X.appendChild(j),X.appendChild(R),X.appendChild(ne),X.appendChild(ie),X.appendChild(de)}function K(){X&&(X.remove(),X=null)}const q=document.createElement("div");q.className="path-bar hidden";function me(a){if(q.replaceChildren(),!P)return;for(let R=0;R<a.nodeIds.length;R++){const j=a.nodeIds[R],ne=P.nodes.find(he=>he.id===j);if(!ne)continue;const de=Object.values(ne.properties).find(he=>typeof he=="string")??ne.id;if(R>0){const he=a.edgeIds[R-1],Me=P.edges.find(Ge=>Ge.id===he),xe=document.createElement("span");xe.className="path-bar-edge",xe.textContent=Me?`→ ${Me.type} →`:"→",q.appendChild(xe)}const ie=document.createElement("span");ie.className="path-bar-node",ie.textContent=de,ie.addEventListener("click",()=>c.panToNode(j)),q.appendChild(ie)}const x=document.createElement("button");x.className="path-bar-close",x.textContent="×",x.addEventListener("click",U),q.appendChild(x),q.classList.remove("hidden")}function U(){q.classList.add("hidden"),q.replaceChildren(),c.clearHighlightedPath()}const pe=rs();function Ee(){ae&&ls({graph:ae,selection:F,focus:(c==null?void 0:c.getFocusInfo())??null})}c=Bo(t,a=>{if(F=a??[],Ee(),pe.emit("selection-changed"),!c.getWalkMode())if(a&&a.length===2){const x=c.findPath(a[0],a[1]);x&&x.nodeIds.length>0?(c.setHighlightedPath(x.nodeIds,x.edgeIds),me(x)):U()}else U();a&&a.length>0&&P?(A.show(a,P),E.matches&&G.collapse(),Re(ae,a)):(A.hide(),ae&&Re(ae))},a=>{if(a){Y(a);const x=t.querySelector(".canvas-top-left");x&&X&&x.appendChild(X),Re(ae,a.seedNodeIds),A.setFocusDisabled(a.hops===0),Q()}else K(),A.setFocusDisabled(!1),ae&&Re(ae),Q();Ee(),pe.emit("focus-changed")},{lod:e.lod,navigation:e.navigation,walk:e.walk});const te=qo(t,{maxResults:e.limits.maxSearchResults,debounceMs:e.limits.searchDebounceMs}),G=Xo(t,{onFilterByType(a){if(P)if(a===null)c.setFilteredNodeIds(null);else{const x=new Set(((P==null?void 0:P.nodes)??[]).filter(R=>R.type===a).map(R=>R.id));c.setFilteredNodeIds(x)}},onNavigateToNode(a){c.panToNode(a),P&&A.show([a],P)},onWalkTrailRemove(a){c.removeFromWalkTrail(a),Q()},onWalkIsolate(){if(!P)return;const a=c.getWalkTrail();a.length!==0&&c.enterFocus(a,0)},async onWalkSaveSnippet(a){if(!ae||!P)return;const x=c.getWalkTrail();if(x.length<2)return;const R=new Set(x),j=P.edges.filter(ne=>R.has(ne.sourceId)&&R.has(ne.targetId)).map(ne=>ne.id);await yn(ae,a,x,j),await ue(ae)},async onStarredSaveSnippet(a,x){if(!ae||!P)return;const R=new Set(x),j=P.edges.filter(ne=>R.has(ne.sourceId)&&R.has(ne.targetId)).map(ne=>ne.id);await yn(ae,a,x,j),await ue(ae)},onFocusChange(a){a&&a.length>0?c.enterFocus(a,0):c.isFocused()&&c.exitFocus()},onRenameNodeType(a,x){if(P){n.push(P);for(const R of P.nodes)R.type===a&&(R.type=x,R.updatedAt=new Date().toISOString());g()}},onRenameEdgeType(a,x){if(P){n.push(P);for(const R of P.edges)R.type===a&&(R.type=x);g()}},onToggleEdgeLabels(a){c.setEdgeLabels(a)},onToggleTypeHulls(a){c.setTypeHulls(a)},onToggleMinimap(a){c.setMinimap(a)},onLayoutChange(a,x){lt({[a]:x}),c.reheat()},onPanSpeedChange(a){V=a},onExport(a){const x=c.exportImage(a);if(!x)return;const R=document.createElement("a");R.download=`${ae||"graph"}.${a}`,R.href=x,R.click()},onSnapshot:async a=>{ae&&(await io(ae,a),await re(ae))},onRollback:async a=>{ae&&(await lo(ae,a),P=await Pt(ae),c.loadGraph(P),te.setLearningGraphData(P),G.setData(P),await re(ae))},onOpen(){E.matches&&A.hide()}}),ye=document.createElement("div");ye.className="canvas-top-bar";const Ce=document.createElement("div");Ce.className="canvas-top-left";const se=document.createElement("div");se.className="canvas-top-center";const ge=document.createElement("div");ge.className="canvas-top-right";const be=t.querySelector(".tools-pane-toggle");be&&Ce.appendChild(be);const p=t.querySelector(".zoom-controls");p&&ge.appendChild(p),ge.appendChild(o);const y=document.createElement("div");y.className="ext-slot ext-slot-top-left",se.appendChild(y);const C=t.querySelector(".search-overlay");C&&se.appendChild(C);const m=document.createElement("div");m.className="ext-slot ext-slot-top-right",se.appendChild(m);const v=as(()=>({graphName:ae,data:P,selection:F,focus:c.getFocusInfo()}));se.appendChild(v),ye.appendChild(Ce),ye.appendChild(se),ye.appendChild(ge),t.appendChild(ye);const S=document.createElement("div");S.className="canvas-bottom-bar";const h=document.createElement("div");h.className="canvas-bottom-left";const I=document.createElement("div");I.className="canvas-bottom-center";const w=document.createElement("div");w.className="canvas-bottom-right";const N=document.createElement("div");N.className="ext-slot ext-slot-bottom-left",h.appendChild(N);const L=document.createElement("div");L.className="ext-slot ext-slot-bottom-center",I.appendChild(L),I.appendChild(q);const b=document.createElement("div");b.className="ext-slot ext-slot-bottom-right",w.appendChild(b),S.appendChild(h),S.appendChild(I),S.appendChild(w),t.appendChild(S),te.onFilterChange(a=>{c.setFilteredNodeIds(a)}),te.onNodeSelect(a=>{c.isFocused()&&G.clearFocusSet(),c.panToNode(a),P&&A.show([a],P)});const M=go(document.getElementById("sidebar"),{onSelect:a=>ct(a),onRename:async(a,x)=>{await oo(a,x),ae===a&&(ae=x);const R=await vt();M.setSummaries(R),M.setActive(ae),ae===x&&(P=await Pt(x),c.loadGraph(P),te.setLearningGraphData(P),G.setData(P))},onBranchSwitch:async(a,x)=>{await gn(a,x),await ce(a),P=await Pt(a),c.loadGraph(P),te.setLearningGraphData(P),G.setData(P),await re(a)},onBranchCreate:async(a,x)=>{await fn(a,x),await ce(a)},onBranchDelete:async(a,x)=>{await ao(a,x),await ce(a)},onSnippetLoad:async(a,x)=>{var j;const R=await po(a,x);((j=R==null?void 0:R.nodeIds)==null?void 0:j.length)>0&&c.enterFocus(R.nodeIds,0)},onSnippetDelete:async(a,x)=>{await uo(a,x),await ue(a)},onBackpackSwitch:async a=>{await fetch("/api/backpacks/switch",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({name:a})}),await $()},onBackpackRegister:async(a,x)=>{await fetch("/api/backpacks",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({path:a,activate:x})}),await $()}});async function $(){try{const x=await(await fetch("/api/backpacks")).json();M.setBackpacks(x)}catch{}try{const a=await vt();M.setSummaries(a),ae&&!a.some(x=>x.name===ae)&&(ae="",P=null,c.loadGraph({metadata:{name:"",description:"",createdAt:"",updatedAt:""},nodes:[],edges:[]}))}catch{}}function Q(){const a=c.getWalkTrail();if(!P||a.length===0){G.setWalkTrail([]),U();return}const x=[],R=a.map((j,ne)=>{const de=P.nodes.find(he=>he.id===j);let ie;if(ne>0){const he=a[ne-1],Me=P.edges.find(xe=>xe.sourceId===he&&xe.targetId===j||xe.targetId===he&&xe.sourceId===j);ie=Me==null?void 0:Me.type,Me&&x.push(Me.id)}return{id:j,label:de?Object.values(de.properties).find(he=>typeof he=="string")??de.id:j,type:(de==null?void 0:de.type)??"?",edgeType:ie}});G.setWalkTrail(R),a.length>=2?(c.setHighlightedPath(a,x),me({nodeIds:a,edgeIds:x})):U()}async function ce(a){const x=await so(a),R=x.find(j=>j.active);R&&M.setActiveBranch(a,R.name,x)}async function re(a){const x=await co(a);G.setSnapshots(x)}async function ue(a){const x=await ro(a);M.setSnippets(a,x)}Ce.insertBefore(M.expandBtn,Ce.firstChild);const ve=es(t,s),$e=ts(t),Qe=ss(t,{onStar(a){if(!P)return;const x=P.nodes.find(j=>j.id===a);if(!x)return;const R=x.properties._starred===!0;x.properties._starred=!R,zt(ae,P),c.loadGraph(P)},onFocusNode(a){G.addToFocusSet([a])},onExploreInBranch(a){if(ae){const x=`explore-${a.slice(0,8)}`;fn(ae,x).then(()=>{gn(ae,x).then(()=>{c.enterFocus([a],1)})})}},onCopyId(a){navigator.clipboard.writeText(a)}});t.addEventListener("contextmenu",a=>{a.preventDefault();const x=t.querySelector("canvas");if(!x||!P)return;const R=x.getBoundingClientRect(),j=a.clientX-R.left,ne=a.clientY-R.top,de=c.nodeAtScreen(j,ne);if(!de)return;const ie=P.nodes.find(xe=>xe.id===de.id);if(!ie)return;const he=Object.values(ie.properties).find(xe=>typeof xe=="string")??ie.id,Me=ie.properties._starred===!0;Qe.show(ie.id,he,Me,a.clientX-R.left,a.clientY-R.top)}),e.display.edges||c.setEdges(!1),e.display.edgeLabels||c.setEdgeLabels(!1),e.display.typeHulls||c.setTypeHulls(!1),e.display.minimap||c.setMinimap(!1);function Re(a,x){const R=[];x!=null&&x.length&&R.push("node="+x.map(encodeURIComponent).join(","));const j=c.getFocusInfo();j&&(R.push("focus="+j.seedNodeIds.map(encodeURIComponent).join(",")),R.push("hops="+j.hops));const ne="#"+encodeURIComponent(a)+(R.length?"?"+R.join("&"):"");history.replaceState(null,"",ne)}function et(){const a=window.location.hash.slice(1);if(!a)return{graph:null,nodes:[],focus:[],hops:1};const[x,R]=a.split("?"),j=x?decodeURIComponent(x):null;let ne=[],de=[],ie=1;if(R){const he=new URLSearchParams(R),Me=he.get("node");Me&&(ne=Me.split(",").map(decodeURIComponent));const xe=he.get("focus");xe&&(de=xe.split(",").map(decodeURIComponent));const Ge=he.get("hops");Ge&&(ie=Math.max(0,parseInt(Ge,10)||1))}return{graph:j,nodes:ne,focus:de,hops:ie}}async function ct(a,x,R,j){ae=a,Kt=Jt.has(a),M.setActive(a),A.hide(),K(),te.clear(),n.clear(),P=Kt?await no(a):await Pt(a);const ne=xo(P.nodes.length);if(lt({spacing:Math.max(e.layout.spacing,ne.spacing),clusterStrength:Math.max(e.layout.clustering,ne.clusterStrength)}),c.loadGraph(P),te.setLearningGraphData(P),G.setData(P),$e.hide(),Re(a),Ee(),pe.emit("graph-switched"),pe.emit("graph-changed"),Kt||(await ce(a),await re(a),await ue(a)),R!=null&&R.length&&P){const de=R.filter(ie=>P.nodes.some(he=>he.id===ie));if(de.length){setTimeout(()=>{c.enterFocus(de,j??1)},500);return}}if(x!=null&&x.length&&P){const de=x.filter(ie=>P.nodes.some(he=>he.id===ie));de.length&&setTimeout(()=>{c.panToNodes(de),P&&A.show(de,P),Re(a,de)},500)}}try{const x=await(await fetch("/api/backpacks")).json();M.setBackpacks(x)}catch{}fetch("/api/version-check").then(a=>a.json()).then(a=>{a.stale&&a.latest&&M.setStaleVersionBanner(a.current,a.latest)}).catch(()=>{});const Xe=new URLSearchParams(window.location.search).get("share");if(Xe)try{const a=await fetch(`/v1/share/${Xe}/meta`);if(!a.ok)throw new Error("Share link not found or expired");const x=await a.json(),R=await fetch(`/v1/share/${Xe}`);if(!R.ok)throw new Error("Failed to download shared backpack");const j=new Uint8Array(await R.arrayBuffer());if(j.length<9||j[0]!==66||j[1]!==80||j[2]!==65||j[3]!==75)throw new Error("Invalid share data: not a BPAK envelope");const ne=new DataView(j.buffer,j.byteOffset,j.byteLength).getUint32(5,!1);if(9+ne>j.length)throw new Error("Invalid envelope: header length exceeds data");const de=JSON.parse(new TextDecoder().decode(j.slice(9,9+ne))),ie=j.slice(9+ne);let he;if(de.format!=="plaintext"){const Me=window.location.hash.slice(1),xe=new URLSearchParams(Me).get("k")??Me.split("k=")[1];if(!xe)throw new Error("Missing decryption key in URL fragment");const{Decrypter:Ge}=await eo(async()=>{const{Decrypter:ft}=await import("./index-D-H7agBH.js");return{Decrypter:ft}},[]),Nt=atob(xe.replace(/-/g,"+").replace(/_/g,"/")),ht=new Ge;ht.addIdentity(Nt);const Lt=await ht.decrypt(ie);he=JSON.parse(new TextDecoder().decode(Lt))}else he=JSON.parse(new TextDecoder().decode(ie));ae=x.backpack_name||"Shared Backpack",P=he,c.loadGraph(he),te.setLearningGraphData(he),M.setSummaries([{name:ae,description:"",nodeCount:((St=he.nodes)==null?void 0:St.length)??0,edgeCount:((mt=he.edges)==null?void 0:mt.length)??0,nodeTypes:[]}]),M.setActive(ae),document.title=`${ae} — Backpack`}catch(a){const x=a instanceof Error?a.message:"Failed to load shared backpack";kt(x,5e3),$e.show()}else{const[a,x]=await Promise.all([vt(),to().catch(()=>[])]);M.setSummaries(a),M.setRemotes(x),Jt=new Set(x.map(ne=>ne.name));const R=et(),j=R.graph&&a.some(ne=>ne.name===R.graph)||R.graph&&Jt.has(R.graph)?R.graph:a.length>0?a[0].name:x.length>0?x[0].name:null;j?await ct(j,R.nodes.length?R.nodes:void 0,R.focus.length?R.focus:void 0,R.hops):$e.show()}ms({getGraph:()=>P,getGraphName:()=>ae,getSelection:()=>[...F],getFocus:()=>c.getFocusInfo(),saveCurrentGraph:async()=>{await g()},snapshotForUndo:()=>{P&&n.push(P)},panToNode:a=>c.panToNode(a),focusNodes:(a,x)=>c.enterFocus(a,x),exitFocus:()=>{c.isFocused()&&c.exitFocus()},taskbarSlots:{topLeft:y,topRight:m,bottomLeft:N,bottomCenter:L,bottomRight:b},subscribe:(a,x)=>pe.subscribe(a,x)},T).catch(a=>{console.error("[backpack-viewer] extension loader failed:",a)});const ut={search(){te.focus()},searchAlt(){te.focus()},undo(){if(P){const a=n.undo(P);a&&i(a)}},redo(){if(P){const a=n.redo(P);a&&i(a)}},focus(){c.isFocused()?G.clearFocusSet():F.length>0&&G.addToFocusSet(F)},hopsDecrease(){const a=c.getFocusInfo();a&&a.hops>0&&c.enterFocus(a.seedNodeIds,a.hops-1)},hopsIncrease(){const a=c.getFocusInfo();a&&c.enterFocus(a.seedNodeIds,a.hops+1)},nextNode(){const a=c.getNodeIds();a.length>0&&(_=(_+1)%a.length,c.panToNode(a[_]),P&&A.show([a[_]],P))},prevNode(){const a=c.getNodeIds();a.length>0&&(_=_<=0?a.length-1:_-1,c.panToNode(a[_]),P&&A.show([a[_]],P))},nextConnection(){const a=A.cycleConnection(1);a&&c.panToNode(a)},prevConnection(){const a=A.cycleConnection(-1);a&&c.panToNode(a)},historyBack(){A.goBack()},historyForward(){A.goForward()},center(){c.centerView()},toggleEdges(){W=!W,c.setEdges(W)},panLeft(){c.panBy(-V,0)},panDown(){c.panBy(0,V)},panUp(){c.panBy(0,-V)},panRight(){c.panBy(V,0)},panFastLeft(){c.panBy(-V*e.navigation.panFastMultiplier,0)},zoomOut(){c.zoomBy(1/e.navigation.zoomFactor)},zoomIn(){c.zoomBy(e.navigation.zoomFactor)},panFastRight(){c.panBy(V*e.navigation.panFastMultiplier,0)},spacingDecrease(){const a=wt();lt({spacing:Math.max(.5,a.spacing-.5)}),c.reheat()},spacingIncrease(){const a=wt();lt({spacing:Math.min(20,a.spacing+.5)}),c.reheat()},clusteringDecrease(){const a=wt();lt({clusterStrength:Math.max(0,a.clusterStrength-.03)}),c.reheat()},clusteringIncrease(){const a=wt();lt({clusterStrength:Math.min(1,a.clusterStrength+.03)}),c.reheat()},help(){ve.toggle()},toggleSidebar(){M.toggle()},resetPins(){c.releaseAllPins()&&kt("Manual layout reset — pins released")},walkIsolate(){if(!P)return;const a=c.getWalkTrail();a.length!==0&&c.enterFocus(a,0)},walkMode(){!c.isFocused()&&F.length>0&&G.addToFocusSet(F),c.setWalkMode(!c.getWalkMode());const a=t.querySelector(".walk-indicator");a&&a.classList.toggle("active",c.getWalkMode()),Q()},escape(){c.getSelectedNodeIds().length>0?c.clearSelection():c.isFocused()?G.clearFocusSet():ve.hide()}};document.addEventListener("keydown",a=>{var x;if(!(a.target instanceof HTMLInputElement||a.target instanceof HTMLTextAreaElement)){for(const[R,j]of Object.entries(s))if(Vo(a,j)){(R==="search"||R==="searchAlt"||R==="undo"||R==="redo"||R==="toggleSidebar")&&a.preventDefault(),(x=ut[R])==null||x.call(ut);return}}}),window.addEventListener("hashchange",()=>{const a=et();if(a.graph&&a.graph!==ae)ct(a.graph,a.nodes.length?a.nodes:void 0,a.focus.length?a.focus:void 0,a.hops);else if(a.graph&&a.focus.length&&P)c.enterFocus(a.focus,a.hops);else if(a.graph&&a.nodes.length&&P){c.isFocused()&&c.exitFocus();const x=a.nodes.filter(R=>P.nodes.some(j=>j.id===R));x.length&&(c.panToNodes(x),A.show(x,P))}})}Ss();
@@ -4,8 +4,8 @@
4
4
  <meta charset="UTF-8" />
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
6
  <title>Backpack Viewer</title>
7
- <script type="module" crossorigin src="/assets/index-T18UaBDP.js"></script>
8
- <link rel="stylesheet" crossorigin href="/assets/index-DE73ngo-.css">
7
+ <script type="module" crossorigin src="/assets/index-DrsNxqo-.js"></script>
8
+ <link rel="stylesheet" crossorigin href="/assets/index-BbX2AsyK.css">
9
9
  </head>
10
10
  <body>
11
11
  <div id="app">
@@ -4,7 +4,7 @@ function I(e) {
4
4
  e.registerTaskbarIcon({
5
5
  label: "Share",
6
6
  iconText: "↗",
7
- position: "bottom-right",
7
+ position: "bottom-center",
8
8
  onClick: () => N(e)
9
9
  });
10
10
  }
@@ -18,7 +18,7 @@ function N(e) {
18
18
  const n = document.createElement("div");
19
19
  n.className = "share-panel-body", m ? (m.element.replaceChildren(), m.element.appendChild(n), m.setTitle(`Share "${t}"`), m.setVisible(!0), m.bringToFront()) : (n.textContent = "Loading...", m = e.mountPanel(n, {
20
20
  title: `Share "${t}"`,
21
- defaultPosition: { left: window.innerWidth - 420, top: 80 },
21
+ defaultPosition: { left: Math.max(100, (window.innerWidth - 380) / 2), top: Math.max(80, (window.innerHeight - 300) / 2) },
22
22
  showFullscreenButton: !1,
23
23
  onClose: () => {
24
24
  m = null;
@@ -1,25 +1,24 @@
1
1
  import type { TaskbarIconOptions } from "./types";
2
2
  /**
3
- * Extension taskbar — routes registered icons into one of four slot
3
+ * Extension taskbar — routes registered icons into one of five slot
4
4
  * containers based on the icon's `position`. Slots are owned by the
5
5
  * host (created in main.ts) so the viewer controls where each slot
6
6
  * lives in the DOM:
7
7
  *
8
- * - top-left, top-right → nested into the existing top bar
9
- * alongside zoom/theme controls
10
- * - bottom-left, bottom-right → floating in the canvas corners
11
- *
12
- * No slot lives at bottom-center; that area is reserved for the
13
- * viewer's path bar so the two never overlap.
8
+ * - top-left, top-right → nested into the existing top bar
9
+ * alongside zoom/theme controls
10
+ * - bottom-left, bottom-center,
11
+ * bottom-right → inside the bottom bar columns
14
12
  *
15
13
  * Each slot tracks its own icon count so it can toggle a `.has-icons`
16
- * class — bottom corner slots use it to stay invisible (and take no
17
- * space) until at least one extension is active.
14
+ * class — bottom slots use it to stay invisible (and take no space)
15
+ * until at least one extension is active.
18
16
  */
19
17
  export interface TaskbarSlots {
20
18
  topLeft: HTMLElement;
21
19
  topRight: HTMLElement;
22
20
  bottomLeft: HTMLElement;
21
+ bottomCenter: HTMLElement;
23
22
  bottomRight: HTMLElement;
24
23
  }
25
24
  export interface Taskbar {
@@ -4,6 +4,7 @@ export function createTaskbar(slots) {
4
4
  "top-left": slots.topLeft,
5
5
  "top-right": slots.topRight,
6
6
  "bottom-left": slots.bottomLeft,
7
+ "bottom-center": slots.bottomCenter,
7
8
  "bottom-right": slots.bottomRight,
8
9
  };
9
10
  // Per-slot icon count so we can toggle visibility cleanly.
@@ -11,6 +12,7 @@ export function createTaskbar(slots) {
11
12
  "top-left": 0,
12
13
  "top-right": 0,
13
14
  "bottom-left": 0,
15
+ "bottom-center": 0,
14
16
  "bottom-right": 0,
15
17
  };
16
18
  function refreshVisibility(pos) {
@@ -22,6 +24,7 @@ export function createTaskbar(slots) {
22
24
  refreshVisibility("top-left");
23
25
  refreshVisibility("top-right");
24
26
  refreshVisibility("bottom-left");
27
+ refreshVisibility("bottom-center");
25
28
  refreshVisibility("bottom-right");
26
29
  function register(opts) {
27
30
  const pos = opts.position ?? DEFAULT_POSITION;
@@ -45,7 +45,7 @@ export interface ViewerExtensionAPI {
45
45
  settings: ExtensionSettingsAPI;
46
46
  fetch(url: string, init?: RequestInit): Promise<Response>;
47
47
  }
48
- export type TaskbarPosition = "top-left" | "top-right" | "bottom-left" | "bottom-right";
48
+ export type TaskbarPosition = "top-left" | "top-right" | "bottom-left" | "bottom-center" | "bottom-right";
49
49
  export interface TaskbarIconOptions {
50
50
  /** Visible button text and accessible label */
51
51
  label: string;
@@ -55,9 +55,6 @@ export interface TaskbarIconOptions {
55
55
  * Where to place the icon. Top slots nest into the viewer's existing
56
56
  * top bar (alongside zoom/theme controls); bottom slots float in the
57
57
  * canvas corners. Default: "bottom-right".
58
- *
59
- * The bottom-center area is reserved for the viewer's path bar — no
60
- * slot lives there to avoid overlap.
61
58
  */
62
59
  position?: TaskbarPosition;
63
60
  /** Click handler — usually toggles a panel */
@@ -175,6 +172,7 @@ export interface ViewerHost {
175
172
  topLeft: HTMLElement;
176
173
  topRight: HTMLElement;
177
174
  bottomLeft: HTMLElement;
175
+ bottomCenter: HTMLElement;
178
176
  bottomRight: HTMLElement;
179
177
  };
180
178
  /** Subscribe to events emitted by the host. */
package/dist/main.js CHANGED
@@ -221,10 +221,9 @@ async function main() {
221
221
  focusIndicator = null;
222
222
  }
223
223
  }
224
- // --- Path bar ---
224
+ // --- Path bar (appended to bottom-center column later) ---
225
225
  const pathBar = document.createElement("div");
226
226
  pathBar.className = "path-bar hidden";
227
- canvasContainer.appendChild(pathBar);
228
227
  function showPathBar(path) {
229
228
  pathBar.replaceChildren();
230
229
  if (!currentData)
@@ -510,16 +509,33 @@ async function main() {
510
509
  focus: canvas.getFocusInfo(),
511
510
  }));
512
511
  topCenter.appendChild(copyPromptBtn);
513
- const extSlotBottomLeft = document.createElement("div");
514
- extSlotBottomLeft.className = "ext-slot ext-slot-bottom-left";
515
- canvasContainer.appendChild(extSlotBottomLeft);
516
- const extSlotBottomRight = document.createElement("div");
517
- extSlotBottomRight.className = "ext-slot ext-slot-bottom-right";
518
- canvasContainer.appendChild(extSlotBottomRight);
519
512
  topBar.appendChild(topLeft);
520
513
  topBar.appendChild(topCenter);
521
514
  topBar.appendChild(topRight);
522
515
  canvasContainer.appendChild(topBar);
516
+ // --- Bottom bar: mirrors top bar structure at the bottom of the canvas ---
517
+ const bottomBar = document.createElement("div");
518
+ bottomBar.className = "canvas-bottom-bar";
519
+ const bottomLeft = document.createElement("div");
520
+ bottomLeft.className = "canvas-bottom-left";
521
+ const bottomCenter = document.createElement("div");
522
+ bottomCenter.className = "canvas-bottom-center";
523
+ const bottomRight = document.createElement("div");
524
+ bottomRight.className = "canvas-bottom-right";
525
+ const extSlotBottomLeft = document.createElement("div");
526
+ extSlotBottomLeft.className = "ext-slot ext-slot-bottom-left";
527
+ bottomLeft.appendChild(extSlotBottomLeft);
528
+ const extSlotBottomCenter = document.createElement("div");
529
+ extSlotBottomCenter.className = "ext-slot ext-slot-bottom-center";
530
+ bottomCenter.appendChild(extSlotBottomCenter);
531
+ bottomCenter.appendChild(pathBar);
532
+ const extSlotBottomRight = document.createElement("div");
533
+ extSlotBottomRight.className = "ext-slot ext-slot-bottom-right";
534
+ bottomRight.appendChild(extSlotBottomRight);
535
+ bottomBar.appendChild(bottomLeft);
536
+ bottomBar.appendChild(bottomCenter);
537
+ bottomBar.appendChild(bottomRight);
538
+ canvasContainer.appendChild(bottomBar);
523
539
  search.onFilterChange((ids) => {
524
540
  canvas.setFilteredNodeIds(ids);
525
541
  });
@@ -960,6 +976,7 @@ async function main() {
960
976
  topLeft: extSlotTopLeft,
961
977
  topRight: extSlotTopRight,
962
978
  bottomLeft: extSlotBottomLeft,
979
+ bottomCenter: extSlotBottomCenter,
963
980
  bottomRight: extSlotBottomRight,
964
981
  },
965
982
  subscribe: (event, cb) => eventBus.subscribe(event, cb),
package/dist/style.css CHANGED
@@ -687,6 +687,36 @@ body {
687
687
  justify-content: center;
688
688
  }
689
689
 
690
+ /* --- Bottom Bar --- */
691
+
692
+ .canvas-bottom-bar {
693
+ position: absolute;
694
+ bottom: 16px;
695
+ left: 16px;
696
+ right: 16px;
697
+ display: flex;
698
+ justify-content: space-between;
699
+ align-items: flex-end;
700
+ pointer-events: none;
701
+ gap: 8px;
702
+ }
703
+
704
+ .canvas-bottom-left,
705
+ .canvas-bottom-center,
706
+ .canvas-bottom-right {
707
+ display: flex;
708
+ align-items: center;
709
+ gap: 4px;
710
+ pointer-events: auto;
711
+ position: relative;
712
+ z-index: var(--z-floating);
713
+ }
714
+
715
+ .canvas-bottom-center {
716
+ flex: 1;
717
+ justify-content: center;
718
+ }
719
+
690
720
  /* --- Focus Indicator --- */
691
721
 
692
722
  .focus-indicator {
@@ -2071,6 +2101,12 @@ body {
2071
2101
  right: 8px;
2072
2102
  }
2073
2103
 
2104
+ .canvas-bottom-bar {
2105
+ bottom: 8px;
2106
+ left: 8px;
2107
+ right: 8px;
2108
+ }
2109
+
2074
2110
  .tools-pane-content {
2075
2111
  top: 48px;
2076
2112
  left: 8px;
@@ -2302,11 +2338,6 @@ body {
2302
2338
  /* --- Path Bar --- */
2303
2339
 
2304
2340
  .path-bar {
2305
- position: absolute;
2306
- bottom: 16px;
2307
- left: 50%;
2308
- transform: translateX(-50%);
2309
- z-index: var(--z-canvas-overlay);
2310
2341
  display: flex;
2311
2342
  align-items: center;
2312
2343
  gap: 4px;
@@ -2429,14 +2460,11 @@ body {
2429
2460
  display: inline-flex;
2430
2461
  }
2431
2462
 
2432
- /* Bottom slots float in the canvas corners. Hidden until populated so
2433
- empty corners don't take any space. The bottom-center area is left
2434
- clear for the path bar — see .path-bar above. */
2463
+ /* Bottom slots live inside bottom bar columns. Hidden until populated
2464
+ so empty slots take no space. */
2435
2465
  .ext-slot-bottom-left,
2466
+ .ext-slot-bottom-center,
2436
2467
  .ext-slot-bottom-right {
2437
- position: absolute;
2438
- bottom: 16px;
2439
- z-index: var(--z-floating);
2440
2468
  display: none;
2441
2469
  flex-direction: row;
2442
2470
  align-items: center;
@@ -2446,18 +2474,10 @@ body {
2446
2474
  border: 1px solid var(--border);
2447
2475
  border-radius: 12px;
2448
2476
  box-shadow: 0 4px 16px var(--shadow);
2449
- pointer-events: auto;
2450
- }
2451
-
2452
- .ext-slot-bottom-left {
2453
- left: 16px;
2454
- }
2455
-
2456
- .ext-slot-bottom-right {
2457
- right: 16px;
2458
2477
  }
2459
2478
 
2460
2479
  .ext-slot-bottom-left.has-icons,
2480
+ .ext-slot-bottom-center.has-icons,
2461
2481
  .ext-slot-bottom-right.has-icons {
2462
2482
  display: flex;
2463
2483
  }
@@ -2487,6 +2507,7 @@ body {
2487
2507
  /* Inside the bottom floating pill, drop the per-icon shadow and
2488
2508
  border so the pill container's chrome wraps the group cleanly. */
2489
2509
  .ext-slot-bottom-left .extension-taskbar-icon,
2510
+ .ext-slot-bottom-center .extension-taskbar-icon,
2490
2511
  .ext-slot-bottom-right .extension-taskbar-icon {
2491
2512
  background: transparent;
2492
2513
  border-color: transparent;
@@ -2500,6 +2521,7 @@ body {
2500
2521
  }
2501
2522
 
2502
2523
  .ext-slot-bottom-left .extension-taskbar-icon:hover,
2524
+ .ext-slot-bottom-center .extension-taskbar-icon:hover,
2503
2525
  .ext-slot-bottom-right .extension-taskbar-icon:hover {
2504
2526
  border-color: var(--border);
2505
2527
  }
@@ -2576,8 +2598,7 @@ body {
2576
2598
  searching and selecting nodes while a panel is fullscreen. */
2577
2599
  #canvas-container.has-fullscreen-panel .canvas-top-left,
2578
2600
  #canvas-container.has-fullscreen-panel .canvas-top-right,
2579
- #canvas-container.has-fullscreen-panel .ext-slot-bottom-left,
2580
- #canvas-container.has-fullscreen-panel .ext-slot-bottom-right,
2601
+ #canvas-container.has-fullscreen-panel .canvas-bottom-bar,
2581
2602
  #canvas-container.has-fullscreen-panel .ext-slot-top-left,
2582
2603
  #canvas-container.has-fullscreen-panel .ext-slot-top-right {
2583
2604
  display: none;
@@ -2701,4 +2722,3 @@ body {
2701
2722
  display: flex;
2702
2723
  flex-direction: column;
2703
2724
  }
2704
-
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "backpack-viewer",
3
- "version": "0.7.4",
3
+ "version": "0.7.6",
4
4
  "description": "Web-based graph visualizer for backpack-ontology — Canvas 2D, force-directed layout, live reload",
5
5
  "license": "Apache-2.0",
6
6
  "author": "Noah Irzinger",
@@ -1 +0,0 @@
1
- *{margin:0;padding:0;box-sizing:border-box}:root{--bg: #141414;--bg-surface: #1a1a1a;--bg-hover: #222222;--bg-active: #2a2a2a;--bg-elevated: #1e1e1e;--bg-inset: #111111;--border: #2a2a2a;--text: #d4d4d4;--text-strong: #e5e5e5;--text-muted: #737373;--text-dim: #525252;--accent: #d4a27f;--accent-hover: #e8b898;--badge-text: #141414;--glass-bg: rgba(20, 20, 20, .85);--glass-border: rgba(255, 255, 255, .08);--chip-bg: rgba(42, 42, 42, .7);--chip-bg-active: rgba(42, 42, 42, .9);--chip-bg-hover: rgba(50, 50, 50, .9);--chip-border-active: rgba(255, 255, 255, .06);--shadow: rgba(0, 0, 0, .6);--shadow-strong: rgba(0, 0, 0, .5);--z-canvas-overlay: 20;--z-panel: 30;--z-floating: 40;--z-panel-fullscreen: 45;--z-floating-primary: 50;--z-popup: 55;--z-modal: 60;--z-toast: 70;--canvas-edge: rgba(255, 255, 255, .08);--canvas-edge-highlight: rgba(212, 162, 127, .5);--canvas-edge-dim: rgba(255, 255, 255, .03);--canvas-edge-label: rgba(255, 255, 255, .2);--canvas-edge-label-highlight: rgba(212, 162, 127, .7);--canvas-edge-label-dim: rgba(255, 255, 255, .05);--canvas-arrow: rgba(255, 255, 255, .12);--canvas-arrow-highlight: rgba(212, 162, 127, .5);--canvas-node-label: #a3a3a3;--canvas-node-label-dim: rgba(212, 212, 212, .2);--canvas-type-badge: rgba(115, 115, 115, .5);--canvas-type-badge-dim: rgba(115, 115, 115, .15);--canvas-selection-border: #d4d4d4;--canvas-node-border: rgba(255, 255, 255, .15);--canvas-walk-edge: #e8d5c4}[data-theme=light]{--bg: #f5f5f4;--bg-surface: #fafaf9;--bg-hover: #f0efee;--bg-active: #e7e5e4;--bg-elevated: #f0efee;--bg-inset: #e7e5e4;--border: #d6d3d1;--text: #292524;--text-strong: #1c1917;--text-muted: #78716c;--text-dim: #a8a29e;--accent: #c17856;--accent-hover: #b07a5e;--badge-text: #fafaf9;--glass-bg: rgba(250, 250, 249, .85);--glass-border: rgba(0, 0, 0, .08);--chip-bg: rgba(214, 211, 209, .5);--chip-bg-active: rgba(214, 211, 209, .8);--chip-bg-hover: rgba(200, 197, 195, .8);--chip-border-active: rgba(0, 0, 0, .08);--shadow: rgba(0, 0, 0, .1);--shadow-strong: rgba(0, 0, 0, .15);--canvas-edge: rgba(0, 0, 0, .1);--canvas-edge-highlight: rgba(193, 120, 86, .6);--canvas-edge-dim: rgba(0, 0, 0, .03);--canvas-edge-label: rgba(0, 0, 0, .25);--canvas-edge-label-highlight: rgba(193, 120, 86, .8);--canvas-edge-label-dim: rgba(0, 0, 0, .06);--canvas-arrow: rgba(0, 0, 0, .15);--canvas-arrow-highlight: rgba(193, 120, 86, .6);--canvas-node-label: #57534e;--canvas-node-label-dim: rgba(87, 83, 78, .2);--canvas-type-badge: rgba(87, 83, 78, .5);--canvas-type-badge-dim: rgba(87, 83, 78, .15);--canvas-selection-border: #292524;--canvas-node-border: rgba(0, 0, 0, .1);--canvas-walk-edge: #1a1a1a}body{font-family:system-ui,-apple-system,sans-serif;background:var(--bg);color:var(--text);overflow:hidden}#app{display:flex;height:100vh;width:100vw}#sidebar{width:280px;min-width:280px;background:var(--bg-surface);border-right:1px solid var(--border);border-left:3px solid var(--backpack-color, transparent);display:flex;flex-direction:column;padding:16px;overflow-y:auto}#sidebar.sidebar-collapsed{width:0;min-width:0;padding:0;overflow:hidden;border-right:none}.sidebar-heading-row{display:flex;align-items:center;justify-content:space-between;margin-bottom:14px}.sidebar-heading-row h2{margin-bottom:0}.sidebar-collapse-btn{background:none;border:1px solid var(--border);border-radius:6px;color:var(--text-dim);cursor:pointer;padding:4px 6px;line-height:1;transition:color .15s,border-color .15s}.sidebar-collapse-btn:hover{color:var(--text);border-color:var(--text-muted)}#sidebar h2{font-size:13px;font-weight:600;text-transform:uppercase;letter-spacing:.05em;color:var(--text-muted);margin-bottom:14px}#sidebar input{width:100%;padding:8px 12px;border:1px solid var(--border);border-radius:6px;background:var(--bg);color:var(--text);font-size:13px;outline:none;margin-bottom:12px}#sidebar input:focus{border-color:var(--accent)}#sidebar input::placeholder{color:var(--text-dim)}#ontology-list{list-style:none;display:flex;flex-direction:column;gap:2px}.ontology-item{padding:10px 12px;border-radius:6px;cursor:pointer;transition:background .15s}.ontology-item:hover{background:var(--bg-hover)}.ontology-item.active{background:var(--bg-active)}.ontology-item .name{display:block;font-size:13px;font-weight:500;color:var(--text)}.ontology-item .stats{display:block;font-size:11px;color:var(--text-dim);margin-top:2px}.sidebar-edit-btn{position:absolute;right:8px;top:10px;background:none;border:none;color:var(--text-dim);font-size:11px;cursor:pointer;opacity:0;transition:opacity .1s}.ontology-item{position:relative}.ontology-item:hover .sidebar-edit-btn{opacity:.7}.sidebar-section-heading{font-size:10px;font-weight:600;color:var(--text-dim);letter-spacing:.08em;margin:16px 12px 6px}.remote-list{list-style:none;padding:0;margin:0}.ontology-item-remote .name{display:inline}.remote-name-row{display:flex;align-items:center;gap:8px}.remote-badge{font-size:9px;font-weight:600;color:var(--text-dim);background:var(--bg-hover);padding:1px 6px;border-radius:4px;text-transform:uppercase;letter-spacing:.04em;border:1px solid var(--border)}.remote-source{display:block;font-size:10px;color:var(--text-dim);margin-top:1px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.sidebar-edit-btn:hover{opacity:1!important;color:var(--text)}.sidebar-rename-input{background:transparent;border:none;border-bottom:1px solid var(--accent);color:var(--text);font:inherit;font-size:13px;font-weight:500;outline:none;width:100%;padding:0}.sidebar-branch{font-size:10px;color:var(--accent);opacity:.7;display:block;margin-top:2px}.sidebar-branch:hover{opacity:1}.sidebar-stale-banner{background:#fff3cd;color:#5c3a00;border:1px solid #e6c263;border-radius:6px;padding:10px 12px;margin-bottom:10px;font-size:11px}.sidebar-stale-banner-title{font-weight:600;margin-bottom:2px}.sidebar-stale-banner-subtitle{opacity:.85;margin-bottom:6px}.sidebar-stale-banner-hint{background:#00000014;border-radius:4px;padding:6px 8px;font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;font-size:10px;line-height:1.4;margin:0;white-space:pre-wrap;word-break:break-all}.backpack-picker-container{position:relative;margin-bottom:10px}.backpack-picker-pill{display:flex;align-items:center;gap:6px;width:100%;padding:6px 10px;background:var(--bg-base);border:1px solid var(--border);border-radius:6px;color:var(--fg);font-size:11px;font-family:inherit;cursor:pointer;text-align:left}.backpack-picker-pill:hover{border-color:var(--backpack-color, var(--accent))}.backpack-picker-dot{display:inline-block;width:8px;height:8px;border-radius:50%;background:var(--backpack-color, var(--accent));flex-shrink:0}.backpack-picker-name{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-weight:500}.backpack-picker-caret{opacity:.6;font-size:10px}.backpack-picker-dropdown{position:absolute;top:calc(100% + 4px);left:0;right:0;background:var(--bg-surface);border:1px solid var(--border);border-radius:8px;box-shadow:0 4px 16px var(--shadow);z-index:50;max-height:300px;overflow-y:auto;padding:4px}.backpack-picker-item{display:flex;align-items:center;gap:6px;width:100%;padding:6px 8px;background:transparent;border:none;border-radius:4px;color:var(--fg);font-family:inherit;font-size:11px;cursor:pointer;text-align:left}.backpack-picker-item:hover{background:var(--bg-hover)}.backpack-picker-item.active{background:var(--bg-hover);font-weight:600}.backpack-picker-item-dot{display:inline-block;width:8px;height:8px;border-radius:50%;background:var(--backpack-color, var(--accent));flex-shrink:0}.backpack-picker-item-name{flex-shrink:0}.backpack-picker-item-path{flex:1;opacity:.55;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:9px;text-align:right}.backpack-picker-divider{height:1px;background:var(--border);margin:4px 0}.backpack-picker-add{opacity:.75;font-style:italic}.sidebar-lock-badge{font-size:10px;color:#c08c00;display:none;margin-top:2px}.sidebar-lock-badge.active{display:block}.sidebar-lock-badge.active:before{content:"● ";color:#c08c00}.branch-picker{background:var(--bg-surface);border:1px solid var(--border);border-radius:8px;padding:4px;margin-top:4px;box-shadow:0 4px 16px var(--shadow);z-index:50}.branch-picker-item{display:flex;align-items:center;justify-content:space-between;padding:6px 8px;font-size:12px;color:var(--text);border-radius:4px;cursor:pointer}.branch-picker-item:hover{background:var(--bg-hover)}.branch-picker-active{color:var(--accent);font-weight:600;cursor:default}.branch-picker-active:hover{background:none}.branch-picker-delete{background:none;border:none;color:var(--text-dim);cursor:pointer;font-size:14px;padding:0 4px}.sidebar-snippets{margin-top:4px;padding-left:8px}.sidebar-snippet{display:flex;align-items:center;justify-content:space-between;padding:2px 4px;border-radius:4px;cursor:pointer}.sidebar-snippet:hover{background:var(--bg-hover)}.sidebar-snippet-label{font-size:10px;color:var(--text-dim);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.sidebar-snippet-delete{background:none;border:none;color:var(--text-dim);font-size:12px;cursor:pointer;padding:0 2px;opacity:0}.sidebar-snippet:hover .sidebar-snippet-delete{opacity:1}.branch-picker-delete:hover{color:var(--danger, #e55)}.branch-picker-create{color:var(--accent);font-size:11px;border-top:1px solid var(--border);margin-top:4px;padding-top:8px}.sidebar-footer{margin-top:auto;padding-top:16px;border-top:1px solid var(--border);text-align:center}.sidebar-footer a{display:block;font-size:12px;font-weight:500;color:var(--accent);text-decoration:none;margin-bottom:4px}.sidebar-footer a:hover{color:var(--accent-hover)}.sidebar-footer span{display:block;font-size:10px;color:var(--text-dim)}.sidebar-version{font-size:9px;color:var(--text-dim);opacity:.5;margin-top:4px}.canvas-top-bar{position:absolute;top:16px;left:16px;right:16px;display:flex;justify-content:space-between;align-items:flex-start;pointer-events:none}.canvas-top-left,.canvas-top-right{position:relative;z-index:var(--z-floating);pointer-events:auto;display:flex;align-items:center;gap:4px}.canvas-top-center{position:relative;z-index:var(--z-floating-primary);pointer-events:auto;display:flex;align-items:center;gap:4px}.canvas-top-left{flex-shrink:0;min-width:var(--tools-width, 264px)}.canvas-top-center{flex:1;justify-content:center}.focus-indicator{display:flex;align-items:center;gap:2px;background:var(--bg-surface);border:1px solid rgba(212,162,127,.4);border-radius:8px;padding:4px 6px 4px 10px;box-shadow:0 2px 8px var(--shadow)}.focus-indicator-label{font-size:11px;color:var(--accent);font-weight:500;white-space:nowrap;margin-right:4px}.focus-indicator-hops{font-size:11px;color:var(--text-muted);font-family:monospace;min-width:12px;text-align:center}.focus-indicator-btn{background:none;border:none;color:var(--text-muted);font-size:14px;cursor:pointer;padding:2px 4px;line-height:1;border-radius:4px;transition:color .15s,background .15s}.focus-indicator-btn:hover:not(:disabled){color:var(--text);background:var(--bg-hover)}.focus-indicator-btn:disabled{color:var(--text-dim);cursor:default;opacity:.3}.focus-indicator-exit{font-size:16px;margin-left:2px}.focus-indicator-exit:hover{color:#ef4444!important}.info-focus-btn{font-size:14px}.theme-toggle{background:var(--bg-surface);border:1px solid var(--border);border-radius:8px;color:var(--text-muted);font-size:18px;cursor:pointer;padding:6px 10px;line-height:1;transition:color .15s,border-color .15s,background .15s;box-shadow:0 2px 8px var(--shadow)}.theme-toggle:hover{color:var(--text);border-color:var(--text-muted);background:var(--bg-hover)}.zoom-controls{display:flex;gap:4px}.zoom-btn{background:var(--bg-surface);border:1px solid var(--border);border-radius:8px;color:var(--text-muted);font-size:18px;cursor:pointer;padding:6px 10px;line-height:1;transition:color .15s,border-color .15s,background .15s;box-shadow:0 2px 8px var(--shadow)}.zoom-btn:hover{color:var(--text);border-color:var(--text-muted);background:var(--bg-hover)}.node-tooltip{position:absolute;pointer-events:none;background:var(--bg);color:var(--text);border:1px solid var(--border);border-radius:6px;padding:4px 8px;font-size:12px;white-space:nowrap;z-index:20;box-shadow:0 2px 8px #00000026;opacity:.95}#canvas-container{flex:1;position:relative;overflow:hidden;touch-action:none}#graph-canvas{position:absolute;top:0;left:0;touch-action:none;width:100%;height:100%;cursor:grab}#graph-canvas:active{cursor:grabbing}.search-overlay{position:relative;display:flex;flex-direction:column;align-items:center;gap:8px;max-height:calc(100vh - 48px);pointer-events:none}.search-overlay>*{pointer-events:auto}.search-overlay.hidden{display:none}.search-input-wrap{position:relative;display:flex;align-items:center;gap:6px;width:380px;max-width:calc(100vw - 340px)}.search-input{flex:1;min-width:0;padding:10px 36px 10px 16px;border:1px solid var(--glass-border);border-radius:10px;background:var(--glass-bg);backdrop-filter:blur(12px);-webkit-backdrop-filter:blur(12px);color:var(--text);font-size:14px;outline:none;transition:border-color .15s,box-shadow .15s}.search-input:focus{border-color:#d4a27f66;box-shadow:0 0 0 3px #d4a27f1a}.search-input::placeholder{color:var(--text-dim)}.search-kbd{position:absolute;right:10px;top:50%;transform:translateY(-50%);padding:2px 7px;border:1px solid var(--border);border-radius:4px;background:var(--bg-surface);color:var(--text-dim);font-size:11px;font-family:monospace;pointer-events:none}.search-kbd.hidden{display:none}.search-results{list-style:none;width:380px;max-width:calc(100vw - 340px);background:var(--glass-bg);backdrop-filter:blur(12px);-webkit-backdrop-filter:blur(12px);border:1px solid var(--border);border-radius:10px;overflow:hidden;box-shadow:0 8px 32px var(--shadow-strong)}.search-results.hidden{display:none}.search-result-item{display:flex;align-items:center;gap:8px;padding:8px 14px;cursor:pointer;transition:background .1s}.search-result-item:hover,.search-result-active{background:var(--bg-hover)}.search-result-dot{width:8px;height:8px;border-radius:50%;flex-shrink:0}.search-result-label{font-size:13px;color:var(--text);flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.search-result-type{font-size:11px;color:var(--text-dim);flex-shrink:0}.chip-toggle{flex-shrink:0;display:flex;align-items:center;justify-content:center;width:36px;height:36px;border:1px solid var(--glass-border);border-radius:10px;background:var(--glass-bg);backdrop-filter:blur(12px);-webkit-backdrop-filter:blur(12px);color:var(--text-dim);cursor:pointer;transition:border-color .15s,color .15s;pointer-events:auto}.chip-toggle:hover{border-color:#d4a27f4d;color:var(--text)}.chip-toggle.active{border-color:#d4a27f66;color:var(--accent)}.type-chips{display:flex;flex-wrap:wrap;gap:4px;justify-content:center;max-width:500px;max-height:200px;overflow-y:auto;padding:4px;border-radius:10px}.type-chips.hidden{display:none}.type-chip{display:flex;align-items:center;gap:4px;padding:3px 10px;border:1px solid transparent;border-radius:12px;background:var(--chip-bg);color:var(--text-dim);font-size:11px;cursor:pointer;transition:all .15s;white-space:nowrap}.type-chip.active{background:var(--chip-bg-active);color:var(--text-muted);border-color:var(--chip-border-active)}.type-chip:hover{background:var(--chip-bg-hover)}.type-chip-dot{width:6px;height:6px;border-radius:50%;flex-shrink:0}.type-chip:not(.active) .type-chip-dot{opacity:.3}.info-panel-content{flex:1;display:flex;flex-direction:column;min-height:0}.info-panel-header{flex-shrink:0;padding:16px 20px 12px;position:relative}.info-panel-body{flex:1;overflow-y:auto;min-height:0;padding:0 20px 20px}.info-connection-link{cursor:pointer;transition:background .15s}.info-connection-link:hover{background:var(--bg-active)}.info-connection-link .info-target{color:var(--accent);text-decoration:underline;text-decoration-color:transparent;transition:text-decoration-color .15s}.info-connection-link:hover .info-target{text-decoration-color:var(--accent)}.info-header{margin-bottom:16px}.info-type-badge{display:inline-block;padding:3px 10px;border-radius:12px;font-size:11px;font-weight:600;color:var(--badge-text);margin-bottom:8px}.info-badge-row{display:flex;flex-wrap:wrap;gap:4px;margin-top:6px}.info-empty-message{font-size:12px;color:var(--text-dim)}.share-list-message{font-size:13px;color:var(--text-dim);text-align:center;padding:12px}.info-label{font-size:18px;font-weight:600;color:var(--text-strong);margin-bottom:4px;word-break:break-word}.info-id{display:block;font-size:11px;color:var(--text-dim);font-family:monospace}.info-section{margin-bottom:16px}.info-section-title{font-size:11px;font-weight:600;text-transform:uppercase;letter-spacing:.05em;color:var(--text-muted);margin-bottom:8px;padding-bottom:4px;border-bottom:1px solid var(--border)}.info-props{display:grid;grid-template-columns:auto 1fr;gap:4px 12px}.info-props dt{font-size:12px;color:var(--text-muted);padding-top:2px}.info-props dd{font-size:12px;color:var(--text);word-break:break-word;display:flex;align-items:center;gap:4px}.info-value{white-space:pre-wrap}.info-array{display:flex;flex-wrap:wrap;gap:4px}.info-tag{display:inline-block;padding:2px 8px;background:var(--bg-hover);border-radius:4px;font-size:11px;color:var(--text-muted)}.info-json{font-size:11px;font-family:monospace;color:var(--text-muted);background:var(--bg-inset);padding:6px 8px;border-radius:4px;overflow-x:auto;white-space:pre}.info-connections{list-style:none;display:flex;flex-direction:column;gap:6px}.info-connection{display:flex;align-items:center;gap:6px;padding:6px 8px;background:var(--bg-elevated);border-radius:6px;font-size:12px;flex-wrap:wrap}.info-connection-active{outline:1.5px solid var(--accent);background:var(--bg-hover)}.info-target-dot{width:8px;height:8px;border-radius:50%;flex-shrink:0}.info-arrow{color:var(--text-dim);font-size:14px;flex-shrink:0}.info-edge-type{color:var(--text-muted);font-size:11px;font-weight:500}.info-target{color:var(--text);font-weight:500}.info-edge-props{width:100%;padding-top:4px;padding-left:20px}.info-edge-prop{display:block;font-size:11px;color:var(--text-dim)}.info-editable{cursor:default;position:relative}.info-inline-edit{background:none;border:none;color:var(--badge-text);opacity:0;font-size:10px;cursor:pointer;margin-left:4px;transition:opacity .15s}.info-editable:hover .info-inline-edit{opacity:.8}.info-inline-edit:hover{opacity:1!important}.info-edit-inline-input{background:transparent;border:none;border-bottom:1px solid var(--accent);color:var(--badge-text);font:inherit;font-size:inherit;outline:none;width:100%;padding:0}.info-edit-input{background:var(--bg-inset);border:1px solid var(--border);border-radius:4px;padding:3px 6px;font-size:12px;font-family:inherit;color:var(--text);flex:1;min-width:0;resize:vertical;overflow:hidden;line-height:1.4;max-height:300px}.info-edit-input:focus{outline:none;border-color:var(--accent)}.info-delete-prop{background:none;border:none;color:var(--text-dim);font-size:14px;cursor:pointer;padding:0 2px;flex-shrink:0;opacity:0;transition:opacity .1s,color .1s}.info-props dd:hover .info-delete-prop{opacity:1}.info-delete-prop:hover{color:#ef4444}.info-add-btn{background:none;border:1px dashed var(--border);border-radius:4px;padding:6px 10px;font-size:12px;color:var(--text-dim);cursor:pointer;width:100%;margin-top:8px;transition:border-color .15s,color .15s}.info-add-btn:hover{border-color:var(--accent);color:var(--text)}.info-add-row{display:flex;gap:4px;margin-top:6px}.info-add-save{background:var(--accent);border:none;border-radius:4px;padding:3px 10px;font-size:12px;color:var(--badge-text);cursor:pointer;flex-shrink:0}.info-add-save:hover{background:var(--accent-hover)}.info-delete-edge{background:none;border:none;color:var(--text-dim);font-size:14px;cursor:pointer;margin-left:auto;padding:0 2px;opacity:0;transition:opacity .1s,color .1s}.info-connection:hover .info-delete-edge{opacity:1}.info-delete-edge:hover{color:#ef4444}.info-danger{margin-top:8px;padding-top:12px;border-top:1px solid var(--border)}.info-delete-node{background:none;border:1px solid rgba(239,68,68,.3);border-radius:6px;padding:6px 12px;font-size:12px;color:#ef4444;cursor:pointer;width:100%;transition:background .15s}.info-delete-node:hover{background:#ef44441a}.tools-pane-toggle{background:var(--bg-surface);border:1px solid var(--border);border-radius:8px;color:var(--text-muted);font-size:18px;cursor:pointer;padding:6px 10px;line-height:1;transition:color .15s,border-color .15s,background .15s;box-shadow:0 2px 8px var(--shadow)}.tools-pane-toggle.hidden{display:none}.tools-pane-toggle:hover{color:var(--text);border-color:var(--text-muted);background:var(--bg-hover)}.tools-pane-toggle.active{color:var(--accent);border-color:#d4a27f66}.tools-pane-content{position:absolute;top:56px;left:16px;bottom:16px;z-index:20;width:var(--tools-width, 264px);box-sizing:border-box;overflow:hidden;display:flex;flex-direction:column;background:var(--bg-surface);border:1px solid var(--border);border-radius:10px;padding:12px;box-shadow:0 8px 32px var(--shadow)}.tools-pane-content.hidden{display:none}.tools-pane-section{margin-bottom:12px}.tools-pane-section:last-child{margin-bottom:0}.tools-pane-heading{font-size:10px;font-weight:600;text-transform:uppercase;letter-spacing:.05em;color:var(--text-dim);margin-bottom:6px}.tools-pane-row{display:flex;align-items:center;gap:6px;padding:3px 0;font-size:12px}.tools-pane-dot{width:6px;height:6px;border-radius:50%;flex-shrink:0}.tools-pane-name{flex:1;color:var(--text);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.tools-pane-count{color:var(--text-dim);font-size:11px;flex-shrink:0}.tools-pane-summary{display:flex;align-items:center;gap:4px;font-size:11px;color:var(--text-muted);padding-bottom:10px;margin-bottom:10px;border-bottom:1px solid var(--border)}.tools-pane-sep{color:var(--text-dim)}.tools-pane-token-card{padding:8px 10px;margin-bottom:10px;border:1px solid var(--border);border-radius:6px;background:var(--bg-hover);font-size:11px}.token-card-label{font-weight:600;color:var(--text);margin-bottom:4px}.token-card-stat{color:var(--text-muted);margin-bottom:4px}.token-card-bar{height:4px;background:var(--border);border-radius:2px;margin:6px 0;overflow:hidden}.token-card-bar-fill{height:100%;background:var(--accent);border-radius:2px;transition:width .3s ease}.tools-pane-clickable{cursor:pointer;border-radius:4px;padding:3px 4px;margin:0 -4px;transition:background .1s}.tools-pane-clickable:hover{background:var(--bg-hover)}.tools-pane-clickable.active{background:var(--bg-hover);outline:1px solid var(--border)}.tools-pane-badge{font-size:9px;color:var(--accent);flex-shrink:0;opacity:.8}.tools-pane-issue .tools-pane-name{color:var(--text-muted)}.tools-pane-more{font-size:10px;color:var(--text-dim);padding:4px 0 0}.tools-pane-edit{background:none;border:none;color:var(--text-dim);font-size:11px;cursor:pointer;padding:0 2px;opacity:0;transition:opacity .1s,color .1s;flex-shrink:0}.tools-pane-row:hover .tools-pane-edit{opacity:1}.tools-pane-edit:hover{color:var(--accent)}.tools-pane-actions{display:flex;gap:6px;padding-top:4px}.tools-pane-action-btn{background:none;border:1px solid var(--border);color:var(--text-muted);font-size:10px;padding:2px 8px;border-radius:3px;cursor:pointer;transition:color .1s,border-color .1s}.tools-pane-action-btn:hover{color:var(--accent);border-color:var(--accent)}.tools-pane-focus-toggle{opacity:.4;font-size:11px}.tools-pane-focus-active{opacity:1!important;color:var(--accent)!important}.tools-pane-focus-clear{margin-top:4px;border-top:1px solid var(--border);padding-top:6px}.tools-pane-editing{background:none!important}.tools-pane-inline-input{width:100%;background:var(--bg);border:1px solid var(--accent);border-radius:4px;color:var(--text);font-size:12px;padding:2px 6px;outline:none}.tools-pane-slider-row{display:flex;align-items:center;gap:6px;padding:4px 0}.tools-pane-slider-label{font-size:11px;color:var(--text-muted);white-space:nowrap;min-width:56px}.tools-pane-slider{flex:1;min-width:0;height:4px;accent-color:var(--accent);cursor:pointer}.tools-pane-slider-value{font-size:10px;color:var(--text-dim);min-width:28px;text-align:right;font-family:monospace}.tools-pane-checkbox{width:14px;height:14px;accent-color:var(--accent);cursor:pointer;flex-shrink:0}.tools-pane-export-row{display:flex;gap:4px;margin-top:6px}.tools-pane-export-btn{flex:1;padding:4px 8px;font-size:11px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text-muted);cursor:pointer;transition:color .15s,border-color .15s}.tools-pane-export-btn:hover{color:var(--text);border-color:var(--text-muted)}.tools-pane-empty{font-size:11px;color:var(--text-dim);text-align:center;padding:8px 0}.tools-pane-tabs{display:flex;gap:2px;margin-bottom:10px;padding-bottom:8px;border-bottom:1px solid var(--border)}.tools-pane-tab{flex:1;padding:4px 0;font-size:10px;font-weight:600;text-transform:uppercase;letter-spacing:.03em;background:none;border:1px solid transparent;border-radius:5px;color:var(--text-dim);cursor:pointer;transition:color .15s,background .15s,border-color .15s}.tools-pane-tab:hover{color:var(--text-muted);background:var(--bg-hover)}.tools-pane-tab-active{color:var(--text);background:var(--bg-hover);border-color:var(--border)}.tools-pane-tab-content{flex:1;overflow-y:auto;overflow-x:hidden;min-height:0}.tools-pane-search{width:100%;padding:4px 8px;font-size:11px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text);outline:none;margin-bottom:8px;box-sizing:border-box}.tools-pane-search:focus{border-color:var(--accent)}.tools-pane-search::placeholder{color:var(--text-dim)}.tools-pane-empty-msg{font-size:11px;color:var(--text-dim);text-align:center;padding:16px 0}.empty-state{position:absolute;top:0;right:0;bottom:0;left:0;display:flex;align-items:center;justify-content:center;z-index:5;pointer-events:none;overflow:hidden}.empty-state.hidden{display:none}.empty-state-bg{position:absolute;top:0;right:0;bottom:0;left:0;overflow:hidden}.empty-state-circle{position:absolute;border-radius:50%;background:var(--accent);opacity:.07}.empty-state-circle.c1{width:80px;height:80px;left:20%;top:15%;animation:float-circle 8s ease-in-out infinite}.empty-state-circle.c2{width:50px;height:50px;right:25%;top:25%;animation:float-circle 6s ease-in-out 1s infinite}.empty-state-circle.c3{width:65px;height:65px;left:55%;bottom:20%;animation:float-circle 7s ease-in-out 2s infinite}.empty-state-circle.c4{width:40px;height:40px;left:15%;bottom:30%;animation:float-circle 9s ease-in-out .5s infinite}.empty-state-circle.c5{width:55px;height:55px;right:15%;bottom:35%;animation:float-circle 7.5s ease-in-out 1.5s infinite}.empty-state-lines{position:absolute;top:0;right:0;bottom:0;left:0;width:100%;height:100%;color:var(--text-dim);animation:float-circle 10s ease-in-out infinite}@keyframes float-circle{0%,to{transform:translateY(0)}50%{transform:translateY(-12px)}}.empty-state-content{text-align:center;max-width:420px;padding:40px 24px;position:relative;z-index:1}.empty-state-icon{color:var(--text-dim);margin-bottom:16px}.empty-state-title{font-size:18px;font-weight:600;color:var(--text);margin-bottom:8px}.empty-state-desc{font-size:13px;color:var(--text-muted);line-height:1.5;margin-bottom:20px}.empty-state-setup{background:var(--bg-surface);border:1px solid var(--border);border-radius:8px;padding:12px 16px;margin-bottom:16px}.empty-state-label{font-size:11px;color:var(--text-dim);margin-bottom:8px}.empty-state-code{display:block;font-size:12px;color:var(--accent);font-family:monospace;word-break:break-all}.empty-state-hint{font-size:11px;color:var(--text-dim)}.empty-state-hint kbd{padding:1px 5px;border:1px solid var(--border);border-radius:3px;background:var(--bg-surface);font-family:monospace;font-size:11px}.shortcuts-overlay{position:fixed;top:0;right:0;bottom:0;left:0;background:#00000080;display:flex;align-items:center;justify-content:center;z-index:100}.shortcuts-overlay.hidden{display:none}.shortcuts-modal{background:var(--bg-surface);border:1px solid var(--border);border-radius:12px;padding:24px;min-width:300px;max-width:400px;box-shadow:0 16px 48px var(--shadow);position:relative}.shortcuts-close{position:absolute;top:12px;right:14px;background:none;border:none;color:var(--text-dim);font-size:20px;cursor:pointer;padding:0 4px;line-height:1}.shortcuts-close:hover{color:var(--text)}.shortcuts-title{font-size:15px;font-weight:600;color:var(--text);margin-bottom:16px}.shortcuts-list{display:flex;flex-direction:column;gap:8px}.shortcuts-row{display:flex;align-items:center;justify-content:space-between;gap:12px}.shortcuts-keys{display:flex;align-items:center;gap:4px}.shortcuts-keys kbd{padding:2px 7px;border:1px solid var(--border);border-radius:4px;background:var(--bg);color:var(--text);font-size:11px;font-family:monospace}.shortcuts-or{font-size:10px;color:var(--text-dim)}.shortcuts-desc{font-size:12px;color:var(--text-muted)}@media(max-width:768px){#app{flex-direction:column}#sidebar{width:100%;min-width:0;max-height:35vh;border-right:none;border-bottom:1px solid var(--border)}.info-panel{top:auto;bottom:72px;right:8px;left:8px;width:auto;max-height:calc(100% - 200px);overflow-y:auto}.info-panel.info-panel-maximized{bottom:0;left:0;right:0}.canvas-top-bar{top:8px;left:8px;right:8px}.tools-pane-content{top:48px;left:8px;bottom:80px;width:160px;max-width:calc(100vw - 24px)}.tools-pane-edit{opacity:.6}}.bp-dialog-overlay{position:fixed;top:0;right:0;bottom:0;left:0;background:#00000080;display:flex;align-items:center;justify-content:center;z-index:1000;-webkit-backdrop-filter:blur(2px);backdrop-filter:blur(2px)}.bp-dialog{background:var(--bg-surface);border:1px solid var(--border);border-radius:12px;padding:20px;min-width:280px;max-width:400px;box-shadow:0 16px 48px #0000004d}.bp-dialog-title{font-size:14px;font-weight:600;color:var(--text);margin-bottom:12px}.bp-dialog-message{font-size:13px;color:var(--text-muted);margin-bottom:16px;line-height:1.5}.bp-dialog-input{width:100%;padding:8px 12px;font-size:13px;background:var(--bg);border:1px solid var(--border);border-radius:8px;color:var(--text);outline:none;margin-bottom:16px}.bp-dialog-input:focus{border-color:var(--accent)}.bp-dialog-label{display:block;font-size:11px;color:var(--text-muted);margin-bottom:4px;margin-top:8px;text-transform:uppercase;letter-spacing:.04em}.bp-dialog-path-row{display:flex;gap:8px;margin-bottom:4px}.bp-dialog-path-input{flex:1;margin-bottom:0}.bp-dialog-browse-btn{flex-shrink:0;padding:8px 14px;font-size:12px}.bp-dialog-browse-btn:disabled{opacity:.4;cursor:not-allowed}.bp-dialog-path-input.bp-dialog-drag-over{border-color:var(--accent);background:var(--bg-hover)}.bp-dialog-picker-hint{font-size:11px;color:var(--text-muted);min-height:1em;margin-bottom:8px}.bp-dialog-activate-row{display:flex;align-items:center;gap:8px;margin-top:8px;margin-bottom:12px;font-size:12px;color:var(--text-muted)}.bp-dialog-activate-row input[type=checkbox]{margin:0}.bp-dialog-activate-row label{cursor:pointer}.bp-dialog-buttons{display:flex;justify-content:flex-end;gap:8px}.bp-dialog-btn{padding:6px 16px;font-size:12px;border-radius:6px;border:1px solid var(--border);background:var(--bg);color:var(--text-muted);cursor:pointer;transition:all .15s}.bp-dialog-btn:hover{background:var(--bg-hover);color:var(--text)}.bp-dialog-btn-accent{background:var(--accent);color:#fff;border-color:var(--accent)}.bp-dialog-btn-accent:hover{opacity:.9;color:#fff;background:var(--accent)}.bp-dialog-btn-danger{background:#e55;color:#fff;border-color:#e55}.bp-dialog-btn-danger:hover{opacity:.9;color:#fff;background:#e55}.bp-toast{position:fixed;bottom:24px;left:50%;transform:translate(-50%) translateY(20px);background:var(--bg-surface);border:1px solid var(--border);color:var(--text);padding:8px 20px;border-radius:8px;font-size:12px;z-index:1001;opacity:0;transition:opacity .3s,transform .3s;box-shadow:0 4px 16px var(--shadow)}.bp-toast-visible{opacity:1;transform:translate(-50%) translateY(0)}.context-menu{position:absolute;z-index:100;background:var(--bg-surface);border:1px solid var(--border);border-radius:8px;padding:4px;min-width:180px;box-shadow:0 8px 24px var(--shadow)}.context-menu-item{padding:6px 12px;font-size:12px;color:var(--text);border-radius:4px;cursor:pointer;white-space:nowrap}.context-menu-item:hover{background:var(--bg-hover)}.context-menu-separator{height:1px;background:var(--border);margin:4px 8px}.path-bar{position:absolute;bottom:16px;left:50%;transform:translate(-50%);z-index:var(--z-canvas-overlay);display:flex;align-items:center;gap:4px;background:var(--bg-surface);border:1px solid var(--border);border-radius:8px;padding:6px 12px;box-shadow:0 4px 16px var(--shadow);max-width:80%;overflow-x:auto}.path-bar.hidden{display:none}.path-bar-node{font-size:11px;color:var(--text);padding:2px 8px;border-radius:4px;cursor:pointer;white-space:nowrap;flex-shrink:0}.path-bar-node:hover{background:var(--bg-hover)}.path-bar-edge{font-size:9px;color:var(--text-dim);white-space:nowrap;flex-shrink:0}.path-bar-close{background:none;border:none;color:var(--text-dim);font-size:14px;cursor:pointer;padding:0 4px;margin-left:8px;flex-shrink:0}.path-bar-close:hover{color:var(--text)}.walk-trail-edge{font-size:9px;color:var(--text-dim);padding:1px 0 1px 24px;opacity:.7}.walk-indicator{font-size:10px;color:var(--accent);padding:2px 8px;border:1px solid rgba(212,162,127,.4);border-radius:4px;cursor:pointer;opacity:.4}.walk-indicator.active{opacity:1;background:#d4a27f26;animation:walk-strobe 2s ease-in-out infinite}@keyframes walk-strobe{0%,to{opacity:.6;border-color:#d4a27f4d}50%{opacity:1;border-color:#d4a27fcc}}.copy-prompt-btn{background:var(--bg-surface);border:1px solid var(--border);border-radius:8px;color:var(--text-muted);font-size:12px;cursor:pointer;padding:6px 10px;line-height:1;transition:color .15s,border-color .15s,background .15s;box-shadow:0 2px 8px var(--shadow)}.copy-prompt-btn:hover{color:var(--text);border-color:var(--text-muted);background:var(--bg-hover)}.ext-slot-top-left,.ext-slot-top-right{display:none;align-items:center;gap:4px}.ext-slot-top-left.has-icons,.ext-slot-top-right.has-icons{display:inline-flex}.ext-slot-bottom-left,.ext-slot-bottom-right{position:absolute;bottom:16px;z-index:var(--z-floating);display:none;flex-direction:row;align-items:center;gap:6px;padding:6px;background:var(--bg-surface);border:1px solid var(--border);border-radius:12px;box-shadow:0 4px 16px var(--shadow);pointer-events:auto}.ext-slot-bottom-left{left:16px}.ext-slot-bottom-right{right:16px}.ext-slot-bottom-left.has-icons,.ext-slot-bottom-right.has-icons{display:flex}.extension-taskbar-icon{display:inline-flex;align-items:center;gap:6px;background:var(--bg-surface);border:1px solid var(--border);border-radius:8px;color:var(--text-muted);font-size:12px;font-weight:500;font-family:inherit;cursor:pointer;padding:6px 10px;line-height:1;box-shadow:0 2px 8px var(--shadow);transition:color .15s,border-color .15s,background .15s}.ext-slot-bottom-left .extension-taskbar-icon,.ext-slot-bottom-right .extension-taskbar-icon{background:transparent;border-color:transparent;box-shadow:none}.extension-taskbar-icon:hover{color:var(--text);border-color:var(--text-muted);background:var(--bg-hover)}.ext-slot-bottom-left .extension-taskbar-icon:hover,.ext-slot-bottom-right .extension-taskbar-icon:hover{border-color:var(--border)}.extension-taskbar-icon-symbol{font-size:11px;opacity:.7}.extension-taskbar-icon-label{font-size:12px}.extension-panel-layer{position:absolute;top:0;right:0;bottom:0;left:0;pointer-events:none}.extension-panel{position:absolute;display:flex;flex-direction:column;background:var(--bg-surface);border:1px solid var(--border);border-radius:12px;box-shadow:0 8px 32px var(--shadow);overflow:hidden;pointer-events:auto;width:380px;max-height:calc(100vh - 120px)}.extension-panel.is-fullscreen{top:0!important;left:0!important;right:0;bottom:0;width:auto;max-height:none;border-radius:0}.extension-panel.is-hidden,#canvas-container.has-fullscreen-panel .canvas-top-left,#canvas-container.has-fullscreen-panel .canvas-top-right,#canvas-container.has-fullscreen-panel .ext-slot-bottom-left,#canvas-container.has-fullscreen-panel .ext-slot-bottom-right,#canvas-container.has-fullscreen-panel .ext-slot-top-left,#canvas-container.has-fullscreen-panel .ext-slot-top-right{display:none}#canvas-container.has-fullscreen-panel .canvas-top-bar{top:0}#canvas-container.has-fullscreen-panel .extension-panel.is-fullscreen .extension-panel-header{padding-top:56px}.extension-panel.is-fullscreen{border:none;box-shadow:none}.extension-panel-header{display:flex;align-items:center;gap:6px;padding:8px 10px;border-bottom:1px solid var(--border);background:var(--bg-surface);flex-shrink:0;cursor:grab;-webkit-user-select:none;user-select:none}.extension-panel-header:active{cursor:grabbing}.extension-panel.is-fullscreen .extension-panel-header{cursor:default}.extension-panel-title{flex:1;font-size:13px;font-weight:500;color:var(--text);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.extension-panel-custom-btns{display:flex;gap:4px}.extension-panel-btn{display:inline-flex;align-items:center;justify-content:center;background:none;border:1px solid var(--border);border-radius:6px;color:var(--text-muted);font-size:12px;font-family:inherit;cursor:pointer;padding:3px 8px;line-height:1;min-height:22px;transition:color .15s,background .15s,border-color .15s}.extension-panel-btn:hover:not(:disabled){color:var(--text);background:var(--bg-hover);border-color:var(--text-muted)}.extension-panel-btn:disabled{opacity:.4;cursor:not-allowed}.extension-panel-btn-fullscreen{padding:2px 6px}.extension-panel-btn-fullscreen svg{display:block}.extension-panel-btn-close{font-size:16px;padding:0 7px}.extension-panel-body{flex:1;overflow:hidden;display:flex;flex-direction:column}
@@ -1,6 +0,0 @@
1
- var Jn=Object.defineProperty;var Kn=(t,e,s)=>e in t?Jn(t,e,{enumerable:!0,configurable:!0,writable:!0,value:s}):t[e]=s;var It=(t,e,s)=>Kn(t,typeof e!="symbol"?e+"":e,s);(function(){const e=document.createElement("link").relList;if(e&&e.supports&&e.supports("modulepreload"))return;for(const u of document.querySelectorAll('link[rel="modulepreload"]'))l(u);new MutationObserver(u=>{for(const r of u)if(r.type==="childList")for(const d of r.addedNodes)d.tagName==="LINK"&&d.rel==="modulepreload"&&l(d)}).observe(document,{childList:!0,subtree:!0});function s(u){const r={};return u.integrity&&(r.integrity=u.integrity),u.referrerPolicy&&(r.referrerPolicy=u.referrerPolicy),u.crossOrigin==="use-credentials"?r.credentials="include":u.crossOrigin==="anonymous"?r.credentials="omit":r.credentials="same-origin",r}function l(u){if(u.ep)return;u.ep=!0;const r=s(u);fetch(u.href,r)}})();const Zn="modulepreload",Qn=function(t){return"/"+t},hn={},eo=function(e,s,l){let u=Promise.resolve();if(s&&s.length>0){let d=function(g){return Promise.all(g.map(i=>Promise.resolve(i).then(a=>({status:"fulfilled",value:a}),a=>({status:"rejected",reason:a}))))};document.getElementsByTagName("link");const o=document.querySelector("meta[property=csp-nonce]"),n=(o==null?void 0:o.nonce)||(o==null?void 0:o.getAttribute("nonce"));u=d(s.map(g=>{if(g=Qn(g),g in hn)return;hn[g]=!0;const i=g.endsWith(".css"),a=i?'[rel="stylesheet"]':"";if(document.querySelector(`link[href="${g}"]${a}`))return;const M=document.createElement("link");if(M.rel=i?"stylesheet":Zn,i||(M.as="script"),M.crossOrigin="",M.href=g,n&&M.setAttribute("nonce",n),document.head.appendChild(M),i)return new Promise((T,x)=>{M.addEventListener("load",T),M.addEventListener("error",()=>x(new Error(`Unable to preload CSS for ${g}`)))})}))}function r(d){const o=new Event("vite:preloadError",{cancelable:!0});if(o.payload=d,window.dispatchEvent(o),!o.defaultPrevented)throw d}return u.then(d=>{for(const o of d||[])o.status==="rejected"&&r(o.reason);return e().catch(r)})};async function vt(){const t=await fetch("/api/ontologies");return t.ok?t.json():[]}async function Mt(t){const e=await fetch(`/api/ontologies/${encodeURIComponent(t)}`);if(!e.ok)throw new Error(`Failed to load ontology: ${t}`);return e.json()}async function to(){const t=await fetch("/api/remotes");return t.ok?t.json():[]}async function no(t){const e=await fetch(`/api/remotes/${encodeURIComponent(t)}`);if(!e.ok)throw new Error(`Failed to load remote graph: ${t}`);return e.json()}async function Ot(t,e){if(!(await fetch(`/api/ontologies/${encodeURIComponent(t)}`,{method:"PUT",headers:{"Content-Type":"application/json"},body:JSON.stringify(e)})).ok)throw new Error(`Failed to save ontology: ${t}`)}async function oo(t,e){if(!(await fetch(`/api/ontologies/${encodeURIComponent(t)}/rename`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({name:e})})).ok)throw new Error(`Failed to rename ontology: ${t}`)}async function so(t){const e=await fetch(`/api/graphs/${encodeURIComponent(t)}/branches`);return e.ok?e.json():[]}async function fn(t,e,s){const l=await fetch(`/api/graphs/${encodeURIComponent(t)}/branches`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({name:e,from:s})});if(!l.ok){const u=await l.json().catch(()=>({}));throw new Error(u.error||"Failed to create branch")}}async function gn(t,e){const s=await fetch(`/api/graphs/${encodeURIComponent(t)}/branches/switch`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({name:e})});if(!s.ok){const l=await s.json().catch(()=>({}));throw new Error(l.error||"Failed to switch branch")}}async function ao(t,e){const s=await fetch(`/api/graphs/${encodeURIComponent(t)}/branches/${encodeURIComponent(e)}`,{method:"DELETE"});if(!s.ok){const l=await s.json().catch(()=>({}));throw new Error(l.error||"Failed to delete branch")}}async function co(t){const e=await fetch(`/api/graphs/${encodeURIComponent(t)}/snapshots`);return e.ok?e.json():[]}async function io(t,e){const s=await fetch(`/api/graphs/${encodeURIComponent(t)}/snapshots`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({label:e})});if(!s.ok){const l=await s.json().catch(()=>({}));throw new Error(l.error||"Failed to create snapshot")}}async function lo(t,e){const s=await fetch(`/api/graphs/${encodeURIComponent(t)}/rollback`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({version:e})});if(!s.ok){const l=await s.json().catch(()=>({}));throw new Error(l.error||"Failed to rollback")}}async function ro(t){const e=await fetch(`/api/graphs/${encodeURIComponent(t)}/snippets`);return e.ok?e.json():[]}async function yn(t,e,s,l,u){const r=await fetch(`/api/graphs/${encodeURIComponent(t)}/snippets`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({label:e,description:u,nodeIds:s,edgeIds:l})});if(!r.ok)throw new Error("Failed to save snippet");return(await r.json()).id}async function po(t,e){const s=await fetch(`/api/graphs/${encodeURIComponent(t)}/snippets/${encodeURIComponent(e)}`);if(!s.ok)throw new Error("Snippet not found");return s.json()}async function uo(t,e){if(!(await fetch(`/api/graphs/${encodeURIComponent(t)}/snippets/${encodeURIComponent(e)}`,{method:"DELETE"})).ok)throw new Error("Failed to delete snippet")}const Cn="bp-dialog-overlay";function Zt(){var e;(e=document.querySelector(`.${Cn}`))==null||e.remove();const t=document.createElement("div");return t.className=Cn,document.body.appendChild(t),t}function Qt(t,e){const s=document.createElement("div");s.className="bp-dialog";const l=document.createElement("h4");return l.className="bp-dialog-title",l.textContent=e,s.appendChild(l),t.appendChild(s),t.addEventListener("click",u=>{u.target===t&&t.remove()}),s}function en(t,e){const s=document.createElement("div");s.className="bp-dialog-buttons";for(const l of e){const u=document.createElement("button");u.className="bp-dialog-btn",l.accent&&u.classList.add("bp-dialog-btn-accent"),l.danger&&u.classList.add("bp-dialog-btn-danger"),u.textContent=l.label,u.addEventListener("click",l.onClick),s.appendChild(u)}t.appendChild(s)}function jn(t,e){return new Promise(s=>{var d;const l=Zt(),u=Qt(l,t),r=document.createElement("p");r.className="bp-dialog-message",r.textContent=e,u.appendChild(r),en(u,[{label:"Cancel",onClick:()=>{l.remove(),s(!1)}},{label:"Confirm",accent:!0,onClick:()=>{l.remove(),s(!0)}}]),(d=u.querySelector(".bp-dialog-btn-accent"))==null||d.focus()})}function Bt(t,e,s){return new Promise(l=>{const u=Zt(),r=Qt(u,t),d=document.createElement("input");d.type="text",d.className="bp-dialog-input",d.placeholder=e??"",d.value="",r.appendChild(d);const o=()=>{const n=d.value.trim();u.remove(),l(n||null)};d.addEventListener("keydown",n=>{n.key==="Enter"&&o(),n.key==="Escape"&&(u.remove(),l(null))}),en(r,[{label:"Cancel",onClick:()=>{u.remove(),l(null)}},{label:"OK",accent:!0,onClick:o}]),d.focus(),d.select()})}function mo(){return new Promise(t=>{const e=Zt(),s=Qt(e,"Add Backpack"),l=document.createElement("p");l.className="bp-dialog-message",l.textContent="Enter the absolute path to a directory that should become a backpack. It will be shown in the sidebar using the last segment of the path as its display name.",s.appendChild(l);const u=document.createElement("label");u.className="bp-dialog-label",u.textContent="Path",s.appendChild(u);const r=document.createElement("div");r.className="bp-dialog-path-row",s.appendChild(r);const d=document.createElement("input");d.type="text",d.className="bp-dialog-input bp-dialog-path-input",d.placeholder="/Users/you/OneDrive/work",r.appendChild(d);const o=document.createElement("button");o.type="button",o.className="bp-dialog-btn bp-dialog-browse-btn",o.textContent="Browse...",r.appendChild(o),typeof window.showDirectoryPicker=="function"||(o.disabled=!0,o.title="Browser doesn't support native folder picker — paste the path manually"),o.addEventListener("click",async x=>{x.preventDefault();try{const F=await window.showDirectoryPicker({mode:"read"});g.textContent=`Picked "${F.name}" — paste the absolute path to it below.`,d.focus()}catch{}});const g=document.createElement("div");g.className="bp-dialog-picker-hint",s.appendChild(g);const i=document.createElement("div");i.className="bp-dialog-activate-row";const a=document.createElement("input");a.type="checkbox",a.id="bp-dialog-activate",a.checked=!0;const M=document.createElement("label");M.htmlFor="bp-dialog-activate",M.textContent="Switch to this backpack after registering",i.appendChild(a),i.appendChild(M),s.appendChild(i),d.addEventListener("dragover",x=>{x.preventDefault(),d.classList.add("bp-dialog-drag-over")}),d.addEventListener("dragleave",()=>{d.classList.remove("bp-dialog-drag-over")}),d.addEventListener("drop",x=>{var V,z,X;x.preventDefault(),d.classList.remove("bp-dialog-drag-over");const F=(V=x.dataTransfer)==null?void 0:V.items;if(!F||F.length===0)return;const W=(X=(z=F[0]).webkitGetAsEntry)==null?void 0:X.call(z);W!=null&&W.isDirectory&&(g.textContent=`Dropped "${W.name}" — paste the absolute path to it below.`)});const T=()=>{const x=d.value.trim();x&&(e.remove(),t({path:x,activate:a.checked}))};d.addEventListener("keydown",x=>{x.key==="Enter"&&T(),x.key==="Escape"&&(e.remove(),t(null))}),en(s,[{label:"Cancel",onClick:()=>{e.remove(),t(null)}},{label:"Register",accent:!0,onClick:T}]),d.focus()})}function wt(t,e=3e3){const s=document.querySelector(".bp-toast");s&&s.remove();const l=document.createElement("div");l.className="bp-toast",l.textContent=t,document.body.appendChild(l),setTimeout(()=>l.classList.add("bp-toast-visible"),10),setTimeout(()=>{l.classList.remove("bp-toast-visible"),setTimeout(()=>l.remove(),300)},e)}const vn="http://www.w3.org/2000/svg";function ct(t,e){const s=document.createElementNS(vn,"svg"),l=t.size??16;s.setAttribute("width",String(l)),s.setAttribute("height",String(l)),s.setAttribute("viewBox",t.viewBox??"0 0 24 24"),s.setAttribute("fill","none"),s.setAttribute("stroke","currentColor"),s.setAttribute("stroke-width",String(t.strokeWidth??2)),t.strokeLinecap&&s.setAttribute("stroke-linecap",t.strokeLinecap),t.strokeLinejoin&&s.setAttribute("stroke-linejoin",t.strokeLinejoin),t.className&&s.setAttribute("class",t.className);for(const u of e){const r=document.createElementNS(vn,u.tag);for(const[d,o]of Object.entries(u.attrs))r.setAttribute(d,String(o));s.appendChild(r)}return s}function ho(t){return Array.from(t.childNodes).map(e=>e.cloneNode(!0))}function fo(t,e){t.replaceChildren(...e)}function bn(t){return t>=1e3?`${(t/1e3).toFixed(1)}k tokens`:`${t} tokens`}function xn(t,e){return t*50+e*25+50}function go(t,e){const s=typeof e=="function"?{onSelect:e}:e,l=document.createElement("h2");l.textContent="Backpack Viewer";const u=document.createElement("input");u.type="text",u.placeholder="Filter...",u.id="filter";const r=document.createElement("ul");r.id="ontology-list";const d=document.createElement("h3");d.className="sidebar-section-heading",d.textContent="REMOTE GRAPHS",d.hidden=!0;const o=document.createElement("ul");o.id="remote-list",o.className="remote-list",o.hidden=!0;const n=document.createElement("div");n.className="sidebar-footer";const g=document.createElement("a");g.href="mailto:support@backpackontology.com",g.textContent="support@backpackontology.com";const i=document.createElement("span");i.textContent="Feedback & support";const a=document.createElement("span");a.className="sidebar-version",a.textContent="v0.7.4",n.append(g,i,a);const M=document.createElement("button");M.className="sidebar-collapse-btn",M.title="Toggle sidebar (Tab)",M.appendChild(ct({size:14},[{tag:"polyline",attrs:{points:"11 17 6 12 11 7"}},{tag:"polyline",attrs:{points:"18 17 13 12 18 7"}}]));let T=!1;function x(){T=!T,t.classList.toggle("sidebar-collapsed",T),ye.classList.toggle("hidden",!T)}M.addEventListener("click",x);const F=document.createElement("div");F.className="sidebar-heading-row",F.appendChild(l),F.appendChild(M),t.appendChild(F);const W=document.createElement("div");W.className="sidebar-stale-banner",W.hidden=!0,t.appendChild(W);const V=document.createElement("button");V.className="backpack-picker-pill",V.type="button",V.setAttribute("aria-haspopup","listbox"),V.setAttribute("aria-expanded","false");const z=document.createElement("span");z.className="backpack-picker-dot";const X=document.createElement("span");X.className="backpack-picker-name",X.textContent="...";const H=document.createElement("span");H.className="backpack-picker-caret",H.textContent="▾",V.appendChild(z),V.appendChild(X),V.appendChild(H);const K=document.createElement("div");K.className="backpack-picker-dropdown",K.hidden=!0,K.setAttribute("role","listbox");const q=document.createElement("div");q.className="backpack-picker-container",q.appendChild(V),q.appendChild(K),t.appendChild(q);let ue=!1;function U(){ue=!1,K.hidden=!0,V.setAttribute("aria-expanded","false")}function de(){ue=!0,K.hidden=!1,V.setAttribute("aria-expanded","true")}V.addEventListener("click",p=>{p.stopPropagation(),ue?U():de()}),document.addEventListener("click",p=>{q.contains(p.target)||U()});let xe=[],ee=null;function G(){K.replaceChildren();for(const v of xe){const m=document.createElement("button");m.className="backpack-picker-item",m.type="button",m.setAttribute("role","option"),v.active&&m.classList.add("active");const b=document.createElement("span");b.className="backpack-picker-item-dot",b.style.setProperty("--backpack-color",v.color);const L=document.createElement("span");L.className="backpack-picker-item-name",L.textContent=v.name;const h=document.createElement("span");h.className="backpack-picker-item-path",h.textContent=v.path,m.appendChild(b),m.appendChild(L),m.appendChild(h),m.addEventListener("click",S=>{S.stopPropagation(),U(),!v.active&&s.onBackpackSwitch&&s.onBackpackSwitch(v.name)}),K.appendChild(m)}const p=document.createElement("div");p.className="backpack-picker-divider",K.appendChild(p);const y=document.createElement("button");y.className="backpack-picker-item backpack-picker-add",y.type="button",y.textContent="+ Add new backpack…",y.addEventListener("click",async v=>{if(v.stopPropagation(),U(),!s.onBackpackRegister)return;const m=await mo();m&&s.onBackpackRegister(m.path,m.activate)}),K.appendChild(y)}const ye=document.createElement("button");ye.className="tools-pane-toggle hidden",ye.title="Show sidebar (Tab)",ye.appendChild(ct({size:14},[{tag:"polyline",attrs:{points:"13 7 18 12 13 17"}},{tag:"polyline",attrs:{points:"6 7 11 12 6 17"}}])),ye.addEventListener("click",x),t.appendChild(u),t.appendChild(r),t.appendChild(d),t.appendChild(o),t.appendChild(n);let Ce=[],se=[],ge="";return u.addEventListener("input",()=>{const p=u.value.toLowerCase();for(const y of Ce){const v=y.dataset.name??"";y.style.display=v.includes(p)?"":"none"}for(const y of se){const v=y.dataset.name??"";y.style.display=v.includes(p)?"":"none"}}),{setStaleVersionBanner(p,y){W.replaceChildren();const v=document.createElement("div");v.className="sidebar-stale-banner-title",v.textContent=`Viewer ${p} is out of date`;const m=document.createElement("div");m.className="sidebar-stale-banner-subtitle",m.textContent=`Latest is ${y}. Your version is stuck because of an npx cache.`;const b=document.createElement("pre");b.className="sidebar-stale-banner-hint",b.textContent=`npm cache clean --force
2
- npx backpack-viewer@latest`,W.appendChild(v),W.appendChild(m),W.appendChild(b),W.hidden=!1},setBackpacks(p){xe=p.slice();const y=p.find(v=>v.active)??null;ee=y,y&&(X.textContent=y.name,z.style.setProperty("--backpack-color",y.color),t.style.setProperty("--backpack-color",y.color)),G()},setActiveBackpack(p){ee=p,xe=xe.map(y=>({...y,active:y.name===p.name})),xe.some(y=>y.name===p.name)||xe.push({...p,active:!0}),X.textContent=p.name,z.style.setProperty("--backpack-color",p.color),t.style.setProperty("--backpack-color",p.color),G()},getActiveBackpack(){return ee},setSummaries(p){r.replaceChildren();const y=fetch("/api/locks").then(v=>v.json()).catch(()=>({}));Ce=p.map(v=>{const m=document.createElement("li");m.className="ontology-item",m.dataset.name=v.name;const b=document.createElement("span");b.className="name",b.textContent=v.name;const L=document.createElement("span");L.className="stats";const h=xn(v.nodeCount,v.edgeCount);L.textContent=`${v.nodeCount} nodes, ${v.edgeCount} edges · ~${bn(h)}`;const S=document.createElement("span");S.className="sidebar-branch",S.dataset.graph=v.name;const w=document.createElement("span");if(w.className="sidebar-lock-badge",w.dataset.graph=v.name,y.then(N=>{if(!w.isConnected)return;const I=N[v.name];I&&typeof I=="object"&&I.author&&(w.textContent=`editing: ${I.author}`,w.title=`Last activity: ${I.lastActivity??""}`,w.classList.add("active"))}),m.appendChild(b),m.appendChild(L),m.appendChild(w),m.appendChild(S),s.onRename){const N=document.createElement("button");N.className="sidebar-edit-btn",N.textContent="✎",N.title="Rename";const I=s.onRename;N.addEventListener("click",C=>{C.stopPropagation();const B=document.createElement("input");B.type="text",B.className="sidebar-rename-input",B.value=v.name,b.textContent="",b.appendChild(B),N.style.display="none",B.focus(),B.select();const $=()=>{const te=B.value.trim();te&&te!==v.name?I(v.name,te):(b.textContent=v.name,N.style.display="")};B.addEventListener("blur",$),B.addEventListener("keydown",te=>{te.key==="Enter"&&B.blur(),te.key==="Escape"&&(B.value=v.name,B.blur())})}),m.appendChild(N)}return m.addEventListener("click",()=>s.onSelect(v.name)),r.appendChild(m),m}),ge&&this.setActive(ge)},setActive(p){ge=p;for(const y of Ce)y.classList.toggle("active",y.dataset.name===p);for(const y of se)y.classList.toggle("active",y.dataset.name===p)},setRemotes(p){o.replaceChildren(),se=p.map(v=>{const m=document.createElement("li");m.className="ontology-item ontology-item-remote",m.dataset.name=v.name;const b=document.createElement("div");b.className="remote-name-row";const L=document.createElement("span");L.className="name",L.textContent=v.name;const h=document.createElement("span");h.className="remote-badge",h.textContent=v.pinned?"remote · pinned":"remote",h.title=`Source: ${v.source??v.url}`,b.appendChild(L),b.appendChild(h);const S=document.createElement("span");S.className="stats";const w=xn(v.nodeCount,v.edgeCount);S.textContent=`${v.nodeCount} nodes, ${v.edgeCount} edges · ~${bn(w)}`;const N=document.createElement("span");return N.className="remote-source",N.textContent=v.source??new URL(v.url).hostname,N.title=v.url,m.appendChild(b),m.appendChild(S),m.appendChild(N),m.addEventListener("click",()=>s.onSelect(v.name)),o.appendChild(m),m});const y=p.length>0;d.hidden=!y,o.hidden=!y,ge&&this.setActive(ge)},setActiveBranch(p,y,v){const m=r.querySelectorAll(`.sidebar-branch[data-graph="${p}"]`);for(const b of m){b.textContent=`/ ${y}`,b.title="Click to switch branch",b.style.cursor="pointer";const L=b.cloneNode(!0);b.replaceWith(L),L.addEventListener("click",h=>{h.stopPropagation(),be(p,L,v??[])})}},setSnippets(p,y){var b;const v=Ce.find(L=>L.dataset.name===p);if(!v||((b=v.querySelector(".sidebar-snippets"))==null||b.remove(),y.length===0))return;const m=document.createElement("div");m.className="sidebar-snippets";for(const L of y){const h=document.createElement("div");h.className="sidebar-snippet";const S=document.createElement("span");S.className="sidebar-snippet-label",S.textContent=`◆ ${L.label}`,S.title=`${L.nodeCount} nodes — click to load`;const w=document.createElement("button");w.className="sidebar-snippet-delete",w.textContent="×",w.title="Delete snippet",w.addEventListener("click",N=>{var I;N.stopPropagation(),(I=s.onSnippetDelete)==null||I.call(s,p,L.id)}),h.appendChild(S),h.appendChild(w),h.addEventListener("click",N=>{var I;N.stopPropagation(),(I=s.onSnippetLoad)==null||I.call(s,p,L.id)}),m.appendChild(h)}v.appendChild(m)},toggle:x,expandBtn:ye};function be(p,y,v){const m=t.querySelector(".branch-picker");m&&m.remove();const b=document.createElement("div");b.className="branch-picker";for(const h of v){const S=document.createElement("div");S.className="branch-picker-item",h.active&&S.classList.add("branch-picker-active");const w=document.createElement("span");if(w.textContent=h.name,S.appendChild(w),!h.active&&s.onBranchDelete){const N=document.createElement("button");N.className="branch-picker-delete",N.textContent="×",N.title=`Delete ${h.name}`,N.addEventListener("click",I=>{I.stopPropagation(),jn("Delete branch",`Delete branch "${h.name}"?`).then(C=>{C&&(s.onBranchDelete(p,h.name),b.remove())})}),S.appendChild(N)}h.active||S.addEventListener("click",()=>{var N;(N=s.onBranchSwitch)==null||N.call(s,p,h.name),b.remove()}),b.appendChild(S)}if(s.onBranchCreate){const h=document.createElement("div");h.className="branch-picker-item branch-picker-create",h.textContent="+ New branch",h.addEventListener("click",()=>{Bt("New branch","Branch name").then(S=>{S&&(s.onBranchCreate(p,S),b.remove())})}),b.appendChild(h)}y.after(b);const L=h=>{b.contains(h.target)||(b.remove(),document.removeEventListener("click",L))};setTimeout(()=>document.addEventListener("click",L),0)}}function Gt(t,e,s,l){return{x0:t,y0:e,x1:s,y1:l,cx:0,cy:0,mass:0,children:[null,null,null,null],body:null}}function En(t,e,s){const l=(t.x0+t.x1)/2,u=(t.y0+t.y1)/2;return(e<l?0:1)+(s<u?0:2)}function wn(t,e){const s=(t.x0+t.x1)/2,l=(t.y0+t.y1)/2;switch(e){case 0:return[t.x0,t.y0,s,l];case 1:return[s,t.y0,t.x1,l];case 2:return[t.x0,l,s,t.y1];default:return[s,l,t.x1,t.y1]}}function Vt(t,e){if(t.mass===0&&t.body===null){t.body=e,t.cx=e.x,t.cy=e.y,t.mass=1;return}if(t.body!==null){const u=t.body;t.body=null,u.x===e.x&&u.y===e.y&&(e.x+=(Math.random()-.5)*.1,e.y+=(Math.random()-.5)*.1);const r=En(t,u.x,u.y);if(t.children[r]===null){const[d,o,n,g]=wn(t,r);t.children[r]=Gt(d,o,n,g)}Vt(t.children[r],u)}const s=En(t,e.x,e.y);if(t.children[s]===null){const[u,r,d,o]=wn(t,s);t.children[s]=Gt(u,r,d,o)}Vt(t.children[s],e);const l=t.mass+1;t.cx=(t.cx*t.mass+e.x)/l,t.cy=(t.cy*t.mass+e.y)/l,t.mass=l}function yo(t){if(t.length===0)return null;let e=1/0,s=1/0,l=-1/0,u=-1/0;for(const i of t)i.x<e&&(e=i.x),i.y<s&&(s=i.y),i.x>l&&(l=i.x),i.y>u&&(u=i.y);const r=Math.max(l-e,u-s)*.1+50,d=(e+l)/2,o=(s+u)/2,n=Math.max(l-e,u-s)/2+r,g=Gt(d-n,o-n,d+n,o+n);for(const i of t)Vt(g,i);return g}function Co(t,e,s,l,u,r){zn(t,e,s,l,u,r)}function zn(t,e,s,l,u,r){if(t.mass===0)return;const d=t.cx-e.x,o=t.cy-e.y,n=d*d+o*o;if(t.body!==null){if(t.body!==e){let i=Math.sqrt(n);i<r&&(i=r);const a=l*u/(i*i),M=d/i*a,T=o/i*a;e.vx-=M,e.vy-=T}return}const g=t.x1-t.x0;if(g*g/n<s*s){let i=Math.sqrt(n);i<r&&(i=r);const a=l*t.mass*u/(i*i),M=d/i*a,T=o/i*a;e.vx-=M,e.vy-=T;return}for(let i=0;i<4;i++)t.children[i]!==null&&zn(t.children[i],e,s,l,u,r)}const _n={clusterStrength:.08,spacing:1.5},kn=6e3,vo=12e3,bo=.004,Hn=140,Yn=350,Sn=.9,Nn=.01,bt=30,Wt=50;let et={..._n};function lt(t){t.clusterStrength!==void 0&&(et.clusterStrength=t.clusterStrength),t.spacing!==void 0&&(et.spacing=t.spacing)}function Et(){return{...et}}function xo(t){if(t<=30)return{..._n};const e=Math.log2(t/30);return{clusterStrength:Math.min(.5,.08+.06*e),spacing:Math.min(15,1.5+1.2*e)}}function Eo(t,e){for(const s of Object.values(t))if(typeof s=="string")return s;return e}function Ln(t,e,s){const l=new Set(e);let u=new Set(e);for(let r=0;r<s;r++){const d=new Set;for(const o of t.edges)u.has(o.sourceId)&&!l.has(o.targetId)&&d.add(o.targetId),u.has(o.targetId)&&!l.has(o.sourceId)&&d.add(o.sourceId);for(const o of d)l.add(o);if(u=d,d.size===0)break}return{nodes:t.nodes.filter(r=>l.has(r.id)),edges:t.edges.filter(r=>l.has(r.sourceId)&&l.has(r.targetId)),metadata:t.metadata}}function Ut(t){const e=new Map,s=[...new Set(t.nodes.map(n=>n.type))],l=Math.sqrt(s.length)*Yn*.6*Math.max(1,et.spacing),u=new Map,r=new Map;for(const n of t.nodes)r.set(n.type,(r.get(n.type)??0)+1);const d=t.nodes.map(n=>{const g=s.indexOf(n.type),i=2*Math.PI*g/Math.max(s.length,1),a=Math.cos(i)*l,M=Math.sin(i)*l,T=u.get(n.type)??0;u.set(n.type,T+1);const x=r.get(n.type)??1,F=2*Math.PI*T/x,W=Hn*.6,V={id:n.id,x:a+Math.cos(F)*W,y:M+Math.sin(F)*W,vx:0,vy:0,label:Eo(n.properties,n.id),type:n.type};return e.set(n.id,V),V}),o=t.edges.map(n=>({sourceId:n.sourceId,targetId:n.targetId,type:n.type}));return{nodes:d,edges:o,nodeMap:e}}const wo=.7,ko=80;function So(t,e){const{nodes:s,edges:l,nodeMap:u}=t,r=vo*et.spacing;if(s.length>=ko){const o=yo(s);if(o)for(const g of s)Co(o,g,wo,r,e,bt);const n=r-kn;if(n>0){const g=new Map;for(const i of s){let a=g.get(i.type);a||(a=[],g.set(i.type,a)),a.push(i)}for(const i of g.values())for(let a=0;a<i.length;a++)for(let M=a+1;M<i.length;M++){const T=i[a],x=i[M];let F=x.x-T.x,W=x.y-T.y,V=Math.sqrt(F*F+W*W);V<bt&&(V=bt);const z=n*e/(V*V),X=F/V*z,H=W/V*z;T.vx+=X,T.vy+=H,x.vx-=X,x.vy-=H}}}else for(let o=0;o<s.length;o++)for(let n=o+1;n<s.length;n++){const g=s[o],i=s[n];let a=i.x-g.x,M=i.y-g.y,T=Math.sqrt(a*a+M*M);T<bt&&(T=bt);const F=(g.type===i.type?kn:r)*e/(T*T),W=a/T*F,V=M/T*F;g.vx-=W,g.vy-=V,i.vx+=W,i.vy+=V}for(const o of l){const n=u.get(o.sourceId),g=u.get(o.targetId);if(!n||!g)continue;const i=g.x-n.x,a=g.y-n.y,M=Math.sqrt(i*i+a*a);if(M===0)continue;const T=n.type===g.type?Hn*et.spacing:Yn*et.spacing,x=bo*(M-T)*e,F=i/M*x,W=a/M*x;n.vx+=F,n.vy+=W,g.vx-=F,g.vy-=W}for(const o of s)o.vx-=o.x*Nn*e,o.vy-=o.y*Nn*e;const d=new Map;for(const o of s){const n=d.get(o.type)??{x:0,y:0,count:0};n.x+=o.x,n.y+=o.y,n.count++,d.set(o.type,n)}for(const o of d.values())o.x/=o.count,o.y/=o.count;for(const o of s){const n=d.get(o.type);o.vx+=(n.x-o.x)*et.clusterStrength*e,o.vy+=(n.y-o.y)*et.clusterStrength*e}for(const o of s){if(o.pinned){o.vx=0,o.vy=0;continue}o.vx*=Sn,o.vy*=Sn;const n=Math.sqrt(o.vx*o.vx+o.vy*o.vy);n>Wt&&(o.vx=o.vx/n*Wt,o.vy=o.vy/n*Wt),o.x+=o.vx,o.y+=o.vy}return e*.995}const In=["#d4a27f","#c17856","#b07a5e","#d4956b","#a67c5a","#cc9e7c","#c4866a","#cb8e6c","#b8956e","#a88a70","#d9b08c","#c4a882","#e8b898","#b5927a","#a8886e","#d1a990"],Mn=new Map;function Ae(t){const e=Mn.get(t);if(e)return e;let s=0;for(let u=0;u<t.length;u++)s=(s<<5)-s+t.charCodeAt(u)|0;const l=In[Math.abs(s)%In.length];return Mn.set(t,l),l}class No{constructor(e){It(this,"cells",new Map);It(this,"cellSize");It(this,"invCell");this.cellSize=e,this.invCell=1/e}key(e,s){const l=e+32768|0,u=s+32768|0;return l*73856093^u*19349663}clear(){this.cells.clear()}insert(e){const s=Math.floor(e.x*this.invCell),l=Math.floor(e.y*this.invCell),u=this.key(s,l),r=this.cells.get(u);r?r.push(e):this.cells.set(u,[e])}rebuild(e){this.cells.clear();for(const s of e)this.insert(s)}query(e,s,l){const u=l*l,r=Math.floor((e-l)*this.invCell),d=Math.floor((e+l)*this.invCell),o=Math.floor((s-l)*this.invCell),n=Math.floor((s+l)*this.invCell);let g=null,i=u;for(let a=r;a<=d;a++)for(let M=o;M<=n;M++){const T=this.cells.get(this.key(a,M));if(T)for(const x of T){const F=x.x-e,W=x.y-s,V=F*F+W*W;V<=i&&(i=V,g=x)}}return g}}const pt=new Map,Lo=2e3;function Io(t,e,s){return`${t}|${e}|${s}`}const Mo=new OffscreenCanvas(1,1),Tn=Mo.getContext("2d");function To(t,e,s){Tn.font=e;const l=Tn.measureText(t),u=Math.ceil(l.width)+2,r=Math.ceil(l.actualBoundingBoxAscent+l.actualBoundingBoxDescent)+4,d=new OffscreenCanvas(u,r),o=d.getContext("2d");return o.font=e,o.fillStyle=s,o.textAlign="left",o.textBaseline="top",o.fillText(t,1,1),{canvas:d,width:u,height:r}}function An(t,e,s,l,u,r,d){const o=Io(e,u,r);let n=pt.get(o);if(!n){if(pt.size>=Lo){const a=pt.keys().next().value;a!==void 0&&pt.delete(a)}n=To(e,u,r),pt.set(o,n)}const g=s-n.width/2,i=d==="top"?l:l-n.height;t.drawImage(n.canvas,g,i)}function Ao(){pt.clear()}function Ee(t){return getComputedStyle(document.documentElement).getPropertyValue(t).trim()}const Ue=20,jt=.001,Po={hideBadges:.4,hideLabels:.25,hideEdgeLabels:.35,smallNodes:.2,hideArrows:.15,dotNodes:.1,hullsOnly:.05},Ro={zoomFactor:1.3,zoomMin:.05,zoomMax:10,panAnimationMs:300};function Tt(t,e,s,l,u,r=100){const d=(t-s.x)*s.scale,o=(e-s.y)*s.scale;return d>=-r&&d<=l+r&&o>=-r&&o<=u+r}function Bo(t,e,s,l){const u={...Po,...(l==null?void 0:l.lod)??{}},r={...Ro,...(l==null?void 0:l.navigation)??{}},d={pulseSpeed:.02,...(l==null?void 0:l.walk)??{}},o=t.querySelector("canvas"),n=o.getContext("2d"),g=window.devicePixelRatio||1;let i={x:0,y:0,scale:1},a=null,M=1,T=0,x=new Set,F=null,W=!0,V=!0,z=!0,X=!0,H="idle",K=[],q=0,ue=0,U=null,de=new Set;const xe=5;let ee=null,G=null,ye=1,Ce=null,se=null,ge=null,be=!1,p=[],y=0,v=0;const m=400,b=new No(Ue*2);let L=0;function h(){ie(),L||(L=requestAnimationFrame(()=>{L=0,c()}))}const S=150;let w=null,N=!1;function I(){if(!w)try{w=new Worker(new URL("/assets/layout-worker-4xak23M6.js",import.meta.url),{type:"module"}),w.onmessage=C,w.onerror=()=>{N=!1,w=null,we()}}catch{return N=!1,null}return w}function C(f){const k=f.data;if(k.type==="tick"&&a){const P=k.positions,D=a.nodes;for(let _=0;_<D.length;_++)D[_].x=P[_*4],D[_].y=P[_*4+1],D[_].vx=P[_*4+2],D[_].vy=P[_*4+3];M=k.alpha,b.rebuild(D),c()}k.type==="settled"&&(M=0,be&&p.length>0&&!ae&&(ae=requestAnimationFrame(pe)))}let B=null,$=null,te=!0;function ie(){te=!0}let le=null,me=null;const ve=r.panAnimationMs;function je(){o.width=o.clientWidth*g,o.height=o.clientHeight*g,ie(),h()}const qe=new ResizeObserver(je);qe.observe(t),je();function Xe(f,k){return[f/i.scale+i.x,k/i.scale+i.y]}function Je(f,k){if(!a)return null;const[P,D]=Xe(f,k);return b.query(P,D,Ue)}function ut(){if(!U)return;n.save();const f=Math.min(U.x1,U.x2),k=Math.max(U.x1,U.x2),P=Math.min(U.y1,U.y2),D=Math.max(U.y1,U.y2);n.strokeStyle=Ee("--accent")||"#d4a27f",n.fillStyle=Ee("--accent")||"#d4a27f",n.globalAlpha=.12,n.fillRect(f,P,k-f,D-P),n.globalAlpha=.8,n.lineWidth=1/Math.max(i.scale,.5),n.setLineDash([6/Math.max(i.scale,.5),4/Math.max(i.scale,.5)]),n.strokeRect(f,P,k-f,D-P),n.setLineDash([]),n.restore()}function mt(){if(!a)return;y+=d.pulseSpeed;const f=new Set(p);n.save(),n.setTransform(g,0,0,g,0,0),B&&(n.clearRect(0,0,o.clientWidth,o.clientHeight),n.drawImage(B,0,0,o.clientWidth,o.clientHeight)),n.save(),n.translate(-i.x*i.scale,-i.y*i.scale),n.scale(i.scale,i.scale);const k=Ee("--canvas-walk-edge")||"#1a1a1a",P=[];for(const j of a.edges){if(!f.has(j.sourceId)||!f.has(j.targetId)||j.sourceId===j.targetId)continue;const O=a.nodeMap.get(j.sourceId),J=a.nodeMap.get(j.targetId);!O||!J||P.push(O.x,O.y,J.x,J.y)}if(P.length>0){n.beginPath();for(let j=0;j<P.length;j+=4)n.moveTo(P[j],P[j+1]),n.lineTo(P[j+2],P[j+3]);n.strokeStyle=k,n.lineWidth=3,n.globalAlpha=.5+.5*Math.sin(y),n.stroke(),n.globalAlpha=1}const D=i.scale<u.smallNodes?Ue*.5:Ue,_=Ee("--accent")||"#d4a27f";for(const j of p){const O=a.nodeMap.get(j);if(!O||!Tt(O.x,O.y,i,o.clientWidth,o.clientHeight))continue;const J=j===p[p.length-1],Z=.5+.5*Math.sin(y);n.strokeStyle=_,n.lineWidth=J?3:2,n.globalAlpha=J?.5+.5*Z:.3+.4*Z,n.beginPath(),n.arc(O.x,O.y,D+(J?6:4),0,Math.PI*2),n.stroke()}n.globalAlpha=1,ut(),n.restore(),X&&a.nodes.length>1&&E(),n.restore()}function c(){var ln;if(!a){n.clearRect(0,0,o.width,o.height);return}if(!te&&B&&be&&p.length>0&&M<jt){mt();return}const f=M<jt&&be&&p.length>0;be&&p.length>0&&(y+=d.pulseSpeed);const k=be&&!f?new Set(p):null,P=Ee("--canvas-edge"),D=Ee("--canvas-edge-highlight"),_=Ee("--canvas-edge-dim"),j=Ee("--canvas-edge-label"),O=Ee("--canvas-edge-label-highlight"),J=Ee("--canvas-edge-label-dim"),Z=Ee("--canvas-arrow"),re=Ee("--canvas-arrow-highlight"),fe=Ee("--canvas-node-label"),ke=Ee("--canvas-node-label-dim"),Se=Ee("--canvas-type-badge"),Te=Ee("--canvas-type-badge-dim"),Re=Ee("--canvas-selection-border"),ze=Ee("--canvas-node-border");if(n.save(),n.setTransform(g,0,0,g,0,0),n.clearRect(0,0,o.clientWidth,o.clientHeight),n.save(),n.translate(-i.x*i.scale,-i.y*i.scale),n.scale(i.scale,i.scale),z&&i.scale>=u.smallNodes){const Q=new Map;for(const Pe of a.nodes){if(F!==null&&!F.has(Pe.id))continue;const Fe=Q.get(Pe.type)??[];Fe.push(Pe),Q.set(Pe.type,Fe)}for(const[Pe,Fe]of Q){if(Fe.length<2)continue;const at=Ae(Pe),ot=Ue*2.5;let Ye=1/0,Ve=1/0,Be=-1/0,Qe=-1/0;for(const We of Fe)We.x<Ye&&(Ye=We.x),We.y<Ve&&(Ve=We.y),We.x>Be&&(Be=We.x),We.y>Qe&&(Qe=We.y);n.beginPath();const oe=(Be-Ye)/2+ot,Me=(Qe-Ve)/2+ot,Ne=(Ye+Be)/2,_e=(Ve+Qe)/2;n.ellipse(Ne,_e,oe,Me,0,0,Math.PI*2),n.fillStyle=at,n.globalAlpha=.05,n.fill(),n.strokeStyle=at,n.globalAlpha=.12,n.lineWidth=1,n.setLineDash([4,4]),n.stroke(),n.setLineDash([]),n.globalAlpha=1}}let Ge=null;if(x.size>0){Ge=new Set;for(const Q of a.edges)x.has(Q.sourceId)&&Ge.add(Q.targetId),x.has(Q.targetId)&&Ge.add(Q.sourceId)}const nt=Ee("--accent")||"#d4a27f",He=Ee("--canvas-walk-edge")||"#1a1a1a",it=i.scale>=u.hideArrows,Nt=V&&i.scale>=u.hideEdgeLabels;if(W){const Q=[],Pe=[],Fe=[],at=[],ot=[],Ye=[];for(const oe of a.edges){const Me=a.nodeMap.get(oe.sourceId),Ne=a.nodeMap.get(oe.targetId);if(!Me||!Ne||!Tt(Me.x,Me.y,i,o.clientWidth,o.clientHeight,200)&&!Tt(Ne.x,Ne.y,i,o.clientWidth,o.clientHeight,200))continue;const _e=F===null||F.has(oe.sourceId),We=F===null||F.has(oe.targetId),rn=_e&&We;if(F!==null&&!_e&&!We)continue;const Dt=x.size>0&&(x.has(oe.sourceId)||x.has(oe.targetId))||F!==null&&rn,dn=F!==null&&!rn,pn=k!==null&&k.has(oe.sourceId)&&k.has(oe.targetId),un=ge?ee==null?void 0:ee.edges.find(Lt=>Lt.sourceId===oe.sourceId&&Lt.targetId===oe.targetId||Lt.targetId===oe.sourceId&&Lt.sourceId===oe.targetId):null,mn=!!(ge&&un&&ge.edgeIds.has(un.id));if(oe.sourceId===oe.targetId){Y(Me,oe.type,Dt,P,D,j,O);continue}(mn?ot:pn?at:Dt?Pe:dn?Fe:Q).push(Me.x,Me.y,Ne.x,Ne.y),(it||Nt)&&Ye.push({sx:Me.x,sy:Me.y,tx:Ne.x,ty:Ne.y,type:oe.type,highlighted:Dt,edgeDimmed:dn,isPathEdge:mn,isWalkEdge:pn})}const Ve=it?1.5:1,Qe=[{lines:Q,color:P,width:Ve,alpha:1},{lines:Fe,color:_,width:Ve,alpha:1},{lines:Pe,color:D,width:it?2.5:1,alpha:1},{lines:ot,color:nt,width:3,alpha:1},{lines:at,color:He,width:3,alpha:.5+.5*Math.sin(y)}];for(const oe of Qe)if(oe.lines.length!==0){n.beginPath();for(let Me=0;Me<oe.lines.length;Me+=4)n.moveTo(oe.lines[Me],oe.lines[Me+1]),n.lineTo(oe.lines[Me+2],oe.lines[Me+3]);n.strokeStyle=oe.color,n.lineWidth=oe.width,n.globalAlpha=oe.alpha,n.stroke()}n.globalAlpha=1;for(const oe of Ye)if(it&&R(oe.sx,oe.sy,oe.tx,oe.ty,oe.highlighted||oe.isPathEdge,Z,re),Nt){const Me=(oe.sx+oe.tx)/2,Ne=(oe.sy+oe.ty)/2;n.fillStyle=oe.highlighted?O:oe.edgeDimmed?J:j,n.font="9px system-ui, sans-serif",n.textAlign="center",n.textBaseline="bottom",n.fillText(oe.type,Me,Ne-4)}}const Ft=performance.now()-v,Ie=Math.min(1,Ft/m),Ke=1-(1-Ie)*(1-Ie),Ze=Ie<1,cn=i.scale<u.hullsOnly,Vn=!cn&&i.scale<u.dotNodes;if(!cn)for(const Q of a.nodes){if(!Tt(Q.x,Q.y,i,o.clientWidth,o.clientHeight))continue;const Pe=Ae(Q.type);if(Vn){const Ne=F!==null&&!F.has(Q.id);n.fillStyle=Pe;const _e=Ne?.1:.8;n.globalAlpha=Ze?_e*Ke:_e,n.fillRect(Q.x-2,Q.y-2,4,4);continue}const Fe=x.has(Q.id),at=Ge!==null&&Ge.has(Q.id),ot=F!==null&&!F.has(Q.id),Ye=ot||x.size>0&&!Fe&&!at,Ve=i.scale<u.smallNodes?Ue*.5:Ue,Be=Ze?Ve*Ke:Ve;if(k!=null&&k.has(Q.id)){const Ne=p[p.length-1]===Q.id,_e=.5+.5*Math.sin(y),We=Ee("--accent")||"#d4a27f";n.save(),n.strokeStyle=We,n.lineWidth=Ne?3:2,n.globalAlpha=Ne?.5+.5*_e:.3+.4*_e,n.beginPath(),n.arc(Q.x,Q.y,Be+(Ne?6:4),0,Math.PI*2),n.stroke(),n.restore()}Fe&&(n.save(),n.shadowColor=Pe,n.shadowBlur=20,n.beginPath(),n.arc(Q.x,Q.y,Be+3,0,Math.PI*2),n.fillStyle=Pe,n.globalAlpha=.3,n.fill(),n.restore()),n.beginPath(),n.arc(Q.x,Q.y,Be,0,Math.PI*2),n.fillStyle=Pe;const Qe=ot?.1:Ye?.3:1;n.globalAlpha=Ze?Qe*Ke:Qe,n.fill(),n.strokeStyle=Fe?Re:ze,n.lineWidth=Fe?3:1.5,n.stroke(),n.globalAlpha=1,Q.pinned&&(n.save(),n.strokeStyle=ze,n.globalAlpha=.55,n.lineWidth=1,n.setLineDash([3,3]),n.beginPath(),n.arc(Q.x,Q.y,Be+4,0,Math.PI*2),n.stroke(),n.setLineDash([]),n.restore()),ge&&ge.nodeIds.has(Q.id)&&!Fe&&(n.save(),n.shadowColor=Ee("--accent")||"#d4a27f",n.shadowBlur=15,n.beginPath(),n.arc(Q.x,Q.y,Be+2,0,Math.PI*2),n.strokeStyle=Ee("--accent")||"#d4a27f",n.globalAlpha=.5,n.lineWidth=2,n.stroke(),n.restore());const oe=ee==null?void 0:ee.nodes.find(Ne=>Ne.id===Q.id);if(((ln=oe==null?void 0:oe.properties)==null?void 0:ln._starred)===!0&&(n.fillStyle="#ffd700",n.font="10px system-ui, sans-serif",n.textAlign="left",n.textBaseline="bottom",n.fillText("★",Q.x+Be-2,Q.y-Be+2)),i.scale>=u.hideLabels){const Ne=Q.label.length>24?Q.label.slice(0,22)+"...":Q.label,_e=Ye?ke:fe;An(n,Ne,Q.x,Q.y+Be+4,"11px system-ui, sans-serif",_e,"top")}if(i.scale>=u.hideBadges){const Ne=Ye?Te:Se;An(n,Q.type,Q.x,Q.y-Be-3,"9px system-ui, sans-serif",Ne,"bottom")}n.globalAlpha=1}if(n.restore(),n.restore(),f){const Q=o.width,Pe=o.height;(!B||B.width!==Q||B.height!==Pe)&&(B=new OffscreenCanvas(Q,Pe),$=B.getContext("2d")),$&&($.clearRect(0,0,Q,Pe),$.drawImage(o,0,0),te=!1),mt();return}X&&a.nodes.length>1&&E(),U&&(n.save(),n.setTransform(g,0,0,g,0,0),n.translate(-i.x*i.scale,-i.y*i.scale),n.scale(i.scale,i.scale),ut(),n.restore())}function E(){if(!a)return;const f=140,k=100,P=8,D=o.clientWidth-f-16,_=o.clientHeight-k-16;let j=1/0,O=1/0,J=-1/0,Z=-1/0;for(const Ie of a.nodes)Ie.x<j&&(j=Ie.x),Ie.y<O&&(O=Ie.y),Ie.x>J&&(J=Ie.x),Ie.y>Z&&(Z=Ie.y);const re=J-j||1,fe=Z-O||1,ke=Math.min((f-P*2)/re,(k-P*2)/fe),Se=D+P+(f-P*2-re*ke)/2,Te=_+P+(k-P*2-fe*ke)/2;n.save(),n.setTransform(g,0,0,g,0,0),n.fillStyle=Ee("--bg-surface")||"#1a1a1a",n.globalAlpha=.85,n.beginPath(),n.roundRect(D,_,f,k,8),n.fill(),n.strokeStyle=Ee("--border")||"#2a2a2a",n.globalAlpha=1,n.lineWidth=1,n.stroke(),n.globalAlpha=.15,n.strokeStyle=Ee("--canvas-edge")||"#555",n.lineWidth=.5;for(const Ie of a.edges){const Ke=a.nodeMap.get(Ie.sourceId),Ze=a.nodeMap.get(Ie.targetId);!Ke||!Ze||Ie.sourceId===Ie.targetId||(n.beginPath(),n.moveTo(Se+(Ke.x-j)*ke,Te+(Ke.y-O)*ke),n.lineTo(Se+(Ze.x-j)*ke,Te+(Ze.y-O)*ke),n.stroke())}n.globalAlpha=.8;for(const Ie of a.nodes){const Ke=Se+(Ie.x-j)*ke,Ze=Te+(Ie.y-O)*ke;n.beginPath(),n.arc(Ke,Ze,2,0,Math.PI*2),n.fillStyle=Ae(Ie.type),n.fill()}const Re=i.x,ze=i.y,Ge=i.x+o.clientWidth/i.scale,nt=i.y+o.clientHeight/i.scale,He=Se+(Re-j)*ke,it=Te+(ze-O)*ke,Nt=(Ge-Re)*ke,Ft=(nt-ze)*ke;n.globalAlpha=.3,n.strokeStyle=Ee("--accent")||"#d4a27f",n.lineWidth=1.5,n.strokeRect(Math.max(D,Math.min(He,D+f)),Math.max(_,Math.min(it,_+k)),Math.min(Nt,f),Math.min(Ft,k)),n.globalAlpha=1,n.restore()}function R(f,k,P,D,_,j,O){const J=Math.atan2(D-k,P-f),Z=P-Math.cos(J)*Ue,re=D-Math.sin(J)*Ue,fe=8;n.beginPath(),n.moveTo(Z,re),n.lineTo(Z-fe*Math.cos(J-.4),re-fe*Math.sin(J-.4)),n.lineTo(Z-fe*Math.cos(J+.4),re-fe*Math.sin(J+.4)),n.closePath(),n.fillStyle=_?O:j,n.fill()}function Y(f,k,P,D,_,j,O){const J=f.x+Ue+15,Z=f.y-Ue-15;n.beginPath(),n.arc(J,Z,15,0,Math.PI*2),n.strokeStyle=P?_:D,n.lineWidth=P?2.5:1.5,n.stroke(),V&&(n.fillStyle=P?O:j,n.font="9px system-ui, sans-serif",n.textAlign="center",n.fillText(k,J,Z-18))}function ne(){if(!le||!me)return;const f=performance.now()-me.time,k=Math.min(f/ve,1),P=1-Math.pow(1-k,3);i.x=me.x+(le.x-me.x)*P,i.y=me.y+(le.y-me.y)*P,ie(),c(),k<1?requestAnimationFrame(ne):(le=null,me=null)}let ae=0;function pe(){if(!be||p.length===0){ae=0;return}c(),ae=requestAnimationFrame(pe)}function he(){if(!a||a.nodes.length===0)return;let f=1/0,k=1/0,P=-1/0,D=-1/0;for(const re of a.nodes)re.x<f&&(f=re.x),re.y<k&&(k=re.y),re.x>P&&(P=re.x),re.y>D&&(D=re.y);const _=Ue*4,j=P-f+_*2,O=D-k+_*2,J=o.clientWidth/Math.max(j,1),Z=o.clientHeight/Math.max(O,1);i.scale=Math.min(J,Z,2),i.x=(f+P)/2-o.clientWidth/(2*i.scale),i.y=(k+D)/2-o.clientHeight/(2*i.scale),h()}function we(){if(!a||M<jt){T=0,be&&p.length>0&&!ae&&(ae=requestAnimationFrame(pe));return}M=So(a,M),b.rebuild(a.nodes),c(),T=requestAnimationFrame(we)}let Le=!1,De=0,tt=0,ht=0,kt=0;o.addEventListener("mousedown",f=>{H="pending",Le=!1,De=f.clientX,tt=f.clientY,ht=f.clientX,kt=f.clientY;const k=o.getBoundingClientRect(),P=f.clientX-k.left,D=f.clientY-k.top,_=Je(P,D);if(_&&!be){if(K=[],x.has(_.id)&&x.size>1)for(const J of x){const Z=a==null?void 0:a.nodeMap.get(J);Z&&K.push({node:Z,startX:Z.x,startY:Z.y})}else K.push({node:_,startX:_.x,startY:_.y});const[j,O]=Xe(P,D);q=j,ue=O}else if(!_&&f.shiftKey){const[j,O]=Xe(P,D);U={x1:j,y1:O,x2:j,y2:O}}}),o.addEventListener("mousemove",f=>{if(H==="idle")return;const k=f.clientX-De,P=f.clientY-tt,D=Math.abs(f.clientX-ht),_=Math.abs(f.clientY-kt);if(H==="pending"&&(D>xe||_>xe)&&(Le=!0,K.length>0?(H="nodeDrag",N&&w&&w.postMessage({type:"stop"})):U?H="rubberBand":H="pan"),H==="nodeDrag"){const j=o.getBoundingClientRect(),O=f.clientX-j.left,J=f.clientY-j.top,[Z,re]=Xe(O,J),fe=Z-q,ke=re-ue;for(const Se of K)Se.node.x=Se.startX+fe,Se.node.y=Se.startY+ke,Se.node.vx=0,Se.node.vy=0,Se.node.pinned=!0,de.add(Se.node.id);b.rebuild((a==null?void 0:a.nodes)??[]),h()}else if(H==="rubberBand"&&U){const j=o.getBoundingClientRect(),O=f.clientX-j.left,J=f.clientY-j.top,[Z,re]=Xe(O,J);U.x2=Z,U.y2=re,h()}else H==="pan"&&(i.x-=k/i.scale,i.y-=P/i.scale,h());De=f.clientX,tt=f.clientY}),o.addEventListener("mouseup",f=>{const k=H==="nodeDrag",P=H==="rubberBand";if(K.map(Z=>Z.node.id),k){if(N&&w&&a){const Z=K.map(re=>({id:re.node.id,x:re.node.x,y:re.node.y}));w.postMessage({type:"pin",updates:Z}),w.postMessage({type:"resume",alpha:.5})}else M=Math.max(M,.5),T||we();H="idle",K=[],h();return}if(P&&U&&a){const Z=Math.min(U.x1,U.x2),re=Math.max(U.x1,U.x2),fe=Math.min(U.y1,U.y2),ke=Math.max(U.y1,U.y2);f.shiftKey||x.clear();for(const Te of a.nodes)Te.x>=Z&&Te.x<=re&&Te.y>=fe&&Te.y<=ke&&x.add(Te.id);const Se=[...x];e==null||e(Se.length>0?Se:null),U=null,H="idle",h();return}if(H==="pan"){H="idle";return}if(H="idle",U=null,Le)return;const D=o.getBoundingClientRect(),_=f.clientX-D.left,j=f.clientY-D.top,O=Je(_,j),J=f.ctrlKey||f.metaKey||f.shiftKey;if(be&&G&&O&&a){const Z=p.length>0?p[p.length-1]:G[0],re=new Set([Z]),fe=[{id:Z,path:[Z]}];let ke=null;for(;fe.length>0;){const{id:ze,path:Ge}=fe.shift();if(ze===O.id){ke=Ge;break}for(const nt of a.edges){let He=null;nt.sourceId===ze?He=nt.targetId:nt.targetId===ze&&(He=nt.sourceId),He&&!re.has(He)&&(re.add(He),fe.push({id:He,path:[...Ge,He]}))}}if(!ke)return;for(const ze of ke.slice(1))p.includes(ze)||p.push(ze);G=[O.id];const Se=Math.max(1,ye);ye=Se;const Te=Ln(ee,[O.id],Se);cancelAnimationFrame(T),w&&w.postMessage({type:"stop"}),a=Ut(Te),b.rebuild(a.nodes),M=1,x=new Set([O.id]),F=null,i={x:0,y:0,scale:1},N=Te.nodes.length>=S;const Re=N?I():null;Re?Re.postMessage({type:"start",data:Te}):(N=!1,we()),setTimeout(()=>{a&&he()},300),s==null||s({seedNodeIds:[O.id],hops:Se,totalNodes:Te.nodes.length}),e==null||e([O.id]);return}if(O){J?x.has(O.id)?x.delete(O.id):x.add(O.id):x.size===1&&x.has(O.id)?x.clear():(x.clear(),x.add(O.id));const Z=[...x];e==null||e(Z.length>0?Z:null)}else x.clear(),e==null||e(null);h()}),o.addEventListener("mouseleave",()=>{if(H==="nodeDrag")if(N&&w&&K.length>0){const f=K.map(k=>({id:k.node.id,x:k.node.x,y:k.node.y}));w.postMessage({type:"pin",updates:f}),w.postMessage({type:"resume",alpha:.5})}else M=Math.max(M,.5),T||we();H==="rubberBand"&&(U=null,h()),H="idle",K=[]}),o.addEventListener("wheel",f=>{f.preventDefault();const k=o.getBoundingClientRect(),P=f.clientX-k.left,D=f.clientY-k.top,[_,j]=Xe(P,D),O=f.ctrlKey?1-f.deltaY*.01:f.deltaY>0?.9:1.1;i.scale=Math.max(r.zoomMin,Math.min(r.zoomMax,i.scale*O)),i.x=_-P/i.scale,i.y=j-D/i.scale,h()},{passive:!1});let Oe=[],tn=0,nn=1,on=0,sn=0,$t=!1;o.addEventListener("touchstart",f=>{f.preventDefault(),Oe=Array.from(f.touches),Oe.length===2?(tn=an(Oe[0],Oe[1]),nn=i.scale):Oe.length===1&&(De=Oe[0].clientX,tt=Oe[0].clientY,on=Oe[0].clientX,sn=Oe[0].clientY,$t=!1)},{passive:!1}),o.addEventListener("touchmove",f=>{f.preventDefault();const k=Array.from(f.touches);if(k.length===2&&Oe.length===2){const D=an(k[0],k[1])/tn;i.scale=Math.max(r.zoomMin,Math.min(r.zoomMax,nn*D)),h()}else if(k.length===1){const P=k[0].clientX-De,D=k[0].clientY-tt;(Math.abs(k[0].clientX-on)>10||Math.abs(k[0].clientY-sn)>10)&&($t=!0),i.x-=P/i.scale,i.y-=D/i.scale,De=k[0].clientX,tt=k[0].clientY,h()}Oe=k},{passive:!1}),o.addEventListener("touchend",f=>{if(f.preventDefault(),$t||f.changedTouches.length!==1)return;const k=f.changedTouches[0],P=o.getBoundingClientRect(),D=k.clientX-P.left,_=k.clientY-P.top,j=Je(D,_);if(j){x.size===1&&x.has(j.id)?x.clear():(x.clear(),x.add(j.id));const O=[...x];e==null||e(O.length>0?O:null)}else x.clear(),e==null||e(null);h()},{passive:!1}),o.addEventListener("gesturestart",f=>f.preventDefault()),o.addEventListener("gesturechange",f=>f.preventDefault());function an(f,k){const P=f.clientX-k.clientX,D=f.clientY-k.clientY;return Math.sqrt(P*P+D*D)}const ft=document.createElement("div");ft.className="zoom-controls";const gt=document.createElement("button");gt.className="zoom-btn",gt.textContent="+",gt.title="Zoom in",gt.addEventListener("click",()=>{const f=o.clientWidth/2,k=o.clientHeight/2,[P,D]=Xe(f,k);i.scale=Math.min(r.zoomMax,i.scale*r.zoomFactor),i.x=P-f/i.scale,i.y=D-k/i.scale,h()});const yt=document.createElement("button");yt.className="zoom-btn",yt.textContent="−",yt.title="Zoom out",yt.addEventListener("click",()=>{const f=o.clientWidth/2,k=o.clientHeight/2,[P,D]=Xe(f,k);i.scale=Math.max(r.zoomMin,i.scale/r.zoomFactor),i.x=P-f/i.scale,i.y=D-k/i.scale,h()});const Ct=document.createElement("button");Ct.className="zoom-btn",Ct.textContent="○",Ct.title="Reset zoom",Ct.addEventListener("click",()=>{if(a){if(i={x:0,y:0,scale:1},a.nodes.length>0){let f=1/0,k=1/0,P=-1/0,D=-1/0;for(const O of a.nodes)O.x<f&&(f=O.x),O.y<k&&(k=O.y),O.x>P&&(P=O.x),O.y>D&&(D=O.y);const _=(f+P)/2,j=(k+D)/2;i.x=_-o.clientWidth/2,i.y=j-o.clientHeight/2}h()}}),ft.appendChild(gt),ft.appendChild(Ct),ft.appendChild(yt),t.appendChild(ft);const $e=document.createElement("div");$e.className="node-tooltip",$e.style.display="none",t.appendChild($e);let St=null,st=null;return o.addEventListener("mousemove",f=>{if(H!=="idle"&&H!=="pending"){$e.style.display!=="none"&&($e.style.display="none",St=null);return}const k=o.getBoundingClientRect(),P=f.clientX-k.left,D=f.clientY-k.top,_=Je(P,D),j=(_==null?void 0:_.id)??null;j!==St?(St=j,$e.style.display="none",st&&clearTimeout(st),st=null,j&&_&&(st=setTimeout(()=>{if(!a||!ee)return;const O=a.edges.filter(J=>J.sourceId===j||J.targetId===j).length;$e.textContent=`${_.label} · ${_.type} · ${O} edge${O!==1?"s":""}`,$e.style.left=`${f.clientX-k.left+12}px`,$e.style.top=`${f.clientY-k.top-8}px`,$e.style.display="block"},200))):j&&$e.style.display==="block"&&($e.style.left=`${f.clientX-k.left+12}px`,$e.style.top=`${f.clientY-k.top-8}px`)}),o.addEventListener("mouseleave",()=>{$e.style.display="none",St=null,st&&clearTimeout(st),st=null}),{loadGraph(f){if(cancelAnimationFrame(T),w&&w.postMessage({type:"stop"}),Ao(),ee=f,G=null,Ce=null,se=null,v=performance.now(),a=Ut(f),b.rebuild(a.nodes),M=1,x=new Set,F=null,de.clear(),H="idle",K=[],U=null,i={x:0,y:0,scale:1},a.nodes.length>0){let P=1/0,D=1/0,_=-1/0,j=-1/0;for(const fe of a.nodes)fe.x<P&&(P=fe.x),fe.y<D&&(D=fe.y),fe.x>_&&(_=fe.x),fe.y>j&&(j=fe.y);const O=(P+_)/2,J=(D+j)/2,Z=o.clientWidth,re=o.clientHeight;i.x=O-Z/2,i.y=J-re/2}N=f.nodes.length>=S;const k=N?I():null;k?k.postMessage({type:"start",data:f}):(N=!1,we())},setFilteredNodeIds(f){F=f,h()},releaseAllPins(){if(!a)return!1;let f=!1;for(const k of a.nodes)k.pinned&&(f=!0,k.pinned=!1);return de.clear(),H="idle",K=[],U=null,f&&(N&&w?w.postMessage({type:"unpin",ids:"all"}):(M=Math.max(M,.5),T||we()),h()),f},hasPinnedNodes(){if(!a)return!1;for(const f of a.nodes)if(f.pinned)return!0;return!1},clearSelection(){x.size!==0&&(x.clear(),e==null||e(null),h())},getSelectedNodeIds(){return[...x]},panToNode(f){this.panToNodes([f])},panToNodes(f){if(!a||f.length===0)return;const k=f.map(_=>a.nodeMap.get(_)).filter(Boolean);if(k.length===0)return;x=new Set(f),e==null||e(f);const P=o.clientWidth,D=o.clientHeight;if(k.length===1)me={x:i.x,y:i.y,time:performance.now()},le={x:k[0].x-P/(2*i.scale),y:k[0].y-D/(2*i.scale)};else{let _=1/0,j=1/0,O=-1/0,J=-1/0;for(const Re of k)Re.x<_&&(_=Re.x),Re.y<j&&(j=Re.y),Re.x>O&&(O=Re.x),Re.y>J&&(J=Re.y);const Z=Ue*4,re=O-_+Z*2,fe=J-j+Z*2,ke=Math.min(P/re,D/fe,i.scale);i.scale=ke;const Se=(_+O)/2,Te=(j+J)/2;me={x:i.x,y:i.y,time:performance.now()},le={x:Se-P/(2*i.scale),y:Te-D/(2*i.scale)}}ne()},setEdges(f){W=f,h()},setEdgeLabels(f){V=f,h()},setTypeHulls(f){z=f,h()},setMinimap(f){X=f,h()},centerView(){he()},panBy(f,k){i.x+=f/i.scale,i.y+=k/i.scale,h()},zoomBy(f){const k=o.clientWidth/2,P=o.clientHeight/2,[D,_]=Xe(k,P);i.scale=Math.max(r.zoomMin,Math.min(r.zoomMax,i.scale*f)),i.x=D-k/i.scale,i.y=_-P/i.scale,h()},reheat(){N&&w?w.postMessage({type:"params",params:Et()}):(M=.5,cancelAnimationFrame(T),we())},exportImage(f){if(!a)return"";const k=o.width,P=o.height;if(f==="png"){const O=document.createElement("canvas");O.width=k,O.height=P;const J=O.getContext("2d");return J.fillStyle=Ee("--bg")||"#141414",J.fillRect(0,0,k,P),J.drawImage(o,0,0),Gn(J,k,P),O.toDataURL("image/png")}const D=o.toDataURL("image/png"),_=Math.max(16,Math.round(k/80)),j=`<svg xmlns="http://www.w3.org/2000/svg" width="${k}" height="${P}">
3
- <image href="${D}" width="${k}" height="${P}"/>
4
- <text x="${k-20}" y="${P-16}" text-anchor="end" font-family="system-ui, sans-serif" font-size="${_}" fill="#ffffff" opacity="0.4">backpackontology.com</text>
5
- </svg>`;return"data:image/svg+xml;charset=utf-8,"+encodeURIComponent(j)},enterFocus(f,k){if(!ee||!a)return;for(const _ of a.nodes)_.pinned=!1;de.clear(),H="idle",K=[],U=null,G||(Ce=a,se={...i}),G=f,ye=k;const P=Ln(ee,f,k);cancelAnimationFrame(T),w&&w.postMessage({type:"stop"}),a=Ut(P),b.rebuild(a.nodes),M=1,x=new Set(f),F=null,i={x:0,y:0,scale:1},N=P.nodes.length>=S;const D=N?I():null;D?D.postMessage({type:"start",data:P}):(N=!1,we()),setTimeout(()=>{!a||!G||he()},300),s==null||s({seedNodeIds:f,hops:k,totalNodes:P.nodes.length})},exitFocus(){if(!(!G||!Ce)){cancelAnimationFrame(T),w&&w.postMessage({type:"stop"}),a=Ce;for(const f of a.nodes)f.pinned=!1;de.clear(),H="idle",K=[],U=null,b.rebuild(a.nodes),i=se??{x:0,y:0,scale:1},G=null,Ce=null,se=null,x=new Set,F=null,h(),s==null||s(null)}},isFocused(){return G!==null},getFocusInfo(){return!G||!a?null:{seedNodeIds:G,hops:ye,totalNodes:a.nodes.length}},findPath(f,k){if(!a)return null;const P=new Set([f]),D=[{nodeId:f,path:[f],edges:[]}];for(;D.length>0;){const{nodeId:_,path:j,edges:O}=D.shift();if(_===k)return{nodeIds:j,edgeIds:O};for(const J of a.edges){let Z=null;if(J.sourceId===_?Z=J.targetId:J.targetId===_&&(Z=J.sourceId),Z&&!P.has(Z)){P.add(Z);const re=ee==null?void 0:ee.edges.find(fe=>fe.sourceId===J.sourceId&&fe.targetId===J.targetId||fe.targetId===J.sourceId&&fe.sourceId===J.targetId);D.push({nodeId:Z,path:[...j,Z],edges:[...O,(re==null?void 0:re.id)??""]})}}}return null},setHighlightedPath(f,k){f&&k?ge={nodeIds:new Set(f),edgeIds:new Set(k)}:ge=null,h()},clearHighlightedPath(){ge=null,h()},setWalkMode(f){be=f,this.releaseAllPins(),f?(p=G?[...G]:[...x],ae||(ae=requestAnimationFrame(pe))):(p=[],ae&&(cancelAnimationFrame(ae),ae=0)),h()},getWalkMode(){return be},getWalkTrail(){return[...p]},getFilteredNodeIds(){return F},removeFromWalkTrail(f){p=p.filter(k=>k!==f),h()},nodeAtScreen(f,k){return Je(f,k)},getNodeIds(){if(!a)return[];if(G){const f=new Set(G),k=a.nodes.filter(D=>f.has(D.id)).map(D=>D.id),P=a.nodes.filter(D=>!f.has(D.id)).map(D=>D.id);return[...k,...P]}return a.nodes.map(f=>f.id)},destroy(){cancelAnimationFrame(T),L&&(cancelAnimationFrame(L),L=0),ae&&(cancelAnimationFrame(ae),ae=0),w&&(w.terminate(),w=null),B=null,$=null,qe.disconnect()}};function Gn(f,k,P){const D=Math.max(16,Math.round(k/80));f.save(),f.font=`${D}px system-ui, sans-serif`,f.fillStyle="rgba(255, 255, 255, 0.4)",f.textAlign="right",f.textBaseline="bottom",f.fillText("backpackontology.com",k-20,P-16),f.restore()}}function rt(t){for(const e of Object.values(t.properties))if(typeof e=="string")return e;return t.id}const $o="✎";function Fo(t,e,s,l,u){const r=document.createElement("div");r.className="info-panel-content";let d=[],o=-1,n=!1,g=null,i=[],a=!1,M=[],T=-1;const x=e.mount("info",r,{title:"Node info",persistKey:"info-panel",hideOnClose:!0,onClose:()=>{d=[],o=-1}});x.setVisible(!1);function F(){x.setVisible(!1),d=[],o=-1}function W(q){!g||!l||(o<d.length-1&&(d=d.slice(0,o+1)),d.push(q),o=d.length-1,n=!0,l(q),n=!1)}function V(){if(o<=0||!g)return;o--,n=!0;const q=d[o];l==null||l(q),H(q,g),n=!1}function z(){if(o>=d.length-1||!g)return;o++,n=!0;const q=d[o];l==null||l(q),H(q,g),n=!1}function X(){const q=[{label:"Back",iconText:"←",onClick:V,disabled:o<=0},{label:"Forward",iconText:"→",onClick:z,disabled:o>=d.length-1}];u&&i.length>0&&q.push({label:"Focus",iconText:"◎",onClick:()=>{a||u(i)},disabled:a}),x.setHeaderButtons(q)}function H(q,ue){const U=ue.nodes.find(h=>h.id===q);if(!U)return;const de=ue.edges.filter(h=>h.sourceId===q||h.targetId===q);M=de.map(h=>h.sourceId===q?h.targetId:h.sourceId),T=-1,r.replaceChildren(),x.setTitle(rt(U)),X(),x.setVisible(!0);const xe=document.createElement("div");xe.className="info-panel-header";const ee=document.createElement("div");ee.className="info-header";const G=document.createElement("span");if(G.className="info-type-badge",G.textContent=U.type,G.style.backgroundColor=Ae(U.type),s){G.classList.add("info-editable");const h=document.createElement("button");h.className="info-inline-edit",h.textContent=$o,h.addEventListener("click",S=>{S.stopPropagation();const w=document.createElement("input");w.type="text",w.className="info-edit-inline-input",w.value=U.type,G.textContent="",G.appendChild(w),w.focus(),w.select();const N=()=>{const I=w.value.trim();I&&I!==U.type?s.onChangeNodeType(q,I):(G.textContent=U.type,G.appendChild(h))};w.addEventListener("blur",N),w.addEventListener("keydown",I=>{I.key==="Enter"&&w.blur(),I.key==="Escape"&&(w.value=U.type,w.blur())})}),G.appendChild(h)}const ye=document.createElement("h3");ye.className="info-label",ye.textContent=rt(U);const Ce=document.createElement("span");Ce.className="info-id",Ce.textContent=U.id,ee.appendChild(G),ee.appendChild(ye),ee.appendChild(Ce),xe.appendChild(ee),r.appendChild(xe);const se=document.createElement("div");se.className="info-panel-body";const ge=Object.keys(U.properties),be=xt("Properties");if(ge.length>0){const h=document.createElement("dl");h.className="info-props";for(const S of ge){const w=document.createElement("dt");w.textContent=S;const N=document.createElement("dd");if(s){const I=zt(U.properties[S]),C=document.createElement("textarea");C.className="info-edit-input",C.value=I,C.rows=1,C.addEventListener("input",()=>Pn(C)),C.addEventListener("keydown",$=>{$.key==="Enter"&&!$.shiftKey&&($.preventDefault(),C.blur())}),C.addEventListener("blur",()=>{const $=C.value;$!==I&&s.onUpdateNode(q,{[S]:Oo($)})}),N.appendChild(C),requestAnimationFrame(()=>Pn(C));const B=document.createElement("button");B.className="info-delete-prop",B.textContent="×",B.title=`Remove ${S}`,B.addEventListener("click",()=>{const $={...U.properties};delete $[S],s.onUpdateNode(q,$)}),N.appendChild(B)}else N.appendChild(Do(U.properties[S]));h.appendChild(w),h.appendChild(N)}be.appendChild(h)}if(s){const h=document.createElement("button");h.className="info-add-btn",h.textContent="+ Add property",h.addEventListener("click",()=>{const S=document.createElement("div");S.className="info-add-row";const w=document.createElement("input");w.type="text",w.className="info-edit-input",w.placeholder="key";const N=document.createElement("input");N.type="text",N.className="info-edit-input",N.placeholder="value";const I=document.createElement("button");I.className="info-add-save",I.textContent="Add",I.addEventListener("click",()=>{w.value&&s.onAddProperty(q,w.value,N.value)}),S.appendChild(w),S.appendChild(N),S.appendChild(I),be.appendChild(S),w.focus()}),be.appendChild(h)}if(se.appendChild(be),de.length>0){const h=xt(`Connections (${de.length})`),S=document.createElement("ul");S.className="info-connections";for(const w of de){const N=w.sourceId===q,I=N?w.targetId:w.sourceId,C=ue.nodes.find(ve=>ve.id===I),B=C?rt(C):I,$=document.createElement("li");if($.className="info-connection",l&&C&&($.classList.add("info-connection-link"),$.addEventListener("click",ve=>{ve.target.closest(".info-delete-edge")||W(I)})),C){const ve=document.createElement("span");ve.className="info-target-dot",ve.style.backgroundColor=Ae(C.type),$.appendChild(ve)}const te=document.createElement("span");te.className="info-arrow",te.textContent=N?"→":"←";const ie=document.createElement("span");ie.className="info-edge-type",ie.textContent=w.type;const le=document.createElement("span");le.className="info-target",le.textContent=B,$.appendChild(te),$.appendChild(ie),$.appendChild(le);const me=Object.keys(w.properties);if(me.length>0){const ve=document.createElement("div");ve.className="info-edge-props";for(const je of me){const qe=document.createElement("span");qe.className="info-edge-prop",qe.textContent=`${je}: ${zt(w.properties[je])}`,ve.appendChild(qe)}$.appendChild(ve)}if(s){const ve=document.createElement("button");ve.className="info-delete-edge",ve.textContent="×",ve.title="Remove connection",ve.addEventListener("click",je=>{je.stopPropagation(),s.onDeleteEdge(w.id)}),$.appendChild(ve)}S.appendChild($)}h.appendChild(S),se.appendChild(h)}const p=xt("Timestamps"),y=document.createElement("dl");y.className="info-props";const v=document.createElement("dt");v.textContent="created";const m=document.createElement("dd");m.textContent=Rn(U.createdAt);const b=document.createElement("dt");b.textContent="updated";const L=document.createElement("dd");if(L.textContent=Rn(U.updatedAt),y.appendChild(v),y.appendChild(m),y.appendChild(b),y.appendChild(L),p.appendChild(y),se.appendChild(p),s){const h=document.createElement("div");h.className="info-section info-danger";const S=document.createElement("button");S.className="info-delete-node",S.textContent="Delete node",S.addEventListener("click",()=>{s.onDeleteNode(q),F()}),h.appendChild(S),se.appendChild(h)}r.appendChild(se)}function K(q,ue){const U=new Set(q),de=ue.nodes.filter(p=>U.has(p.id));if(de.length===0)return;const xe=ue.edges.filter(p=>U.has(p.sourceId)&&U.has(p.targetId));r.replaceChildren(),x.setTitle(`${de.length} nodes selected`),X(),x.setVisible(!0);const ee=document.createElement("div");ee.className="info-header";const G=document.createElement("h3");G.className="info-label",G.textContent=`${de.length} nodes selected`,ee.appendChild(G);const ye=document.createElement("div");ye.className="info-badge-row";const Ce=new Map;for(const p of de)Ce.set(p.type,(Ce.get(p.type)??0)+1);for(const[p,y]of Ce){const v=document.createElement("span");v.className="info-type-badge",v.style.backgroundColor=Ae(p),v.textContent=y>1?`${p} (${y})`:p,ye.appendChild(v)}ee.appendChild(ye),r.appendChild(ee);const se=xt("Selected Nodes"),ge=document.createElement("ul");ge.className="info-connections";for(const p of de){const y=document.createElement("li");y.className="info-connection",l&&(y.classList.add("info-connection-link"),y.addEventListener("click",()=>{W(p.id)}));const v=document.createElement("span");v.className="info-target-dot",v.style.backgroundColor=Ae(p.type);const m=document.createElement("span");m.className="info-target",m.textContent=rt(p);const b=document.createElement("span");b.className="info-edge-type",b.textContent=p.type,y.appendChild(v),y.appendChild(m),y.appendChild(b),ge.appendChild(y)}se.appendChild(ge),r.appendChild(se);const be=xt(xe.length>0?`Connections Between Selected (${xe.length})`:"Connections Between Selected");if(xe.length===0){const p=document.createElement("p");p.className="info-empty-message",p.textContent="No direct connections between selected nodes",be.appendChild(p)}else{const p=document.createElement("ul");p.className="info-connections";for(const y of xe){const v=ue.nodes.find($=>$.id===y.sourceId),m=ue.nodes.find($=>$.id===y.targetId),b=v?rt(v):y.sourceId,L=m?rt(m):y.targetId,h=document.createElement("li");if(h.className="info-connection",v){const $=document.createElement("span");$.className="info-target-dot",$.style.backgroundColor=Ae(v.type),h.appendChild($)}const S=document.createElement("span");S.className="info-target",S.textContent=b;const w=document.createElement("span");w.className="info-arrow",w.textContent="→";const N=document.createElement("span");N.className="info-edge-type",N.textContent=y.type;const I=document.createElement("span");if(I.className="info-arrow",I.textContent="→",h.appendChild(S),h.appendChild(w),h.appendChild(N),h.appendChild(I),m){const $=document.createElement("span");$.className="info-target-dot",$.style.backgroundColor=Ae(m.type),h.appendChild($)}const C=document.createElement("span");C.className="info-target",C.textContent=L,h.appendChild(C);const B=Object.keys(y.properties);if(B.length>0){const $=document.createElement("div");$.className="info-edge-props";for(const te of B){const ie=document.createElement("span");ie.className="info-edge-prop",ie.textContent=`${te}: ${zt(y.properties[te])}`,$.appendChild(ie)}h.appendChild($)}p.appendChild(h)}be.appendChild(p)}r.appendChild(be)}return{show(q,ue){if(g=ue,i=q,q.length===1&&!n){const U=q[0];d[o]!==U&&(o<d.length-1&&(d=d.slice(0,o+1)),d.push(U),o=d.length-1)}q.length===1?H(q[0],ue):q.length>1&&K(q,ue)},hide:F,goBack:V,goForward:z,cycleConnection(q){if(M.length===0)return null;T===-1?T=q===1?0:M.length-1:(T+=q,T>=M.length&&(T=0),T<0&&(T=M.length-1));const ue=r.querySelectorAll(".info-connection");return ue.forEach((U,de)=>{U.classList.toggle("info-connection-active",de===T)}),T>=0&&ue[T]&&ue[T].scrollIntoView({block:"nearest"}),M[T]??null},setFocusDisabled(q){a=q,X()},get visible(){return x.isVisible()}}}function xt(t){const e=document.createElement("div");e.className="info-section";const s=document.createElement("h4");return s.className="info-section-title",s.textContent=t,e.appendChild(s),e}function Do(t){if(Array.isArray(t)){const s=document.createElement("div");s.className="info-array";for(const l of t){const u=document.createElement("span");u.className="info-tag",u.textContent=String(l),s.appendChild(u)}return s}if(t!==null&&typeof t=="object"){const s=document.createElement("pre");return s.className="info-json",s.textContent=JSON.stringify(t,null,2),s}const e=document.createElement("span");return e.className="info-value",e.textContent=String(t??""),e}function zt(t){return Array.isArray(t)?t.map(String).join(", "):t!==null&&typeof t=="object"?JSON.stringify(t):String(t??"")}function Oo(t){const e=t.trim();if(e==="true")return!0;if(e==="false")return!1;if(e!==""&&!isNaN(Number(e)))return Number(e);if(e.startsWith("[")&&e.endsWith("]")||e.startsWith("{")&&e.endsWith("}"))try{return JSON.parse(e)}catch{return t}return t}function Pn(t){t.style.height="auto",t.style.height=t.scrollHeight+"px"}function Rn(t){try{return new Date(t).toLocaleString()}catch{return t}}const Jt=30,Wo=39,Uo=45,Bn=380,jo=70,zo=16,$n=80,qn="backpack-viewer:panel:",_o="has-fullscreen-panel";let At=Jt;function dt(t){At++,At>Wo&&(document.querySelectorAll(".extension-panel").forEach(e=>{e.style.zIndex=String(Jt+1)}),At=Jt+2),t.style.zIndex=String(At)}let Pt=0;function Rt(t,e){const s=t.id==="canvas-container"?t:t.closest("#canvas-container")??t;e?Pt++:Pt=Math.max(0,Pt-1),s.classList.toggle(_o,Pt>0)}function _t(t){try{const e=localStorage.getItem(qn+t);if(!e)return null;const s=JSON.parse(e);if(s&&typeof s=="object")return s}catch{}return null}function Fn(t,e){try{localStorage.setItem(qn+t,JSON.stringify(e))}catch{}}function Dn(){return ct({size:13,strokeWidth:1.8,strokeLinecap:"round",strokeLinejoin:"round"},[{tag:"polyline",attrs:{points:"4 9 4 4 9 4"}},{tag:"polyline",attrs:{points:"20 9 20 4 15 4"}},{tag:"polyline",attrs:{points:"4 15 4 20 9 20"}},{tag:"polyline",attrs:{points:"20 15 20 20 15 20"}}])}function Ho(){return ct({size:13,strokeWidth:1.8,strokeLinecap:"round",strokeLinejoin:"round"},[{tag:"polyline",attrs:{points:"9 4 9 9 4 9"}},{tag:"polyline",attrs:{points:"15 4 15 9 20 9"}},{tag:"polyline",attrs:{points:"9 20 9 15 4 15"}},{tag:"polyline",attrs:{points:"15 20 15 15 20 15"}}])}function Yo(t){const e=document.createElement("div");e.className="extension-panel-layer",t.appendChild(e);function s(){const r=t.getBoundingClientRect();return{left:Math.max(0,r.width-Bn-zo),top:jo}}function l(r,d){const o=t.getBoundingClientRect(),n=$n-d.width,g=o.width-$n,i=0,a=o.height-40;return{left:Math.max(n,Math.min(g,r.left)),top:Math.max(i,Math.min(a,r.top))}}function u(r,d,o={}){const n=o.persistKey??r,g=_t(n),i=document.createElement("aside");i.className="extension-panel",i.dataset.panel=n;const a=document.createElement("div");a.className="extension-panel-header";const M=document.createElement("span");M.className="extension-panel-title",M.textContent=o.title??r,a.appendChild(M);const T=document.createElement("div");T.className="extension-panel-custom-btns",a.appendChild(T);function x(m){T.replaceChildren();for(const b of m){const L=document.createElement("button");L.className="extension-panel-btn",L.title=b.label,L.setAttribute("aria-label",b.label),L.textContent=b.iconText??b.label,b.disabled&&(L.disabled=!0),L.addEventListener("click",h=>{h.stopPropagation();try{b.onClick()}catch(S){console.error(`[backpack-viewer] panel header button "${b.label}" threw:`,S)}}),L.addEventListener("mousedown",h=>h.stopPropagation()),T.appendChild(L)}}x(o.headerButtons??[]);let F=!1,W=null,V=null;o.showFullscreenButton!==!1&&(W=document.createElement("button"),W.className="extension-panel-btn extension-panel-btn-fullscreen",W.title="Toggle fullscreen",W.setAttribute("aria-label","Toggle fullscreen"),V=Dn(),W.appendChild(V),W.addEventListener("click",m=>{m.stopPropagation(),p(!F)}),W.addEventListener("mousedown",m=>m.stopPropagation()),a.appendChild(W));let z=null;o.showCloseButton!==!1&&(z=document.createElement("button"),z.className="extension-panel-btn extension-panel-btn-close",z.title="Close panel",z.setAttribute("aria-label","Close panel"),z.textContent="×",z.addEventListener("click",m=>{var b;if(m.stopPropagation(),o.hideOnClose){be(!1);try{(b=o.onClose)==null||b.call(o)}catch(L){console.error("[backpack-viewer] panel onClose threw:",L)}}else ge()}),z.addEventListener("mousedown",m=>m.stopPropagation()),a.appendChild(z)),i.appendChild(a);const X=document.createElement("div");X.className="extension-panel-body",X.appendChild(d),i.appendChild(X),e.appendChild(i);const H=g&&g.left!=null&&g.top!=null?{left:g.left,top:g.top}:o.defaultPosition??s(),q=l(H,{width:Bn});i.style.left=q.left+"px",i.style.top=q.top+"px",dt(i);let ue=0,U=0,de=0,xe=0,ee=!1;function G(m){if(!ee)return;const b=m.clientX-ue,L=m.clientY-U,h=l({left:de+b,top:xe+L},i.getBoundingClientRect());i.style.left=h.left+"px",i.style.top=h.top+"px"}function ye(){if(!ee)return;ee=!1,document.removeEventListener("mousemove",G),document.removeEventListener("mouseup",ye);const m=i.getBoundingClientRect(),b=t.getBoundingClientRect();Fn(n,{..._t(n),left:m.left-b.left,top:m.top-b.top})}a.addEventListener("mousedown",m=>{if(F)return;ee=!0,ue=m.clientX,U=m.clientY;const b=i.getBoundingClientRect(),L=t.getBoundingClientRect();de=b.left-L.left,xe=b.top-L.top,dt(i),document.addEventListener("mousemove",G),document.addEventListener("mouseup",ye),m.preventDefault()}),i.addEventListener("mousedown",()=>{F||dt(i)},{capture:!0});let Ce=!1,se=!0;function ge(){var m;if(!Ce){Ce=!0,document.removeEventListener("mousemove",G),document.removeEventListener("mouseup",ye),F&&(Rt(t,!1),F=!1),i.remove();try{(m=o.onClose)==null||m.call(o)}catch(b){console.error("[backpack-viewer] panel onClose threw:",b)}}}function be(m){m!==se&&(se=m,i.classList.toggle("is-hidden",!se),se?(dt(i),F&&Rt(t,!0)):F&&Rt(t,!1))}function p(m){var b;if(m!==F){F=m,i.classList.toggle("is-fullscreen",F),W&&V&&(V.remove(),V=F?Ho():Dn(),W.appendChild(V)),F?i.style.zIndex=String(Uo):dt(i),Rt(t,F),Fn(n,{..._t(n),fullscreen:F});try{(b=o.onFullscreenChange)==null||b.call(o,F)}catch(L){console.error("[backpack-viewer] panel onFullscreenChange threw:",L)}}}g!=null&&g.fullscreen&&p(!0);function y(m){M.textContent=m}function v(m){x(m)}return{close:ge,setFullscreen:p,isFullscreen:()=>F,setTitle:y,setHeaderButtons:v,setVisible:be,isVisible:()=>se,bringToFront:()=>dt(i),element:d}}return{mount:u}}function Xn(t){for(const e of Object.values(t.properties))if(typeof e=="string")return e;return t.id}function On(t,e){const s=e.toLowerCase();if(Xn(t).toLowerCase().includes(s)||t.type.toLowerCase().includes(s))return!0;for(const l of Object.values(t.properties))if(typeof l=="string"&&l.toLowerCase().includes(s))return!0;return!1}function qo(t,e){const s=(e==null?void 0:e.maxResults)??8,l=(e==null?void 0:e.debounceMs)??150;let u=null,r=null,d=null,o=null;const n=document.createElement("div");n.className="search-overlay hidden";const g=document.createElement("div");g.className="search-input-wrap";const i=document.createElement("input");i.className="search-input",i.type="text",i.placeholder="Search nodes...",i.setAttribute("autocomplete","off"),i.setAttribute("spellcheck","false");const a=document.createElement("kbd");a.className="search-kbd",a.textContent="/",g.appendChild(i),g.appendChild(a);const M=document.createElement("ul");M.className="search-results hidden",n.appendChild(g),n.appendChild(M),t.appendChild(n);function T(){if(!u)return null;const z=i.value.trim();if(z.length===0)return null;const X=new Set;for(const H of u.nodes)On(H,z)&&X.add(H.id);return X}function x(){const z=T();r==null||r(z),F()}function F(){M.replaceChildren(),W=-1;const z=i.value.trim();if(!u||z.length===0){M.classList.add("hidden");return}const X=[];for(const H of u.nodes)if(On(H,z)&&(X.push(H),X.length>=s))break;if(X.length===0){M.classList.add("hidden");return}for(const H of X){const K=document.createElement("li");K.className="search-result-item";const q=document.createElement("span");q.className="search-result-dot",q.style.backgroundColor=Ae(H.type);const ue=document.createElement("span");ue.className="search-result-label";const U=Xn(H);ue.textContent=U.length>36?U.slice(0,34)+"...":U;const de=document.createElement("span");de.className="search-result-type",de.textContent=H.type,K.appendChild(q),K.appendChild(ue),K.appendChild(de),K.addEventListener("click",()=>{d==null||d(H.id),i.value="",M.classList.add("hidden"),x()}),M.appendChild(K)}M.classList.remove("hidden")}i.addEventListener("input",()=>{o&&clearTimeout(o),o=setTimeout(x,l)});let W=-1;function V(){const z=M.querySelectorAll(".search-result-item");z.forEach((X,H)=>{X.classList.toggle("search-result-active",H===W)}),W>=0&&z[W]&&z[W].scrollIntoView({block:"nearest"})}return i.addEventListener("keydown",z=>{const X=M.querySelectorAll(".search-result-item");z.key==="ArrowDown"?(z.preventDefault(),X.length>0&&(W=Math.min(W+1,X.length-1),V())):z.key==="ArrowUp"?(z.preventDefault(),X.length>0&&(W=Math.max(W-1,0),V())):z.key==="Enter"?(z.preventDefault(),W>=0&&X[W]?X[W].click():X.length>0&&X[0].click(),i.blur()):z.key==="Escape"&&(i.value="",i.blur(),M.classList.add("hidden"),W=-1,x())}),document.addEventListener("click",z=>{n.contains(z.target)||M.classList.add("hidden")}),i.addEventListener("focus",()=>a.classList.add("hidden")),i.addEventListener("blur",()=>{i.value.length===0&&a.classList.remove("hidden")}),{setLearningGraphData(z){u=z,i.value="",M.classList.add("hidden"),u&&u.nodes.length>0?n.classList.remove("hidden"):n.classList.add("hidden")},onFilterChange(z){r=z},onNodeSelect(z){d=z},clear(){i.value="",M.classList.add("hidden"),r==null||r(null)},focus(){i.focus()}}}function Xo(t,e){let s=null,l=null,u=!0,r=null,d=!0,o=!0,n=!0,g="types",i="",a="",M=[],T=[];const x={types:new Set,nodeIds:new Set};function F(){if(!s)return[];const p=new Set;for(const y of s.nodes)x.types.has(y.type)&&p.add(y.id);for(const y of x.nodeIds)p.add(y);return[...p]}function W(p){if(x.nodeIds.has(p))return!0;const y=s==null?void 0:s.nodes.find(v=>v.id===p);return y?x.types.has(y.type):!1}function V(){return x.types.size===0&&x.nodeIds.size===0}function z(){const p=F();e.onFocusChange(p.length>0?p:null)}const X=document.createElement("button");X.className="tools-pane-toggle hidden",X.title="Graph Inspector",X.appendChild(ct({size:16,strokeLinecap:"round",strokeLinejoin:"round"},[{tag:"path",attrs:{d:"M4 7h16"}},{tag:"path",attrs:{d:"M4 12h16"}},{tag:"path",attrs:{d:"M4 17h10"}}]));const H=document.createElement("div");H.className="tools-pane-content hidden",t.appendChild(X),t.appendChild(H),X.addEventListener("click",()=>{var p;u=!u,H.classList.toggle("hidden",u),X.classList.toggle("active",!u),u||(p=e.onOpen)==null||p.call(e)});function K(){if(H.replaceChildren(),!l)return;const p=document.createElement("div");p.className="tools-pane-summary";const y=document.createElement("span");y.textContent=`${l.nodeCount} nodes`;const v=document.createElement("span");v.className="tools-pane-sep",v.textContent="·";const m=document.createElement("span");m.textContent=`${l.edgeCount} edges`;const b=document.createElement("span");b.className="tools-pane-sep",b.textContent="·";const L=document.createElement("span");if(L.textContent=`${l.types.length} types`,p.append(y,v,m,b,L),H.appendChild(p),s&&l.nodeCount>0){const N=Math.ceil(JSON.stringify(s).length/4),I=Math.round(N/l.nodeCount),C=Math.max(10,Math.round(I*.3)*Math.min(5,l.nodeCount)),B=N>C?Math.round((1-C/N)*100):0,$=document.createElement("div");$.className="tools-pane-token-card";const te=Math.min(100,B),ie=document.createElement("div");ie.className="token-card-label",ie.textContent="Token Efficiency",$.appendChild(ie);const le=document.createElement("div");le.className="token-card-stat",le.textContent=`~${N.toLocaleString()} tokens stored`,$.appendChild(le);const me=document.createElement("div");me.className="token-card-bar";const ve=document.createElement("div");ve.className="token-card-bar-fill",ve.style.width=`${te}%`,me.appendChild(ve),$.appendChild(me);const je=document.createElement("div");je.className="token-card-stat",je.textContent=`A search returns ~${C} tokens instead of ~${N.toLocaleString()} (${B}% reduction)`,$.appendChild(je),H.appendChild($)}const h=document.createElement("div");h.className="tools-pane-tabs";const S=[{id:"types",label:"Types"},{id:"insights",label:"Insights"},{id:"controls",label:"Controls"}];for(const N of S){const I=document.createElement("button");I.className="tools-pane-tab",g===N.id&&I.classList.add("tools-pane-tab-active"),I.textContent=N.label,I.addEventListener("click",()=>{g=N.id,K()}),h.appendChild(I)}H.appendChild(h),V()||U(),T.length>0&&ue(),g==="types"&&l.types.length>5?H.appendChild(xe("Filter types...",i,N=>{i=N,q()})):g==="insights"&&l.orphans.length+l.singletons.length+l.emptyNodes.length>5&&H.appendChild(xe("Filter issues...",a,I=>{a=I,q()}));const w=document.createElement("div");w.className="tools-pane-tab-content",H.appendChild(w),q()}function q(){const p=H.querySelector(".tools-pane-tab-content");p&&(p.replaceChildren(),g==="types"?ee(p):g==="insights"?G(p):g==="controls"&&ye(p))}function ue(){H.appendChild(se(`Walk Trail (${T.length})`,p=>{for(let v=0;v<T.length;v++){const m=T[v],b=v===T.length-1;if(m.edgeType){const C=document.createElement("div");C.className="walk-trail-edge",C.textContent=`↓ ${m.edgeType}`,p.appendChild(C)}const L=document.createElement("div");L.className="tools-pane-row tools-pane-clickable",b&&(L.style.fontWeight="600");const h=document.createElement("span");h.className="tools-pane-count",h.style.minWidth="18px",h.textContent=`${v+1}`;const S=document.createElement("span");S.className="tools-pane-dot",S.style.backgroundColor=Ae(m.type);const w=document.createElement("span");w.className="tools-pane-name",w.textContent=m.label;const N=document.createElement("span");N.className="tools-pane-count",N.textContent=m.type;const I=document.createElement("button");I.className="tools-pane-edit",I.style.opacity="1",I.textContent="×",I.title="Remove from trail",I.addEventListener("click",C=>{var B;C.stopPropagation(),(B=e.onWalkTrailRemove)==null||B.call(e,m.id)}),L.appendChild(h),L.appendChild(S),L.appendChild(w),L.appendChild(N),L.appendChild(I),L.addEventListener("click",()=>{e.onNavigateToNode(m.id)}),p.appendChild(L)}const y=document.createElement("div");if(y.className="tools-pane-export-row",e.onWalkIsolate){const v=document.createElement("button");v.className="tools-pane-export-btn",v.textContent="Isolate (I)",v.addEventListener("click",()=>e.onWalkIsolate()),y.appendChild(v)}if(e.onWalkSaveSnippet&&T.length>=2){const v=document.createElement("button");v.className="tools-pane-export-btn",v.textContent="Save snippet",v.addEventListener("click",()=>{Bt("Save snippet","Name for this snippet").then(m=>{m&&e.onWalkSaveSnippet(m)})}),y.appendChild(v)}p.appendChild(y)}))}function U(){if(!l||!s)return;const p=F();H.appendChild(se("Focused",y=>{for(const L of x.types){const h=l.types.find(B=>B.name===L);if(!h)continue;const S=document.createElement("div");S.className="tools-pane-row tools-pane-clickable";const w=document.createElement("span");w.className="tools-pane-dot",w.style.backgroundColor=Ae(h.name);const N=document.createElement("span");N.className="tools-pane-name",N.textContent=h.name;const I=document.createElement("span");I.className="tools-pane-count",I.textContent=`${h.count} nodes`;const C=document.createElement("button");C.className="tools-pane-edit tools-pane-focus-active",C.style.opacity="1",C.textContent="×",C.title=`Remove ${h.name} from focus`,S.appendChild(w),S.appendChild(N),S.appendChild(I),S.appendChild(C),C.addEventListener("click",B=>{B.stopPropagation(),x.types.delete(h.name),z(),K()}),y.appendChild(S)}for(const L of x.nodeIds){const h=s.nodes.find($=>$.id===L);if(!h)continue;const S=Wn(h.properties)??h.id,w=document.createElement("div");w.className="tools-pane-row tools-pane-clickable";const N=document.createElement("span");N.className="tools-pane-dot",N.style.backgroundColor=Ae(h.type);const I=document.createElement("span");I.className="tools-pane-name",I.textContent=S;const C=document.createElement("span");C.className="tools-pane-count",C.textContent=h.type;const B=document.createElement("button");B.className="tools-pane-edit tools-pane-focus-active",B.style.opacity="1",B.textContent="×",B.title=`Remove ${S} from focus`,w.appendChild(N),w.appendChild(I),w.appendChild(C),w.appendChild(B),w.addEventListener("click",$=>{$.target.closest(".tools-pane-edit")||e.onNavigateToNode(L)}),B.addEventListener("click",$=>{$.stopPropagation(),x.nodeIds.delete(L),z(),K()}),y.appendChild(w)}const v=document.createElement("div");v.className="tools-pane-row tools-pane-clickable tools-pane-focus-clear";const m=document.createElement("span");m.className="tools-pane-name",m.style.color="var(--accent)",m.textContent=`${p.length} total`;const b=document.createElement("span");b.className="tools-pane-badge",b.textContent="clear all",v.appendChild(m),v.appendChild(b),v.addEventListener("click",()=>{x.types.clear(),x.nodeIds.clear(),z(),K()}),y.appendChild(v)}))}function de(p){const y=document.createElement("div");y.className="tools-pane-row tools-pane-clickable",r===p.name&&y.classList.add("active");const v=document.createElement("span");v.className="tools-pane-dot",v.style.backgroundColor=Ae(p.name);const m=document.createElement("span");m.className="tools-pane-name",m.textContent=p.name;const b=document.createElement("span");b.className="tools-pane-count",b.textContent=String(p.count);const L=document.createElement("button");L.className="tools-pane-edit tools-pane-focus-toggle",x.types.has(p.name)&&L.classList.add("tools-pane-focus-active"),L.textContent="◎",L.title=x.types.has(p.name)?`Remove ${p.name} from focus`:`Add ${p.name} to focus`;const h=document.createElement("button");return h.className="tools-pane-edit",h.textContent="✎",h.title=`Rename all ${p.name} nodes`,y.appendChild(v),y.appendChild(m),y.appendChild(b),y.appendChild(L),y.appendChild(h),y.addEventListener("click",S=>{S.target.closest(".tools-pane-edit")||(r===p.name?(r=null,e.onFilterByType(null)):(r=p.name,e.onFilterByType(p.name)),K())}),L.addEventListener("click",S=>{S.stopPropagation(),x.types.has(p.name)?x.types.delete(p.name):x.types.add(p.name),z(),K()}),h.addEventListener("click",S=>{S.stopPropagation(),ge(y,p.name,w=>{w&&w!==p.name&&e.onRenameNodeType(p.name,w)})}),y}function xe(p,y,v){const m=document.createElement("input");return m.type="text",m.className="tools-pane-search",m.placeholder=p,m.value=y,m.addEventListener("input",()=>v(m.value)),m}function ee(p){if(!l)return;const y=i.toLowerCase();if(l.types.length){const m=l.types.filter(b=>!x.types.has(b.name)).filter(b=>!y||b.name.toLowerCase().includes(y));m.length>0&&p.appendChild(se("Node Types",b=>{for(const L of m)b.appendChild(de(L))}))}const v=l.edgeTypes.filter(m=>!y||m.name.toLowerCase().includes(y));v.length&&p.appendChild(se("Edge Types",m=>{for(const b of v){const L=document.createElement("div");L.className="tools-pane-row tools-pane-clickable";const h=document.createElement("span");h.className="tools-pane-name",h.textContent=b.name;const S=document.createElement("span");S.className="tools-pane-count",S.textContent=String(b.count);const w=document.createElement("button");w.className="tools-pane-edit",w.textContent="✎",w.title=`Rename all ${b.name} edges`,L.appendChild(h),L.appendChild(S),L.appendChild(w),w.addEventListener("click",N=>{N.stopPropagation(),ge(L,b.name,I=>{I&&I!==b.name&&e.onRenameEdgeType(b.name,I)})}),m.appendChild(L)}}))}function G(p){if(!l)return;const y=a.toLowerCase(),v=l.starred.filter(I=>!y||I.label.toLowerCase().includes(y)||I.type.toLowerCase().includes(y));v.length&&p.appendChild(se("★ Starred",I=>{for(const $ of v){const te=document.createElement("div");te.className="tools-pane-row tools-pane-clickable";const ie=document.createElement("span");ie.className="tools-pane-dot",ie.style.backgroundColor=Ae($.type);const le=document.createElement("span");le.className="tools-pane-name",le.textContent=$.label;const me=document.createElement("button");me.className="tools-pane-edit tools-pane-focus-toggle",W($.id)&&me.classList.add("tools-pane-focus-active"),me.textContent="◎",me.title=W($.id)?`Remove ${$.label} from focus`:`Add ${$.label} to focus`,te.appendChild(ie),te.appendChild(le),te.appendChild(me),te.addEventListener("click",ve=>{ve.target.closest(".tools-pane-edit")||e.onNavigateToNode($.id)}),me.addEventListener("click",ve=>{ve.stopPropagation(),x.nodeIds.has($.id)?x.nodeIds.delete($.id):x.nodeIds.add($.id),z(),K()}),I.appendChild(te)}const C=document.createElement("div");C.className="tools-pane-row tools-pane-actions";const B=document.createElement("button");if(B.className="tools-pane-action-btn",B.textContent="Focus all",B.title="Enter focus mode with all starred nodes",B.addEventListener("click",()=>{x.nodeIds.clear(),x.types.clear();for(const $ of l.starred)x.nodeIds.add($.id);z(),K()}),C.appendChild(B),e.onStarredSaveSnippet){const $=document.createElement("button");$.className="tools-pane-action-btn",$.textContent="Save as snippet",$.title="Save starred nodes as a reusable snippet",$.addEventListener("click",async()=>{const te=await Bt("Snippet name","starred");te&&e.onStarredSaveSnippet(te,l.starred.map(ie=>ie.id))}),C.appendChild($)}I.appendChild(C)}));const m=l.mostConnected.filter(I=>!y||I.label.toLowerCase().includes(y)||I.type.toLowerCase().includes(y));m.length&&p.appendChild(se("Most Connected",I=>{for(const C of m){const B=document.createElement("div");B.className="tools-pane-row tools-pane-clickable";const $=document.createElement("span");$.className="tools-pane-dot",$.style.backgroundColor=Ae(C.type);const te=document.createElement("span");te.className="tools-pane-name",te.textContent=C.label;const ie=document.createElement("span");ie.className="tools-pane-count",ie.textContent=`${C.connections}`;const le=document.createElement("button");le.className="tools-pane-edit tools-pane-focus-toggle",W(C.id)&&le.classList.add("tools-pane-focus-active"),le.textContent="◎",le.title=W(C.id)?`Remove ${C.label} from focus`:`Add ${C.label} to focus`,B.appendChild($),B.appendChild(te),B.appendChild(ie),B.appendChild(le),B.addEventListener("click",me=>{me.target.closest(".tools-pane-edit")||e.onNavigateToNode(C.id)}),le.addEventListener("click",me=>{me.stopPropagation(),x.nodeIds.has(C.id)?x.nodeIds.delete(C.id):x.nodeIds.add(C.id),z(),K()}),I.appendChild(B)}}));const b=l.orphans.filter(I=>!y||I.label.toLowerCase().includes(y)||I.type.toLowerCase().includes(y)),L=l.singletons.filter(I=>!y||I.name.toLowerCase().includes(y)),h=l.emptyNodes.filter(I=>!y||I.label.toLowerCase().includes(y)||I.type.toLowerCase().includes(y)),S=b.length>0,w=L.length>0,N=h.length>0;if(!S&&!w&&!N){const I=document.createElement("div");I.className="tools-pane-empty-msg",I.textContent="No issues found",p.appendChild(I);return}S&&p.appendChild(se("Orphans",I=>{for(const C of b.slice(0,5)){const B=document.createElement("div");B.className="tools-pane-row tools-pane-clickable tools-pane-issue";const $=document.createElement("span");$.className="tools-pane-dot",$.style.backgroundColor=Ae(C.type);const te=document.createElement("span");te.className="tools-pane-name",te.textContent=C.label;const ie=document.createElement("span");ie.className="tools-pane-badge",ie.textContent="orphan";const le=document.createElement("button");le.className="tools-pane-edit tools-pane-focus-toggle",W(C.id)&&le.classList.add("tools-pane-focus-active"),le.textContent="◎",le.title=W(C.id)?`Remove ${C.label} from focus`:`Add ${C.label} to focus`,B.appendChild($),B.appendChild(te),B.appendChild(ie),B.appendChild(le),B.addEventListener("click",me=>{me.target.closest(".tools-pane-edit")||e.onNavigateToNode(C.id)}),le.addEventListener("click",me=>{me.stopPropagation(),x.nodeIds.has(C.id)?x.nodeIds.delete(C.id):x.nodeIds.add(C.id),z(),K()}),I.appendChild(B)}if(b.length>5){const C=document.createElement("div");C.className="tools-pane-more",C.textContent=`+ ${b.length-5} more orphans`,I.appendChild(C)}})),w&&p.appendChild(se("Singletons",I=>{for(const C of L.slice(0,5)){const B=document.createElement("div");B.className="tools-pane-row tools-pane-issue";const $=document.createElement("span");$.className="tools-pane-dot",$.style.backgroundColor=Ae(C.name);const te=document.createElement("span");te.className="tools-pane-name",te.textContent=C.name;const ie=document.createElement("span");ie.className="tools-pane-badge",ie.textContent="1 node",B.appendChild($),B.appendChild(te),B.appendChild(ie),I.appendChild(B)}})),N&&p.appendChild(se("Empty Nodes",I=>{for(const C of h.slice(0,5)){const B=document.createElement("div");B.className="tools-pane-row tools-pane-issue";const $=document.createElement("span");$.className="tools-pane-dot",$.style.backgroundColor=Ae(C.type);const te=document.createElement("span");te.className="tools-pane-name",te.textContent=C.label;const ie=document.createElement("span");ie.className="tools-pane-badge",ie.textContent="empty",B.appendChild($),B.appendChild(te),B.appendChild(ie),I.appendChild(B)}if(l.emptyNodes.length>5){const C=document.createElement("div");C.className="tools-pane-more",C.textContent=`+ ${l.emptyNodes.length-5} more empty nodes`,I.appendChild(C)}}))}function ye(p){p.appendChild(se("Display",y=>{const v=document.createElement("div");v.className="tools-pane-row tools-pane-clickable";const m=document.createElement("input");m.type="checkbox",m.checked=d,m.className="tools-pane-checkbox";const b=document.createElement("span");b.className="tools-pane-name",b.textContent="Edge labels",v.appendChild(m),v.appendChild(b),v.addEventListener("click",C=>{C.target!==m&&(m.checked=!m.checked),d=m.checked,e.onToggleEdgeLabels(d)}),y.appendChild(v);const L=document.createElement("div");L.className="tools-pane-row tools-pane-clickable";const h=document.createElement("input");h.type="checkbox",h.checked=o,h.className="tools-pane-checkbox";const S=document.createElement("span");S.className="tools-pane-name",S.textContent="Type regions",L.appendChild(h),L.appendChild(S),L.addEventListener("click",C=>{C.target!==h&&(h.checked=!h.checked),o=h.checked,e.onToggleTypeHulls(o)}),y.appendChild(L);const w=document.createElement("div");w.className="tools-pane-row tools-pane-clickable";const N=document.createElement("input");N.type="checkbox",N.checked=n,N.className="tools-pane-checkbox";const I=document.createElement("span");I.className="tools-pane-name",I.textContent="Minimap",w.appendChild(N),w.appendChild(I),w.addEventListener("click",C=>{C.target!==N&&(N.checked=!N.checked),n=N.checked,e.onToggleMinimap(n)}),y.appendChild(w)})),p.appendChild(se("Layout",y=>{y.appendChild(Ce("Clustering",0,1,.02,.08,v=>{e.onLayoutChange("clusterStrength",v)})),y.appendChild(Ce("Spacing",.5,20,.5,1.5,v=>{e.onLayoutChange("spacing",v)})),y.appendChild(Ce("Pan speed",20,200,10,60,v=>{e.onPanSpeedChange(v)}))})),p.appendChild(se("Export",y=>{const v=document.createElement("div");v.className="tools-pane-export-row";const m=document.createElement("button");m.className="tools-pane-export-btn",m.textContent="Export PNG",m.addEventListener("click",()=>e.onExport("png"));const b=document.createElement("button");b.className="tools-pane-export-btn",b.textContent="Export SVG",b.addEventListener("click",()=>e.onExport("svg")),v.appendChild(m),v.appendChild(b),y.appendChild(v)})),(e.onSnapshot||e.onRollback)&&p.appendChild(se("Versions",y=>{const v=document.createElement("div");v.className="tools-pane-export-row";const m=document.createElement("button");if(m.className="tools-pane-export-btn",m.textContent="Save snapshot",m.addEventListener("click",()=>{Bt("Save snapshot","Label (optional)").then(b=>{var L;(L=e.onSnapshot)==null||L.call(e,b||void 0)})}),v.appendChild(m),y.appendChild(v),M.length>0)for(const b of M){const L=document.createElement("div");L.className="tools-pane-row";const h=document.createElement("span");h.className="tools-pane-name";const S=Go(b.timestamp);h.textContent=b.label?`#${b.version} ${b.label}`:`#${b.version}`,h.title=`${S} — ${b.nodeCount} nodes, ${b.edgeCount} edges`;const w=document.createElement("span");w.className="tools-pane-count",w.textContent=S;const N=document.createElement("button");N.className="tools-pane-edit",N.style.opacity="1",N.textContent="↩",N.title="Restore this snapshot",N.addEventListener("click",()=>{jn("Restore snapshot",`Restore snapshot #${b.version}? Current state will be lost unless you save a snapshot first.`).then(I=>{var C;I&&((C=e.onRollback)==null||C.call(e,b.version))})}),L.appendChild(h),L.appendChild(w),L.appendChild(N),y.appendChild(L)}else{const b=document.createElement("div");b.className="tools-pane-empty-msg",b.textContent="No snapshots yet",y.appendChild(b)}}))}function Ce(p,y,v,m,b,L){const h=document.createElement("div");h.className="tools-pane-slider-row";const S=document.createElement("span");S.className="tools-pane-slider-label",S.textContent=p;const w=document.createElement("input");w.type="range",w.className="tools-pane-slider",w.min=String(y),w.max=String(v),w.step=String(m),w.value=String(b);const N=document.createElement("span");return N.className="tools-pane-slider-value",N.textContent=String(b),w.addEventListener("input",()=>{const I=parseFloat(w.value);N.textContent=I%1===0?String(I):I.toFixed(2),L(I)}),h.appendChild(S),h.appendChild(w),h.appendChild(N),h}function se(p,y){const v=document.createElement("div");v.className="tools-pane-section";const m=document.createElement("div");return m.className="tools-pane-heading",m.textContent=p,v.appendChild(m),y(v),v}function ge(p,y,v){const m=document.createElement("input");m.className="tools-pane-inline-input",m.value=y,m.type="text";const b=ho(p);p.replaceChildren(m),p.classList.add("tools-pane-editing"),m.focus(),m.select();function L(){fo(p,b)}function h(){const S=m.value.trim();p.classList.remove("tools-pane-editing"),S&&S!==y?v(S):L()}m.addEventListener("keydown",S=>{S.key==="Enter"&&(S.preventDefault(),h()),S.key==="Escape"&&(L(),p.classList.remove("tools-pane-editing"))}),m.addEventListener("blur",h)}function be(p){const y=new Map,v=new Map,m=new Map,b=new Set;for(const C of p.nodes)y.set(C.type,(y.get(C.type)??0)+1);for(const C of p.edges)v.set(C.type,(v.get(C.type)??0)+1),m.set(C.sourceId,(m.get(C.sourceId)??0)+1),m.set(C.targetId,(m.get(C.targetId)??0)+1),b.add(C.sourceId),b.add(C.targetId);const L=C=>Wn(C.properties)??C.id,h=p.nodes.filter(C=>C.properties._starred===!0).map(C=>({id:C.id,label:L(C),type:C.type})),S=p.nodes.filter(C=>!b.has(C.id)).map(C=>({id:C.id,label:L(C),type:C.type})),w=[...y.entries()].filter(([,C])=>C===1).map(([C])=>({name:C})),N=p.nodes.filter(C=>Object.keys(C.properties).length===0).map(C=>({id:C.id,label:C.id,type:C.type})),I=p.nodes.map(C=>({id:C.id,label:L(C),type:C.type,connections:m.get(C.id)??0})).filter(C=>C.connections>0).sort((C,B)=>B.connections-C.connections).slice(0,5);return{nodeCount:p.nodes.length,edgeCount:p.edges.length,types:[...y.entries()].sort((C,B)=>B[1]-C[1]).map(([C,B])=>({name:C,count:B})),edgeTypes:[...v.entries()].sort((C,B)=>B[1]-C[1]).map(([C,B])=>({name:C,count:B})),starred:h,orphans:S,singletons:w,emptyNodes:N,mostConnected:I}}return{collapse(){u=!0,H.classList.add("hidden"),X.classList.remove("active")},addToFocusSet(p){for(const y of p)x.nodeIds.add(y);z(),K()},clearFocusSet(){x.types.clear(),x.nodeIds.clear(),z(),K()},setData(p){s=p,r=null,x.types.clear(),x.nodeIds.clear(),s&&s.nodes.length>0?(l=be(s),X.classList.remove("hidden"),K()):(l=null,X.classList.add("hidden"),H.classList.add("hidden"))},setSnapshots(p){M=p,g==="controls"&&q()},setWalkTrail(p){T=p,K()}}}function Go(t){const e=Date.now()-new Date(t).getTime(),s=Math.floor(e/6e4);if(s<1)return"just now";if(s<60)return`${s}m ago`;const l=Math.floor(s/60);return l<24?`${l}h ago`:`${Math.floor(l/24)}d ago`}function Wn(t){for(const e of Object.values(t))if(typeof e=="string")return e;return null}function Vo(t,e){const s=e.split("+"),l=s.pop(),u=s.map(n=>n.toLowerCase()),r=u.includes("ctrl")||u.includes("cmd")||u.includes("meta"),d=u.includes("shift"),o=u.includes("alt");return r!==(t.ctrlKey||t.metaKey)||!r&&(t.ctrlKey||t.metaKey)||d&&!t.shiftKey||o!==t.altKey?!1:l.toLowerCase()==="escape"?t.key==="Escape":l.toLowerCase()==="tab"?t.key==="Tab":u.length>0?t.key.toLowerCase()===l.toLowerCase():t.key===l}function Jo(){return{search:"Focus search",searchAlt:"Focus search (alt)",undo:"Undo",redo:"Redo",help:"Toggle help",escape:"Exit focus / close panel",focus:"Focus on selected / exit focus",toggleEdges:"Toggle edges on/off",center:"Center view on graph",nextNode:"Next node in view",prevNode:"Previous node in view",nextConnection:"Next connection",prevConnection:"Previous connection",historyBack:"Node history back",historyForward:"Node history forward",hopsIncrease:"Increase hops",hopsDecrease:"Decrease hops",panLeft:"Pan left",panDown:"Pan down",panUp:"Pan up",panRight:"Pan right",panFastLeft:"Pan fast left",zoomOut:"Zoom out",zoomIn:"Zoom in",panFastRight:"Pan fast right",spacingDecrease:"Decrease spacing",spacingIncrease:"Increase spacing",clusteringDecrease:"Decrease clustering",clusteringIncrease:"Increase clustering",toggleSidebar:"Toggle sidebar",walkMode:"Toggle walk mode (in focus)",walkIsolate:"Isolate walk trail nodes",resetPins:"Release all pinned nodes (reset manual layout)"}}const Ko=[{key:"Click",description:"Select node"},{key:"Shift+Click",description:"Multi-select nodes"},{key:"Drag node",description:"Move & pin node (temporary)"},{key:"Drag selection",description:"Move selected group (temporary)"},{key:"Shift+drag empty",description:"Rubber-band select"},{key:"Drag empty",description:"Pan canvas"},{key:"Scroll",description:"Zoom in/out"}],Zo=["search","searchAlt","undo","redo","help","focus","toggleEdges","center","nextNode","prevNode","nextConnection","prevConnection","historyBack","historyForward","hopsIncrease","hopsDecrease","panLeft","panDown","panUp","panRight","panFastLeft","panFastRight","zoomIn","zoomOut","spacingDecrease","spacingIncrease","clusteringDecrease","clusteringIncrease","toggleSidebar","walkMode","walkIsolate","resetPins","escape"];function Qo(t){return t.split("+").map(e=>e.charAt(0).toUpperCase()+e.slice(1)).join("+")}function es(t,e){const s=Jo(),l=document.createElement("div");l.className="shortcuts-overlay hidden";const u=document.createElement("div");u.className="shortcuts-modal";const r=document.createElement("h3");r.className="shortcuts-title",r.textContent="Keyboard Shortcuts";const d=document.createElement("div");d.className="shortcuts-list";for(const a of Zo){const M=e[a];if(!M)continue;const T=document.createElement("div");T.className="shortcuts-row";const x=document.createElement("div");x.className="shortcuts-keys";const F=document.createElement("kbd");F.textContent=Qo(M),x.appendChild(F);const W=document.createElement("span");W.className="shortcuts-desc",W.textContent=s[a],T.appendChild(x),T.appendChild(W),d.appendChild(T)}for(const a of Ko){const M=document.createElement("div");M.className="shortcuts-row";const T=document.createElement("div");T.className="shortcuts-keys";const x=document.createElement("kbd");x.textContent=a.key,T.appendChild(x);const F=document.createElement("span");F.className="shortcuts-desc",F.textContent=a.description,M.appendChild(T),M.appendChild(F),d.appendChild(M)}const o=document.createElement("button");o.className="shortcuts-close",o.textContent="×",u.appendChild(o),u.appendChild(r),u.appendChild(d),l.appendChild(u),t.appendChild(l);function n(){l.classList.remove("hidden")}function g(){l.classList.add("hidden")}function i(){l.classList.toggle("hidden")}return o.addEventListener("click",g),l.addEventListener("click",a=>{a.target===l&&g()}),{show:n,hide:g,toggle:i}}function ts(t){const e=document.createElement("div");e.className="empty-state";const s=document.createElement("div");s.className="empty-state-bg";for(const T of["c1","c2","c3","c4","c5"]){const x=document.createElement("div");x.className=`empty-state-circle ${T}`,s.appendChild(x)}s.appendChild(ct({size:0,viewBox:"0 0 400 300",className:"empty-state-lines"},[{tag:"line",attrs:{x1:80,y1:60,x2:220,y2:140,"stroke-width":"0.5",opacity:"0.15"}},{tag:"line",attrs:{x1:220,y1:140,x2:320,y2:80,"stroke-width":"0.5",opacity:"0.15"}},{tag:"line",attrs:{x1:220,y1:140,x2:160,y2:240,"stroke-width":"0.5",opacity:"0.15"}},{tag:"line",attrs:{x1:160,y1:240,x2:300,y2:220,"stroke-width":"0.5",opacity:"0.15"}}]));const l=s.querySelector(".empty-state-lines");l&&(l.removeAttribute("width"),l.removeAttribute("height"),l.setAttribute("preserveAspectRatio","xMidYMid slice")),e.appendChild(s);const u=document.createElement("div");u.className="empty-state-content";const r=document.createElement("div");r.className="empty-state-icon",r.appendChild(ct({size:48,strokeWidth:1.5,strokeLinecap:"round",strokeLinejoin:"round"},[{tag:"path",attrs:{d:"M21 16V8a2 2 0 00-1-1.73l-7-4a2 2 0 00-2 0l-7 4A2 2 0 002 8v8a2 2 0 001 1.73l7 4a2 2 0 002 0l7-4A2 2 0 0022 16z"}},{tag:"polyline",attrs:{points:"3.27 6.96 12 12.01 20.73 6.96"}},{tag:"line",attrs:{x1:12,y1:22.08,x2:12,y2:12}}])),u.appendChild(r);const d=document.createElement("h2");d.className="empty-state-title",d.textContent="No learning graphs yet",u.appendChild(d);const o=document.createElement("p");o.className="empty-state-desc",o.textContent="Connect Backpack to Claude, then start a conversation. Claude will build your first learning graph automatically.",u.appendChild(o);const n=document.createElement("div");n.className="empty-state-setup";const g=document.createElement("div");g.className="empty-state-label",g.textContent="Add Backpack to Claude Code:";const i=document.createElement("code");i.className="empty-state-code",i.textContent="claude mcp add backpack-local -s user -- npx backpack-ontology@latest",n.append(g,i),u.appendChild(n);const a=document.createElement("p");a.className="empty-state-hint",a.append("Press ");const M=document.createElement("kbd");return M.textContent="?",a.appendChild(M),a.append(" for keyboard shortcuts"),u.appendChild(a),e.appendChild(u),t.appendChild(e),{show(){e.classList.remove("hidden")},hide(){e.classList.add("hidden")}}}const ns=30;function os(){let t=[],e=[];return{push(s){t.push(JSON.stringify(s)),t.length>ns&&t.shift(),e=[]},undo(s){return t.length===0?null:(e.push(JSON.stringify(s)),JSON.parse(t.pop()))},redo(s){return e.length===0?null:(t.push(JSON.stringify(s)),JSON.parse(e.pop()))},canUndo(){return t.length>0},canRedo(){return e.length>0},clear(){t=[],e=[]}}}function ss(t,e){let s=null;function l(d,o,n,g,i){u(),s=document.createElement("div"),s.className="context-menu",s.style.left=`${g}px`,s.style.top=`${i}px`;const a=[{label:n?"★ Unstar":"☆ Star",action:()=>e.onStar(d),premium:!1},{label:"◎ Focus on node",action:()=>e.onFocusNode(d),premium:!1},{label:"⑂ Explore in branch",action:()=>e.onExploreInBranch(d),premium:!1},{label:"⎘ Copy ID",action:()=>e.onCopyId(d),premium:!1}];e.onExpand&&a.push({label:"⊕ Expand node",action:()=>e.onExpand(d),premium:!0}),e.onExplainPath&&a.push({label:"↔ Explain path to…",action:()=>e.onExplainPath(d),premium:!0}),e.onEnrich&&a.push({label:"≡ Enrich from web",action:()=>e.onEnrich(d),premium:!0});let M=!1;for(const x of a){if(!M&&x.premium){const W=document.createElement("div");W.className="context-menu-separator",s.appendChild(W),M=!0}const F=document.createElement("div");F.className="context-menu-item",F.textContent=x.label,F.addEventListener("click",()=>{x.action(),u()}),s.appendChild(F)}t.appendChild(s);const T=s.getBoundingClientRect();T.right>window.innerWidth&&(s.style.left=`${g-T.width}px`),T.bottom>window.innerHeight&&(s.style.top=`${i-T.height}px`),setTimeout(()=>document.addEventListener("click",u),0),document.addEventListener("keydown",r)}function u(){s&&(s.remove(),s=null),document.removeEventListener("click",u),document.removeEventListener("keydown",r)}function r(d){d.key==="Escape"&&u()}return{show:l,hide:u}}function as(t){const e=document.createElement("button");return e.className="copy-prompt-btn",e.title="Copy a prompt about the current view to clipboard",e.textContent="Copy Prompt",e.addEventListener("click",async()=>{const s=t();if(!s.graphName||!s.data){wt("No graph loaded");return}const l=cs(s);try{await navigator.clipboard.writeText(l),wt("Prompt copied — paste into Claude")}catch{wt("Failed to copy to clipboard")}}),e}function Un(t){return Object.values(t.properties).find(s=>typeof s=="string")??t.id}function cs(t){const{graphName:e,data:s,selection:l,focus:u}=t,r=[];r.push(`I'm looking at the Backpack learning graph "${e}" in the viewer.`),r.push(`It has ${s.nodes.length} nodes and ${s.edges.length} edges.`);const d=new Map;for(const o of s.nodes)d.set(o.type,(d.get(o.type)??0)+1);if(d.size>0){const o=Array.from(d.entries()).sort((n,g)=>g[1]-n[1]).slice(0,8).map(([n,g])=>`${n} (${g})`).join(", ");r.push(`Node types: ${o}`)}if(u&&u.seedNodeIds.length>0){r.push(""),r.push(`I'm focused on ${u.seedNodeIds.length} seed node(s) at ${u.hops} hop(s):`);for(const o of u.seedNodeIds.slice(0,10)){const n=s.nodes.find(g=>g.id===o);n&&r.push(`- ${Un(n)} (type: ${n.type})`)}}if(l.length>0){r.push(""),r.push(`I have ${l.length} node(s) selected:`);for(const o of l.slice(0,20)){const n=s.nodes.find(i=>i.id===o);if(!n)continue;const g=Object.entries(n.properties).filter(([i])=>!i.startsWith("_")).slice(0,5).map(([i,a])=>`${i}=${JSON.stringify(a)}`).join(", ");r.push(`- ${Un(n)} (type: ${n.type}, id: ${o}${g?`, ${g}`:""})`)}}return r.push(""),r.push("If you have access to the Backpack MCP tools, please use them to answer questions about this graph (backpack_get_node, backpack_get_neighbors, backpack_search, etc)."),r.push(""),r.push("My question: "),r.join(`
6
- `)}const is=200;let Ht=null,Yt=null;function ls(t){Ht=t,Yt===null&&(Yt=window.setTimeout(async()=>{const e=Ht;if(Ht=null,Yt=null,!!e)try{await fetch("/api/viewer-state",{method:"PUT",headers:{"Content-Type":"application/json"},body:JSON.stringify({...e,updatedAt:new Date().toISOString()})})}catch{}},is))}function rs(){const t=new Map;return{emit(e){const s=t.get(e);if(s)for(const l of s)try{l()}catch(u){console.error(`[backpack-viewer] event handler for ${e} threw:`,u)}},subscribe(e,s){let l=t.get(e);return l||(l=new Set,t.set(e,l)),l.add(s),()=>{const u=t.get(e);u==null||u.delete(s)}}}}const Kt="1";function ds(t,e,s,l){function u(){return Date.now().toString(36)+Math.random().toString(36).slice(2,10)}function r(){const d=e.getGraph();if(!d)throw new Error("no graph loaded in viewer");return d}return{name:t,viewerApiVersion:Kt,getGraph:()=>e.getGraph(),getGraphName:()=>e.getGraphName(),getSelection:()=>e.getSelection(),getFocus:()=>e.getFocus(),on(d,o){return e.subscribe(d,o)},async addNode(d,o){if(!d)throw new Error("addNode: type is required");const n=r();e.snapshotForUndo();const g=u(),i=new Date().toISOString();return n.nodes.push({id:g,type:d,properties:o,createdAt:i,updatedAt:i}),await e.saveCurrentGraph(),g},async updateNode(d,o){const g=r().nodes.find(i=>i.id===d);if(!g)throw new Error(`updateNode: node not found: ${d}`);e.snapshotForUndo(),g.properties={...g.properties,...o},g.updatedAt=new Date().toISOString(),await e.saveCurrentGraph()},async removeNode(d){const o=r();if(!o.nodes.find(g=>g.id===d))throw new Error(`removeNode: node not found: ${d}`);e.snapshotForUndo(),o.nodes=o.nodes.filter(g=>g.id!==d),o.edges=o.edges.filter(g=>g.sourceId!==d&&g.targetId!==d),await e.saveCurrentGraph()},async addEdge(d,o,n){if(!d||!o||!n)throw new Error("addEdge: sourceId, targetId, and type are required");const g=r();if(!g.nodes.find(a=>a.id===d))throw new Error(`addEdge: source not found: ${d}`);if(!g.nodes.find(a=>a.id===o))throw new Error(`addEdge: target not found: ${o}`);e.snapshotForUndo();const i=u();return g.edges.push({id:i,sourceId:d,targetId:o,type:n}),await e.saveCurrentGraph(),i},async removeEdge(d){const o=r();if(!o.edges.find(g=>g.id===d))throw new Error(`removeEdge: edge not found: ${d}`);e.snapshotForUndo(),o.edges=o.edges.filter(g=>g.id!==d),await e.saveCurrentGraph()},panToNode:d=>e.panToNode(d),focusNodes:(d,o)=>e.focusNodes(d,o),exitFocus:()=>e.exitFocus(),registerTaskbarIcon(d){return s.register(d)},mountPanel(d,o){return l.mount(t,d,o)},settings:{async get(d){const o=`/api/extensions/${encodeURIComponent(t)}/settings`,n=await fetch(o);if(!n.ok)return null;const g=await n.json();return d in g?g[d]:null},async set(d,o){const n=`/api/extensions/${encodeURIComponent(t)}/settings/${encodeURIComponent(d)}`,g=await fetch(n,{method:"PUT",headers:{"Content-Type":"application/json"},body:JSON.stringify({value:o})});if(!g.ok){const i=await g.text().catch(()=>"");throw new Error(`settings.set failed: ${i||g.status}`)}},async remove(d){const o=`/api/extensions/${encodeURIComponent(t)}/settings/${encodeURIComponent(d)}`,n=await fetch(o,{method:"DELETE"});if(!n.ok){const g=await n.text().catch(()=>"");throw new Error(`settings.remove failed: ${g||n.status}`)}}},async fetch(d,o={}){const n=`/api/extensions/${encodeURIComponent(t)}/fetch`,g={};if(o.headers)if(o.headers instanceof Headers)o.headers.forEach((a,M)=>{g[M]=a});else if(Array.isArray(o.headers))for(const[a,M]of o.headers)g[a]=M;else Object.assign(g,o.headers);const i=typeof o.body=="string"||o.body==null?o.body:(()=>{throw new Error("viewer.fetch only supports string bodies in v1")})();return fetch(n,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({url:d,method:o.method??"POST",headers:g,body:i})})}}}const ps="bottom-right";function us(t){const e={"top-left":t.topLeft,"top-right":t.topRight,"bottom-left":t.bottomLeft,"bottom-right":t.bottomRight},s={"top-left":0,"top-right":0,"bottom-left":0,"bottom-right":0};function l(r){e[r].classList.toggle("has-icons",s[r]>0)}l("top-left"),l("top-right"),l("bottom-left"),l("bottom-right");function u(r){const d=r.position??ps,o=e[d];if(!o)throw new Error(`unknown taskbar position: ${d}`);const n=document.createElement("button");if(n.className="extension-taskbar-icon",n.title=r.label,n.setAttribute("aria-label",r.label),r.iconText){const i=document.createElement("span");i.className="extension-taskbar-icon-symbol",i.textContent=r.iconText,n.appendChild(i)}const g=document.createElement("span");return g.className="extension-taskbar-icon-label",g.textContent=r.label,n.appendChild(g),n.addEventListener("click",()=>{try{r.onClick()}catch(i){console.error(`[backpack-viewer] taskbar icon "${r.label}" onClick threw:`,i)}}),o.appendChild(n),s[d]++,l(d),()=>{n.remove(),s[d]=Math.max(0,s[d]-1),l(d)}}return{register:u}}async function ms(t,e){const s=us(t.taskbarSlots);let l=[];try{const r=await fetch("/api/extensions");if(!r.ok)return console.warn(`[backpack-viewer] /api/extensions returned ${r.status}; no extensions will be loaded`),[];l=await r.json()}catch(r){return console.error(`[backpack-viewer] failed to fetch extensions list: ${r.message}`),[]}const u=[];for(const r of l){if(r.viewerApi!==Kt){console.warn(`[backpack-viewer] extension "${r.name}" targets viewerApi "${r.viewerApi}" but this viewer supports "${Kt}"; skipping`);continue}if(r.stylesheet)try{hs(r.name,r.stylesheet)}catch(o){console.error(`[backpack-viewer] extension "${r.name}" stylesheet load failed:`,o)}const d=ds(r.name,t,s,e);try{const g=(await import(`/extensions/${encodeURIComponent(r.name)}/${r.entry}`)).activate;if(typeof g!="function"){console.error(`[backpack-viewer] extension "${r.name}" has no exported activate(api) function; skipping`);continue}await g(d),u.push({info:r,api:d}),console.log(`[backpack-viewer] loaded extension "${r.name}" v${r.version}`)}catch(o){console.error(`[backpack-viewer] extension "${r.name}" failed to activate:`,o)}}return u}function hs(t,e){if(e.includes(".."))throw new Error(`stylesheet path "${e}" is invalid`);const s=document.createElement("link");s.rel="stylesheet",s.href=`/extensions/${encodeURIComponent(t)}/${e}`,s.dataset.extension=t,document.head.appendChild(s)}const fs={search:"/",searchAlt:"ctrl+k",undo:"ctrl+z",redo:"ctrl+shift+z",help:"?",escape:"Escape",focus:"f",toggleEdges:"e",center:"c",nextNode:".",prevNode:",",nextConnection:">",prevConnection:"<",historyBack:"(",historyForward:")",hopsIncrease:"=",hopsDecrease:"-",panLeft:"h",panDown:"j",panUp:"k",panRight:"l",panFastLeft:"H",zoomOut:"J",zoomIn:"K",panFastRight:"L",spacingDecrease:"[",spacingIncrease:"]",clusteringDecrease:"{",clusteringIncrease:"}",toggleSidebar:"Tab",walkMode:"w",walkIsolate:"i",resetPins:"r"},gs={host:"127.0.0.1",port:5173},ys={edges:!0,edgeLabels:!0,typeHulls:!0,minimap:!0,theme:"system"},Cs={spacing:1.5,clustering:.08},vs={panSpeed:60,panFastMultiplier:3,zoomFactor:1.3,zoomMin:.05,zoomMax:10,panAnimationMs:300},bs={hideBadges:.4,hideLabels:.25,hideEdgeLabels:.35,smallNodes:.2,hideArrows:.15},xs={pulseSpeed:.02},Es={maxSearchResults:8,maxQualityItems:5,maxMostConnected:5,searchDebounceMs:150},ws={disabled:[],external:[]},ks={keybindings:fs,server:gs,display:ys,layout:Cs,navigation:vs,lod:bs,walk:xs,limits:Es,extensions:ws};let ce="",A=null,qt=new Set,Xt=!1;async function Ss(){var ut,mt;const t=document.getElementById("canvas-container"),e={...ks};try{const c=await fetch("/api/config");if(c.ok){const E=await c.json();Object.assign(e.keybindings,E.keybindings??{}),Object.assign(e.display,E.display??{}),Object.assign(e.layout,E.layout??{}),Object.assign(e.navigation,E.navigation??{}),Object.assign(e.lod,E.lod??{}),Object.assign(e.limits,E.limits??{})}}catch{}const s=e.keybindings,l=window.matchMedia("(prefers-color-scheme: dark)"),u=e.display.theme==="system"?l.matches?"dark":"light":e.display.theme,d=localStorage.getItem("backpack-theme")??u;document.documentElement.setAttribute("data-theme",d);const o=document.createElement("button");o.className="theme-toggle",o.textContent=d==="light"?"☾":"☼",o.title="Toggle light/dark mode",o.addEventListener("click",()=>{const E=document.documentElement.getAttribute("data-theme")==="light"?"dark":"light";document.documentElement.setAttribute("data-theme",E),localStorage.setItem("backpack-theme",E),o.textContent=E==="light"?"☾":"☼"}),t.appendChild(o);const n=os();async function g(){if(!ce||!A)return;A.metadata.updatedAt=new Date().toISOString(),await Ot(ce,A),a.loadGraph(A),ee.setLearningGraphData(A),G.setData(A);const c=await vt();S.setSummaries(c),de.emit("graph-changed")}async function i(c){A=c,await Ot(ce,A),a.loadGraph(A),ee.setLearningGraphData(A),G.setData(A);const E=await vt();S.setSummaries(E)}let a;const M=Yo(t),T=Fo(t,M,{onUpdateNode(c,E){if(!A)return;n.push(A);const R=A.nodes.find(Y=>Y.id===c);R&&(R.properties={...R.properties,...E},R.updatedAt=new Date().toISOString(),g().then(()=>T.show([c],A)))},onChangeNodeType(c,E){if(!A)return;n.push(A);const R=A.nodes.find(Y=>Y.id===c);R&&(R.type=E,R.updatedAt=new Date().toISOString(),g().then(()=>T.show([c],A)))},onDeleteNode(c){A&&(n.push(A),A.nodes=A.nodes.filter(E=>E.id!==c),A.edges=A.edges.filter(E=>E.sourceId!==c&&E.targetId!==c),g())},onDeleteEdge(c){var R;if(!A)return;n.push(A);const E=(R=A.edges.find(Y=>Y.id===c))==null?void 0:R.sourceId;A.edges=A.edges.filter(Y=>Y.id!==c),g().then(()=>{E&&A&&T.show([E],A)})},onAddProperty(c,E,R){if(!A)return;n.push(A);const Y=A.nodes.find(ne=>ne.id===c);Y&&(Y.properties[E]=R,Y.updatedAt=new Date().toISOString(),g().then(()=>T.show([c],A)))}},c=>{a.panToNode(c)},c=>{G.addToFocusSet(c)}),x=window.matchMedia("(max-width: 768px)");let F=[],W=e.display.edges,V=e.navigation.panSpeed,z=-1,X=null;function H(c){X&&X.remove(),X=document.createElement("div"),X.className="focus-indicator";const E=document.createElement("span");E.className="focus-indicator-label",E.textContent=`Focused: ${c.totalNodes} nodes`;const R=document.createElement("span");R.className="focus-indicator-hops",R.textContent=`${c.hops}`;const Y=document.createElement("button");Y.className="focus-indicator-btn",Y.textContent="−",Y.title="Fewer hops",Y.disabled=c.hops===0,Y.addEventListener("click",()=>{a.enterFocus(c.seedNodeIds,Math.max(0,c.hops-1))});const ne=document.createElement("button");ne.className="focus-indicator-btn",ne.textContent="+",ne.title="More hops",ne.disabled=!1,ne.addEventListener("click",()=>{a.enterFocus(c.seedNodeIds,c.hops+1)});const ae=document.createElement("button");ae.className="focus-indicator-btn focus-indicator-exit",ae.textContent="×",ae.title="Exit focus (Esc)",ae.addEventListener("click",()=>G.clearFocusSet());const pe=document.createElement("button");pe.className="walk-indicator",a.getWalkMode()&&pe.classList.add("active"),pe.textContent="Walk",pe.title="Toggle walk mode (W) — click nodes to traverse",pe.addEventListener("click",()=>{a.setWalkMode(!a.getWalkMode()),pe.classList.toggle("active",a.getWalkMode())}),X.appendChild(E),X.appendChild(Y),X.appendChild(R),X.appendChild(ne),X.appendChild(pe),X.appendChild(ae)}function K(){X&&(X.remove(),X=null)}const q=document.createElement("div");q.className="path-bar hidden",t.appendChild(q);function ue(c){if(q.replaceChildren(),!A)return;for(let R=0;R<c.nodeIds.length;R++){const Y=c.nodeIds[R],ne=A.nodes.find(he=>he.id===Y);if(!ne)continue;const ae=Object.values(ne.properties).find(he=>typeof he=="string")??ne.id;if(R>0){const he=c.edgeIds[R-1],we=A.edges.find(De=>De.id===he),Le=document.createElement("span");Le.className="path-bar-edge",Le.textContent=we?`→ ${we.type} →`:"→",q.appendChild(Le)}const pe=document.createElement("span");pe.className="path-bar-node",pe.textContent=ae,pe.addEventListener("click",()=>a.panToNode(Y)),q.appendChild(pe)}const E=document.createElement("button");E.className="path-bar-close",E.textContent="×",E.addEventListener("click",U),q.appendChild(E),q.classList.remove("hidden")}function U(){q.classList.add("hidden"),q.replaceChildren(),a.clearHighlightedPath()}const de=rs();function xe(){ce&&ls({graph:ce,selection:F,focus:(a==null?void 0:a.getFocusInfo())??null})}a=Bo(t,c=>{if(F=c??[],xe(),de.emit("selection-changed"),!a.getWalkMode())if(c&&c.length===2){const E=a.findPath(c[0],c[1]);E&&E.nodeIds.length>0?(a.setHighlightedPath(E.nodeIds,E.edgeIds),ue(E)):U()}else U();c&&c.length>0&&A?(T.show(c,A),x.matches&&G.collapse(),le(ce,c)):(T.hide(),ce&&le(ce))},c=>{if(c){H(c);const E=t.querySelector(".canvas-top-left");E&&X&&E.appendChild(X),le(ce,c.seedNodeIds),T.setFocusDisabled(c.hops===0),N()}else K(),T.setFocusDisabled(!1),ce&&le(ce),N();xe(),de.emit("focus-changed")},{lod:e.lod,navigation:e.navigation,walk:e.walk});const ee=qo(t,{maxResults:e.limits.maxSearchResults,debounceMs:e.limits.searchDebounceMs}),G=Xo(t,{onFilterByType(c){if(A)if(c===null)a.setFilteredNodeIds(null);else{const E=new Set(((A==null?void 0:A.nodes)??[]).filter(R=>R.type===c).map(R=>R.id));a.setFilteredNodeIds(E)}},onNavigateToNode(c){a.panToNode(c),A&&T.show([c],A)},onWalkTrailRemove(c){a.removeFromWalkTrail(c),N()},onWalkIsolate(){if(!A)return;const c=a.getWalkTrail();c.length!==0&&a.enterFocus(c,0)},async onWalkSaveSnippet(c){if(!ce||!A)return;const E=a.getWalkTrail();if(E.length<2)return;const R=new Set(E),Y=A.edges.filter(ne=>R.has(ne.sourceId)&&R.has(ne.targetId)).map(ne=>ne.id);await yn(ce,c,E,Y),await B(ce)},async onStarredSaveSnippet(c,E){if(!ce||!A)return;const R=new Set(E),Y=A.edges.filter(ne=>R.has(ne.sourceId)&&R.has(ne.targetId)).map(ne=>ne.id);await yn(ce,c,E,Y),await B(ce)},onFocusChange(c){c&&c.length>0?a.enterFocus(c,0):a.isFocused()&&a.exitFocus()},onRenameNodeType(c,E){if(A){n.push(A);for(const R of A.nodes)R.type===c&&(R.type=E,R.updatedAt=new Date().toISOString());g()}},onRenameEdgeType(c,E){if(A){n.push(A);for(const R of A.edges)R.type===c&&(R.type=E);g()}},onToggleEdgeLabels(c){a.setEdgeLabels(c)},onToggleTypeHulls(c){a.setTypeHulls(c)},onToggleMinimap(c){a.setMinimap(c)},onLayoutChange(c,E){lt({[c]:E}),a.reheat()},onPanSpeedChange(c){V=c},onExport(c){const E=a.exportImage(c);if(!E)return;const R=document.createElement("a");R.download=`${ce||"graph"}.${c}`,R.href=E,R.click()},onSnapshot:async c=>{ce&&(await io(ce,c),await C(ce))},onRollback:async c=>{ce&&(await lo(ce,c),A=await Mt(ce),a.loadGraph(A),ee.setLearningGraphData(A),G.setData(A),await C(ce))},onOpen(){x.matches&&T.hide()}}),ye=document.createElement("div");ye.className="canvas-top-bar";const Ce=document.createElement("div");Ce.className="canvas-top-left";const se=document.createElement("div");se.className="canvas-top-center";const ge=document.createElement("div");ge.className="canvas-top-right";const be=t.querySelector(".tools-pane-toggle");be&&Ce.appendChild(be);const p=t.querySelector(".zoom-controls");p&&ge.appendChild(p),ge.appendChild(o);const y=document.createElement("div");y.className="ext-slot ext-slot-top-left",se.appendChild(y);const v=t.querySelector(".search-overlay");v&&se.appendChild(v);const m=document.createElement("div");m.className="ext-slot ext-slot-top-right",se.appendChild(m);const b=as(()=>({graphName:ce,data:A,selection:F,focus:a.getFocusInfo()}));se.appendChild(b);const L=document.createElement("div");L.className="ext-slot ext-slot-bottom-left",t.appendChild(L);const h=document.createElement("div");h.className="ext-slot ext-slot-bottom-right",t.appendChild(h),ye.appendChild(Ce),ye.appendChild(se),ye.appendChild(ge),t.appendChild(ye),ee.onFilterChange(c=>{a.setFilteredNodeIds(c)}),ee.onNodeSelect(c=>{a.isFocused()&&G.clearFocusSet(),a.panToNode(c),A&&T.show([c],A)});const S=go(document.getElementById("sidebar"),{onSelect:c=>ve(c),onRename:async(c,E)=>{await oo(c,E),ce===c&&(ce=E);const R=await vt();S.setSummaries(R),S.setActive(ce),ce===E&&(A=await Mt(E),a.loadGraph(A),ee.setLearningGraphData(A),G.setData(A))},onBranchSwitch:async(c,E)=>{await gn(c,E),await I(c),A=await Mt(c),a.loadGraph(A),ee.setLearningGraphData(A),G.setData(A),await C(c)},onBranchCreate:async(c,E)=>{await fn(c,E),await I(c)},onBranchDelete:async(c,E)=>{await ao(c,E),await I(c)},onSnippetLoad:async(c,E)=>{var Y;const R=await po(c,E);((Y=R==null?void 0:R.nodeIds)==null?void 0:Y.length)>0&&a.enterFocus(R.nodeIds,0)},onSnippetDelete:async(c,E)=>{await uo(c,E),await B(c)},onBackpackSwitch:async c=>{await fetch("/api/backpacks/switch",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({name:c})}),await w()},onBackpackRegister:async(c,E)=>{await fetch("/api/backpacks",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({path:c,activate:E})}),await w()}});async function w(){try{const E=await(await fetch("/api/backpacks")).json();S.setBackpacks(E)}catch{}try{const c=await vt();S.setSummaries(c),ce&&!c.some(E=>E.name===ce)&&(ce="",A=null,a.loadGraph({metadata:{name:"",description:"",createdAt:"",updatedAt:""},nodes:[],edges:[]}))}catch{}}function N(){const c=a.getWalkTrail();if(!A||c.length===0){G.setWalkTrail([]),U();return}const E=[],R=c.map((Y,ne)=>{const ae=A.nodes.find(he=>he.id===Y);let pe;if(ne>0){const he=c[ne-1],we=A.edges.find(Le=>Le.sourceId===he&&Le.targetId===Y||Le.targetId===he&&Le.sourceId===Y);pe=we==null?void 0:we.type,we&&E.push(we.id)}return{id:Y,label:ae?Object.values(ae.properties).find(he=>typeof he=="string")??ae.id:Y,type:(ae==null?void 0:ae.type)??"?",edgeType:pe}});G.setWalkTrail(R),c.length>=2?(a.setHighlightedPath(c,E),ue({nodeIds:c,edgeIds:E})):U()}async function I(c){const E=await so(c),R=E.find(Y=>Y.active);R&&S.setActiveBranch(c,R.name,E)}async function C(c){const E=await co(c);G.setSnapshots(E)}async function B(c){const E=await ro(c);S.setSnippets(c,E)}Ce.insertBefore(S.expandBtn,Ce.firstChild);const $=es(t,s),te=ts(t),ie=ss(t,{onStar(c){if(!A)return;const E=A.nodes.find(Y=>Y.id===c);if(!E)return;const R=E.properties._starred===!0;E.properties._starred=!R,Ot(ce,A),a.loadGraph(A)},onFocusNode(c){G.addToFocusSet([c])},onExploreInBranch(c){if(ce){const E=`explore-${c.slice(0,8)}`;fn(ce,E).then(()=>{gn(ce,E).then(()=>{a.enterFocus([c],1)})})}},onCopyId(c){navigator.clipboard.writeText(c)}});t.addEventListener("contextmenu",c=>{c.preventDefault();const E=t.querySelector("canvas");if(!E||!A)return;const R=E.getBoundingClientRect(),Y=c.clientX-R.left,ne=c.clientY-R.top,ae=a.nodeAtScreen(Y,ne);if(!ae)return;const pe=A.nodes.find(Le=>Le.id===ae.id);if(!pe)return;const he=Object.values(pe.properties).find(Le=>typeof Le=="string")??pe.id,we=pe.properties._starred===!0;ie.show(pe.id,he,we,c.clientX-R.left,c.clientY-R.top)}),e.display.edges||a.setEdges(!1),e.display.edgeLabels||a.setEdgeLabels(!1),e.display.typeHulls||a.setTypeHulls(!1),e.display.minimap||a.setMinimap(!1);function le(c,E){const R=[];E!=null&&E.length&&R.push("node="+E.map(encodeURIComponent).join(","));const Y=a.getFocusInfo();Y&&(R.push("focus="+Y.seedNodeIds.map(encodeURIComponent).join(",")),R.push("hops="+Y.hops));const ne="#"+encodeURIComponent(c)+(R.length?"?"+R.join("&"):"");history.replaceState(null,"",ne)}function me(){const c=window.location.hash.slice(1);if(!c)return{graph:null,nodes:[],focus:[],hops:1};const[E,R]=c.split("?"),Y=E?decodeURIComponent(E):null;let ne=[],ae=[],pe=1;if(R){const he=new URLSearchParams(R),we=he.get("node");we&&(ne=we.split(",").map(decodeURIComponent));const Le=he.get("focus");Le&&(ae=Le.split(",").map(decodeURIComponent));const De=he.get("hops");De&&(pe=Math.max(0,parseInt(De,10)||1))}return{graph:Y,nodes:ne,focus:ae,hops:pe}}async function ve(c,E,R,Y){ce=c,Xt=qt.has(c),S.setActive(c),T.hide(),K(),ee.clear(),n.clear(),A=Xt?await no(c):await Mt(c);const ne=xo(A.nodes.length);if(lt({spacing:Math.max(e.layout.spacing,ne.spacing),clusterStrength:Math.max(e.layout.clustering,ne.clusterStrength)}),a.loadGraph(A),ee.setLearningGraphData(A),G.setData(A),te.hide(),le(c),xe(),de.emit("graph-switched"),de.emit("graph-changed"),Xt||(await I(c),await C(c),await B(c)),R!=null&&R.length&&A){const ae=R.filter(pe=>A.nodes.some(he=>he.id===pe));if(ae.length){setTimeout(()=>{a.enterFocus(ae,Y??1)},500);return}}if(E!=null&&E.length&&A){const ae=E.filter(pe=>A.nodes.some(he=>he.id===pe));ae.length&&setTimeout(()=>{a.panToNodes(ae),A&&T.show(ae,A),le(c,ae)},500)}}try{const E=await(await fetch("/api/backpacks")).json();S.setBackpacks(E)}catch{}fetch("/api/version-check").then(c=>c.json()).then(c=>{c.stale&&c.latest&&S.setStaleVersionBanner(c.current,c.latest)}).catch(()=>{});const qe=new URLSearchParams(window.location.search).get("share");if(qe)try{const c=await fetch(`/v1/share/${qe}/meta`);if(!c.ok)throw new Error("Share link not found or expired");const E=await c.json(),R=await fetch(`/v1/share/${qe}`);if(!R.ok)throw new Error("Failed to download shared backpack");const Y=new Uint8Array(await R.arrayBuffer());if(Y.length<9||Y[0]!==66||Y[1]!==80||Y[2]!==65||Y[3]!==75)throw new Error("Invalid share data: not a BPAK envelope");const ne=new DataView(Y.buffer,Y.byteOffset,Y.byteLength).getUint32(5,!1);if(9+ne>Y.length)throw new Error("Invalid envelope: header length exceeds data");const ae=JSON.parse(new TextDecoder().decode(Y.slice(9,9+ne))),pe=Y.slice(9+ne);let he;if(ae.format!=="plaintext"){const we=window.location.hash.slice(1),Le=new URLSearchParams(we).get("k")??we.split("k=")[1];if(!Le)throw new Error("Missing decryption key in URL fragment");const{Decrypter:De}=await eo(async()=>{const{Decrypter:Oe}=await import("./index-D-H7agBH.js");return{Decrypter:Oe}},[]),tt=atob(Le.replace(/-/g,"+").replace(/_/g,"/")),ht=new De;ht.addIdentity(tt);const kt=await ht.decrypt(pe);he=JSON.parse(new TextDecoder().decode(kt))}else he=JSON.parse(new TextDecoder().decode(pe));ce=E.backpack_name||"Shared Backpack",A=he,a.loadGraph(he),ee.setLearningGraphData(he),S.setSummaries([{name:ce,description:"",nodeCount:((ut=he.nodes)==null?void 0:ut.length)??0,edgeCount:((mt=he.edges)==null?void 0:mt.length)??0,nodeTypes:[]}]),S.setActive(ce),document.title=`${ce} — Backpack`}catch(c){const E=c instanceof Error?c.message:"Failed to load shared backpack";wt(E,5e3),te.show()}else{const[c,E]=await Promise.all([vt(),to().catch(()=>[])]);S.setSummaries(c),S.setRemotes(E),qt=new Set(E.map(ne=>ne.name));const R=me(),Y=R.graph&&c.some(ne=>ne.name===R.graph)||R.graph&&qt.has(R.graph)?R.graph:c.length>0?c[0].name:E.length>0?E[0].name:null;Y?await ve(Y,R.nodes.length?R.nodes:void 0,R.focus.length?R.focus:void 0,R.hops):te.show()}ms({getGraph:()=>A,getGraphName:()=>ce,getSelection:()=>[...F],getFocus:()=>a.getFocusInfo(),saveCurrentGraph:async()=>{await g()},snapshotForUndo:()=>{A&&n.push(A)},panToNode:c=>a.panToNode(c),focusNodes:(c,E)=>a.enterFocus(c,E),exitFocus:()=>{a.isFocused()&&a.exitFocus()},taskbarSlots:{topLeft:y,topRight:m,bottomLeft:L,bottomRight:h},subscribe:(c,E)=>de.subscribe(c,E)},M).catch(c=>{console.error("[backpack-viewer] extension loader failed:",c)});const Je={search(){ee.focus()},searchAlt(){ee.focus()},undo(){if(A){const c=n.undo(A);c&&i(c)}},redo(){if(A){const c=n.redo(A);c&&i(c)}},focus(){a.isFocused()?G.clearFocusSet():F.length>0&&G.addToFocusSet(F)},hopsDecrease(){const c=a.getFocusInfo();c&&c.hops>0&&a.enterFocus(c.seedNodeIds,c.hops-1)},hopsIncrease(){const c=a.getFocusInfo();c&&a.enterFocus(c.seedNodeIds,c.hops+1)},nextNode(){const c=a.getNodeIds();c.length>0&&(z=(z+1)%c.length,a.panToNode(c[z]),A&&T.show([c[z]],A))},prevNode(){const c=a.getNodeIds();c.length>0&&(z=z<=0?c.length-1:z-1,a.panToNode(c[z]),A&&T.show([c[z]],A))},nextConnection(){const c=T.cycleConnection(1);c&&a.panToNode(c)},prevConnection(){const c=T.cycleConnection(-1);c&&a.panToNode(c)},historyBack(){T.goBack()},historyForward(){T.goForward()},center(){a.centerView()},toggleEdges(){W=!W,a.setEdges(W)},panLeft(){a.panBy(-V,0)},panDown(){a.panBy(0,V)},panUp(){a.panBy(0,-V)},panRight(){a.panBy(V,0)},panFastLeft(){a.panBy(-V*e.navigation.panFastMultiplier,0)},zoomOut(){a.zoomBy(1/e.navigation.zoomFactor)},zoomIn(){a.zoomBy(e.navigation.zoomFactor)},panFastRight(){a.panBy(V*e.navigation.panFastMultiplier,0)},spacingDecrease(){const c=Et();lt({spacing:Math.max(.5,c.spacing-.5)}),a.reheat()},spacingIncrease(){const c=Et();lt({spacing:Math.min(20,c.spacing+.5)}),a.reheat()},clusteringDecrease(){const c=Et();lt({clusterStrength:Math.max(0,c.clusterStrength-.03)}),a.reheat()},clusteringIncrease(){const c=Et();lt({clusterStrength:Math.min(1,c.clusterStrength+.03)}),a.reheat()},help(){$.toggle()},toggleSidebar(){S.toggle()},resetPins(){a.releaseAllPins()&&wt("Manual layout reset — pins released")},walkIsolate(){if(!A)return;const c=a.getWalkTrail();c.length!==0&&a.enterFocus(c,0)},walkMode(){!a.isFocused()&&F.length>0&&G.addToFocusSet(F),a.setWalkMode(!a.getWalkMode());const c=t.querySelector(".walk-indicator");c&&c.classList.toggle("active",a.getWalkMode()),N()},escape(){a.getSelectedNodeIds().length>0?a.clearSelection():a.isFocused()?G.clearFocusSet():$.hide()}};document.addEventListener("keydown",c=>{var E;if(!(c.target instanceof HTMLInputElement||c.target instanceof HTMLTextAreaElement)){for(const[R,Y]of Object.entries(s))if(Vo(c,Y)){(R==="search"||R==="searchAlt"||R==="undo"||R==="redo"||R==="toggleSidebar")&&c.preventDefault(),(E=Je[R])==null||E.call(Je);return}}}),window.addEventListener("hashchange",()=>{const c=me();if(c.graph&&c.graph!==ce)ve(c.graph,c.nodes.length?c.nodes:void 0,c.focus.length?c.focus:void 0,c.hops);else if(c.graph&&c.focus.length&&A)a.enterFocus(c.focus,c.hops);else if(c.graph&&c.nodes.length&&A){a.isFocused()&&a.exitFocus();const E=c.nodes.filter(R=>A.nodes.some(Y=>Y.id===R));E.length&&(a.panToNodes(E),T.show(E,A))}})}Ss();