/*
THIS IS A GENERATED/BUNDLED FILE BY ESBUILD
if you want to view the source, please visit the github repository of this plugin
*/

"use strict";
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
  for (var name in all)
    __defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
  if (from && typeof from === "object" || typeof from === "function") {
    for (let key of __getOwnPropNames(from))
      if (!__hasOwnProp.call(to, key) && key !== except)
        __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
  }
  return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var __toBinary = /* @__PURE__ */ (() => {
  var table = new Uint8Array(128);
  for (var i = 0; i < 64; i++) table[i < 26 ? i + 65 : i < 52 ? i + 71 : i < 62 ? i - 4 : i * 4 - 205] = i;
  return (base64) => {
    var n = base64.length, bytes = new Uint8Array((n - (base64[n - 1] == "=") - (base64[n - 2] == "=")) * 3 / 4 | 0);
    for (var i2 = 0, j = 0; i2 < n; ) {
      var c0 = table[base64.charCodeAt(i2++)], c1 = table[base64.charCodeAt(i2++)];
      var c22 = table[base64.charCodeAt(i2++)], c32 = table[base64.charCodeAt(i2++)];
      bytes[j++] = c0 << 2 | c1 >> 4;
      bytes[j++] = c1 << 4 | c22 >> 2;
      bytes[j++] = c22 << 6 | c32;
    }
    return bytes;
  };
})();

// src/main.ts
var main_exports = {};
__export(main_exports, {
  default: () => GraphAnalysisPlugin
});
module.exports = __toCommonJS(main_exports);
var import_obsidian18 = require("obsidian");

// src/types/types.ts
var DEFAULT_SETTINGS = {
  excludeFolders: [],
  excludeTags: [],
  geminiApiKey: "",
  aiResponseLanguage: "auto",
  uiLanguage: "auto"
};

// src/views/GraphAnalysisView.ts
var import_obsidian14 = require("obsidian");

// src/components/graph-view/GraphView.ts
var import_obsidian13 = require("obsidian");

// node_modules/d3-array/src/ascending.js
function ascending(a2, b) {
  return a2 == null || b == null ? NaN : a2 < b ? -1 : a2 > b ? 1 : a2 >= b ? 0 : NaN;
}

// node_modules/d3-array/src/descending.js
function descending(a2, b) {
  return a2 == null || b == null ? NaN : b < a2 ? -1 : b > a2 ? 1 : b >= a2 ? 0 : NaN;
}

// node_modules/d3-array/src/bisector.js
function bisector(f) {
  let compare1, compare2, delta;
  if (f.length !== 2) {
    compare1 = ascending;
    compare2 = (d, x3) => ascending(f(d), x3);
    delta = (d, x3) => f(d) - x3;
  } else {
    compare1 = f === ascending || f === descending ? f : zero;
    compare2 = f;
    delta = f;
  }
  function left2(a2, x3, lo = 0, hi = a2.length) {
    if (lo < hi) {
      if (compare1(x3, x3) !== 0) return hi;
      do {
        const mid = lo + hi >>> 1;
        if (compare2(a2[mid], x3) < 0) lo = mid + 1;
        else hi = mid;
      } while (lo < hi);
    }
    return lo;
  }
  function right2(a2, x3, lo = 0, hi = a2.length) {
    if (lo < hi) {
      if (compare1(x3, x3) !== 0) return hi;
      do {
        const mid = lo + hi >>> 1;
        if (compare2(a2[mid], x3) <= 0) lo = mid + 1;
        else hi = mid;
      } while (lo < hi);
    }
    return lo;
  }
  function center2(a2, x3, lo = 0, hi = a2.length) {
    const i = left2(a2, x3, lo, hi - 1);
    return i > lo && delta(a2[i - 1], x3) > -delta(a2[i], x3) ? i - 1 : i;
  }
  return { left: left2, center: center2, right: right2 };
}
function zero() {
  return 0;
}

// node_modules/d3-array/src/number.js
function number(x3) {
  return x3 === null ? NaN : +x3;
}

// node_modules/d3-array/src/bisect.js
var ascendingBisect = bisector(ascending);
var bisectRight = ascendingBisect.right;
var bisectLeft = ascendingBisect.left;
var bisectCenter = bisector(number).center;
var bisect_default = bisectRight;

// node_modules/internmap/src/index.js
var InternMap = class extends Map {
  constructor(entries, key = keyof) {
    super();
    Object.defineProperties(this, { _intern: { value: /* @__PURE__ */ new Map() }, _key: { value: key } });
    if (entries != null) for (const [key2, value] of entries) this.set(key2, value);
  }
  get(key) {
    return super.get(intern_get(this, key));
  }
  has(key) {
    return super.has(intern_get(this, key));
  }
  set(key, value) {
    return super.set(intern_set(this, key), value);
  }
  delete(key) {
    return super.delete(intern_delete(this, key));
  }
};
function intern_get({ _intern, _key }, value) {
  const key = _key(value);
  return _intern.has(key) ? _intern.get(key) : value;
}
function intern_set({ _intern, _key }, value) {
  const key = _key(value);
  if (_intern.has(key)) return _intern.get(key);
  _intern.set(key, value);
  return value;
}
function intern_delete({ _intern, _key }, value) {
  const key = _key(value);
  if (_intern.has(key)) {
    value = _intern.get(key);
    _intern.delete(key);
  }
  return value;
}
function keyof(value) {
  return value !== null && typeof value === "object" ? value.valueOf() : value;
}

// node_modules/d3-array/src/ticks.js
var e10 = Math.sqrt(50);
var e5 = Math.sqrt(10);
var e2 = Math.sqrt(2);
function tickSpec(start2, stop, count2) {
  const step = (stop - start2) / Math.max(0, count2), power = Math.floor(Math.log10(step)), error = step / Math.pow(10, power), factor = error >= e10 ? 10 : error >= e5 ? 5 : error >= e2 ? 2 : 1;
  let i1, i2, inc;
  if (power < 0) {
    inc = Math.pow(10, -power) / factor;
    i1 = Math.round(start2 * inc);
    i2 = Math.round(stop * inc);
    if (i1 / inc < start2) ++i1;
    if (i2 / inc > stop) --i2;
    inc = -inc;
  } else {
    inc = Math.pow(10, power) * factor;
    i1 = Math.round(start2 / inc);
    i2 = Math.round(stop / inc);
    if (i1 * inc < start2) ++i1;
    if (i2 * inc > stop) --i2;
  }
  if (i2 < i1 && 0.5 <= count2 && count2 < 2) return tickSpec(start2, stop, count2 * 2);
  return [i1, i2, inc];
}
function ticks(start2, stop, count2) {
  stop = +stop, start2 = +start2, count2 = +count2;
  if (!(count2 > 0)) return [];
  if (start2 === stop) return [start2];
  const reverse = stop < start2, [i1, i2, inc] = reverse ? tickSpec(stop, start2, count2) : tickSpec(start2, stop, count2);
  if (!(i2 >= i1)) return [];
  const n = i2 - i1 + 1, ticks2 = new Array(n);
  if (reverse) {
    if (inc < 0) for (let i = 0; i < n; ++i) ticks2[i] = (i2 - i) / -inc;
    else for (let i = 0; i < n; ++i) ticks2[i] = (i2 - i) * inc;
  } else {
    if (inc < 0) for (let i = 0; i < n; ++i) ticks2[i] = (i1 + i) / -inc;
    else for (let i = 0; i < n; ++i) ticks2[i] = (i1 + i) * inc;
  }
  return ticks2;
}
function tickIncrement(start2, stop, count2) {
  stop = +stop, start2 = +start2, count2 = +count2;
  return tickSpec(start2, stop, count2)[2];
}
function tickStep(start2, stop, count2) {
  stop = +stop, start2 = +start2, count2 = +count2;
  const reverse = stop < start2, inc = reverse ? tickIncrement(stop, start2, count2) : tickIncrement(start2, stop, count2);
  return (reverse ? -1 : 1) * (inc < 0 ? 1 / -inc : inc);
}

// node_modules/d3-array/src/range.js
function range(start2, stop, step) {
  start2 = +start2, stop = +stop, step = (n = arguments.length) < 2 ? (stop = start2, start2 = 0, 1) : n < 3 ? 1 : +step;
  var i = -1, n = Math.max(0, Math.ceil((stop - start2) / step)) | 0, range2 = new Array(n);
  while (++i < n) {
    range2[i] = start2 + i * step;
  }
  return range2;
}

// node_modules/d3-axis/src/identity.js
function identity_default(x3) {
  return x3;
}

// node_modules/d3-axis/src/axis.js
var top = 1;
var right = 2;
var bottom = 3;
var left = 4;
var epsilon = 1e-6;
function translateX(x3) {
  return "translate(" + x3 + ",0)";
}
function translateY(y3) {
  return "translate(0," + y3 + ")";
}
function number2(scale) {
  return (d) => +scale(d);
}
function center(scale, offset) {
  offset = Math.max(0, scale.bandwidth() - offset * 2) / 2;
  if (scale.round()) offset = Math.round(offset);
  return (d) => +scale(d) + offset;
}
function entering() {
  return !this.__axis;
}
function axis(orient, scale) {
  var tickArguments = [], tickValues = null, tickFormat2 = null, tickSizeInner = 6, tickSizeOuter = 6, tickPadding = 3, offset = typeof window !== "undefined" && window.devicePixelRatio > 1 ? 0 : 0.5, k = orient === top || orient === left ? -1 : 1, x3 = orient === left || orient === right ? "x" : "y", transform2 = orient === top || orient === bottom ? translateX : translateY;
  function axis2(context) {
    var values = tickValues == null ? scale.ticks ? scale.ticks.apply(scale, tickArguments) : scale.domain() : tickValues, format2 = tickFormat2 == null ? scale.tickFormat ? scale.tickFormat.apply(scale, tickArguments) : identity_default : tickFormat2, spacing = Math.max(tickSizeInner, 0) + tickPadding, range2 = scale.range(), range0 = +range2[0] + offset, range1 = +range2[range2.length - 1] + offset, position = (scale.bandwidth ? center : number2)(scale.copy(), offset), selection2 = context.selection ? context.selection() : context, path2 = selection2.selectAll(".domain").data([null]), tick = selection2.selectAll(".tick").data(values, scale).order(), tickExit = tick.exit(), tickEnter = tick.enter().append("g").attr("class", "tick"), line = tick.select("line"), text = tick.select("text");
    path2 = path2.merge(path2.enter().insert("path", ".tick").attr("class", "domain").attr("stroke", "currentColor"));
    tick = tick.merge(tickEnter);
    line = line.merge(tickEnter.append("line").attr("stroke", "currentColor").attr(x3 + "2", k * tickSizeInner));
    text = text.merge(tickEnter.append("text").attr("fill", "currentColor").attr(x3, k * spacing).attr("dy", orient === top ? "0em" : orient === bottom ? "0.71em" : "0.32em"));
    if (context !== selection2) {
      path2 = path2.transition(context);
      tick = tick.transition(context);
      line = line.transition(context);
      text = text.transition(context);
      tickExit = tickExit.transition(context).attr("opacity", epsilon).attr("transform", function(d) {
        return isFinite(d = position(d)) ? transform2(d + offset) : this.getAttribute("transform");
      });
      tickEnter.attr("opacity", epsilon).attr("transform", function(d) {
        var p = this.parentNode.__axis;
        return transform2((p && isFinite(p = p(d)) ? p : position(d)) + offset);
      });
    }
    tickExit.remove();
    path2.attr("d", orient === left || orient === right ? tickSizeOuter ? "M" + k * tickSizeOuter + "," + range0 + "H" + offset + "V" + range1 + "H" + k * tickSizeOuter : "M" + offset + "," + range0 + "V" + range1 : tickSizeOuter ? "M" + range0 + "," + k * tickSizeOuter + "V" + offset + "H" + range1 + "V" + k * tickSizeOuter : "M" + range0 + "," + offset + "H" + range1);
    tick.attr("opacity", 1).attr("transform", function(d) {
      return transform2(position(d) + offset);
    });
    line.attr(x3 + "2", k * tickSizeInner);
    text.attr(x3, k * spacing).text(format2);
    selection2.filter(entering).attr("fill", "none").attr("font-size", 10).attr("font-family", "sans-serif").attr("text-anchor", orient === right ? "start" : orient === left ? "end" : "middle");
    selection2.each(function() {
      this.__axis = position;
    });
  }
  axis2.scale = function(_) {
    return arguments.length ? (scale = _, axis2) : scale;
  };
  axis2.ticks = function() {
    return tickArguments = Array.from(arguments), axis2;
  };
  axis2.tickArguments = function(_) {
    return arguments.length ? (tickArguments = _ == null ? [] : Array.from(_), axis2) : tickArguments.slice();
  };
  axis2.tickValues = function(_) {
    return arguments.length ? (tickValues = _ == null ? null : Array.from(_), axis2) : tickValues && tickValues.slice();
  };
  axis2.tickFormat = function(_) {
    return arguments.length ? (tickFormat2 = _, axis2) : tickFormat2;
  };
  axis2.tickSize = function(_) {
    return arguments.length ? (tickSizeInner = tickSizeOuter = +_, axis2) : tickSizeInner;
  };
  axis2.tickSizeInner = function(_) {
    return arguments.length ? (tickSizeInner = +_, axis2) : tickSizeInner;
  };
  axis2.tickSizeOuter = function(_) {
    return arguments.length ? (tickSizeOuter = +_, axis2) : tickSizeOuter;
  };
  axis2.tickPadding = function(_) {
    return arguments.length ? (tickPadding = +_, axis2) : tickPadding;
  };
  axis2.offset = function(_) {
    return arguments.length ? (offset = +_, axis2) : offset;
  };
  return axis2;
}
function axisBottom(scale) {
  return axis(bottom, scale);
}
function axisLeft(scale) {
  return axis(left, scale);
}

// node_modules/d3-dispatch/src/dispatch.js
var noop = { value: () => {
} };
function dispatch() {
  for (var i = 0, n = arguments.length, _ = {}, t2; i < n; ++i) {
    if (!(t2 = arguments[i] + "") || t2 in _ || /[\s.]/.test(t2)) throw new Error("illegal type: " + t2);
    _[t2] = [];
  }
  return new Dispatch(_);
}
function Dispatch(_) {
  this._ = _;
}
function parseTypenames(typenames, types) {
  return typenames.trim().split(/^|\s+/).map(function(t2) {
    var name = "", i = t2.indexOf(".");
    if (i >= 0) name = t2.slice(i + 1), t2 = t2.slice(0, i);
    if (t2 && !types.hasOwnProperty(t2)) throw new Error("unknown type: " + t2);
    return { type: t2, name };
  });
}
Dispatch.prototype = dispatch.prototype = {
  constructor: Dispatch,
  on: function(typename, callback) {
    var _ = this._, T = parseTypenames(typename + "", _), t2, i = -1, n = T.length;
    if (arguments.length < 2) {
      while (++i < n) if ((t2 = (typename = T[i]).type) && (t2 = get(_[t2], typename.name))) return t2;
      return;
    }
    if (callback != null && typeof callback !== "function") throw new Error("invalid callback: " + callback);
    while (++i < n) {
      if (t2 = (typename = T[i]).type) _[t2] = set(_[t2], typename.name, callback);
      else if (callback == null) for (t2 in _) _[t2] = set(_[t2], typename.name, null);
    }
    return this;
  },
  copy: function() {
    var copy2 = {}, _ = this._;
    for (var t2 in _) copy2[t2] = _[t2].slice();
    return new Dispatch(copy2);
  },
  call: function(type2, that) {
    if ((n = arguments.length - 2) > 0) for (var args = new Array(n), i = 0, n, t2; i < n; ++i) args[i] = arguments[i + 2];
    if (!this._.hasOwnProperty(type2)) throw new Error("unknown type: " + type2);
    for (t2 = this._[type2], i = 0, n = t2.length; i < n; ++i) t2[i].value.apply(that, args);
  },
  apply: function(type2, that, args) {
    if (!this._.hasOwnProperty(type2)) throw new Error("unknown type: " + type2);
    for (var t2 = this._[type2], i = 0, n = t2.length; i < n; ++i) t2[i].value.apply(that, args);
  }
};
function get(type2, name) {
  for (var i = 0, n = type2.length, c4; i < n; ++i) {
    if ((c4 = type2[i]).name === name) {
      return c4.value;
    }
  }
}
function set(type2, name, callback) {
  for (var i = 0, n = type2.length; i < n; ++i) {
    if (type2[i].name === name) {
      type2[i] = noop, type2 = type2.slice(0, i).concat(type2.slice(i + 1));
      break;
    }
  }
  if (callback != null) type2.push({ name, value: callback });
  return type2;
}
var dispatch_default = dispatch;

// node_modules/d3-selection/src/namespaces.js
var xhtml = "http://www.w3.org/1999/xhtml";
var namespaces_default = {
  svg: "http://www.w3.org/2000/svg",
  xhtml,
  xlink: "http://www.w3.org/1999/xlink",
  xml: "http://www.w3.org/XML/1998/namespace",
  xmlns: "http://www.w3.org/2000/xmlns/"
};

// node_modules/d3-selection/src/namespace.js
function namespace_default(name) {
  var prefix = name += "", i = prefix.indexOf(":");
  if (i >= 0 && (prefix = name.slice(0, i)) !== "xmlns") name = name.slice(i + 1);
  return namespaces_default.hasOwnProperty(prefix) ? { space: namespaces_default[prefix], local: name } : name;
}

// node_modules/d3-selection/src/creator.js
function creatorInherit(name) {
  return function() {
    var document2 = this.ownerDocument, uri = this.namespaceURI;
    return uri === xhtml && document2.documentElement.namespaceURI === xhtml ? document2.createElement(name) : document2.createElementNS(uri, name);
  };
}
function creatorFixed(fullname) {
  return function() {
    return this.ownerDocument.createElementNS(fullname.space, fullname.local);
  };
}
function creator_default(name) {
  var fullname = namespace_default(name);
  return (fullname.local ? creatorFixed : creatorInherit)(fullname);
}

// node_modules/d3-selection/src/selector.js
function none() {
}
function selector_default(selector) {
  return selector == null ? none : function() {
    return this.querySelector(selector);
  };
}

// node_modules/d3-selection/src/selection/select.js
function select_default(select) {
  if (typeof select !== "function") select = selector_default(select);
  for (var groups = this._groups, m2 = groups.length, subgroups = new Array(m2), j = 0; j < m2; ++j) {
    for (var group = groups[j], n = group.length, subgroup = subgroups[j] = new Array(n), node, subnode, i = 0; i < n; ++i) {
      if ((node = group[i]) && (subnode = select.call(node, node.__data__, i, group))) {
        if ("__data__" in node) subnode.__data__ = node.__data__;
        subgroup[i] = subnode;
      }
    }
  }
  return new Selection(subgroups, this._parents);
}

// node_modules/d3-selection/src/array.js
function array(x3) {
  return x3 == null ? [] : Array.isArray(x3) ? x3 : Array.from(x3);
}

// node_modules/d3-selection/src/selectorAll.js
function empty() {
  return [];
}
function selectorAll_default(selector) {
  return selector == null ? empty : function() {
    return this.querySelectorAll(selector);
  };
}

// node_modules/d3-selection/src/selection/selectAll.js
function arrayAll(select) {
  return function() {
    return array(select.apply(this, arguments));
  };
}
function selectAll_default(select) {
  if (typeof select === "function") select = arrayAll(select);
  else select = selectorAll_default(select);
  for (var groups = this._groups, m2 = groups.length, subgroups = [], parents = [], j = 0; j < m2; ++j) {
    for (var group = groups[j], n = group.length, node, i = 0; i < n; ++i) {
      if (node = group[i]) {
        subgroups.push(select.call(node, node.__data__, i, group));
        parents.push(node);
      }
    }
  }
  return new Selection(subgroups, parents);
}

// node_modules/d3-selection/src/matcher.js
function matcher_default(selector) {
  return function() {
    return this.matches(selector);
  };
}
function childMatcher(selector) {
  return function(node) {
    return node.matches(selector);
  };
}

// node_modules/d3-selection/src/selection/selectChild.js
var find = Array.prototype.find;
function childFind(match) {
  return function() {
    return find.call(this.children, match);
  };
}
function childFirst() {
  return this.firstElementChild;
}
function selectChild_default(match) {
  return this.select(match == null ? childFirst : childFind(typeof match === "function" ? match : childMatcher(match)));
}

// node_modules/d3-selection/src/selection/selectChildren.js
var filter = Array.prototype.filter;
function children() {
  return Array.from(this.children);
}
function childrenFilter(match) {
  return function() {
    return filter.call(this.children, match);
  };
}
function selectChildren_default(match) {
  return this.selectAll(match == null ? children : childrenFilter(typeof match === "function" ? match : childMatcher(match)));
}

// node_modules/d3-selection/src/selection/filter.js
function filter_default(match) {
  if (typeof match !== "function") match = matcher_default(match);
  for (var groups = this._groups, m2 = groups.length, subgroups = new Array(m2), j = 0; j < m2; ++j) {
    for (var group = groups[j], n = group.length, subgroup = subgroups[j] = [], node, i = 0; i < n; ++i) {
      if ((node = group[i]) && match.call(node, node.__data__, i, group)) {
        subgroup.push(node);
      }
    }
  }
  return new Selection(subgroups, this._parents);
}

// node_modules/d3-selection/src/selection/sparse.js
function sparse_default(update) {
  return new Array(update.length);
}

// node_modules/d3-selection/src/selection/enter.js
function enter_default() {
  return new Selection(this._enter || this._groups.map(sparse_default), this._parents);
}
function EnterNode(parent, datum2) {
  this.ownerDocument = parent.ownerDocument;
  this.namespaceURI = parent.namespaceURI;
  this._next = null;
  this._parent = parent;
  this.__data__ = datum2;
}
EnterNode.prototype = {
  constructor: EnterNode,
  appendChild: function(child) {
    return this._parent.insertBefore(child, this._next);
  },
  insertBefore: function(child, next) {
    return this._parent.insertBefore(child, next);
  },
  querySelector: function(selector) {
    return this._parent.querySelector(selector);
  },
  querySelectorAll: function(selector) {
    return this._parent.querySelectorAll(selector);
  }
};

// node_modules/d3-selection/src/constant.js
function constant_default(x3) {
  return function() {
    return x3;
  };
}

// node_modules/d3-selection/src/selection/data.js
function bindIndex(parent, group, enter, update, exit, data) {
  var i = 0, node, groupLength = group.length, dataLength = data.length;
  for (; i < dataLength; ++i) {
    if (node = group[i]) {
      node.__data__ = data[i];
      update[i] = node;
    } else {
      enter[i] = new EnterNode(parent, data[i]);
    }
  }
  for (; i < groupLength; ++i) {
    if (node = group[i]) {
      exit[i] = node;
    }
  }
}
function bindKey(parent, group, enter, update, exit, data, key) {
  var i, node, nodeByKeyValue = /* @__PURE__ */ new Map(), groupLength = group.length, dataLength = data.length, keyValues = new Array(groupLength), keyValue;
  for (i = 0; i < groupLength; ++i) {
    if (node = group[i]) {
      keyValues[i] = keyValue = key.call(node, node.__data__, i, group) + "";
      if (nodeByKeyValue.has(keyValue)) {
        exit[i] = node;
      } else {
        nodeByKeyValue.set(keyValue, node);
      }
    }
  }
  for (i = 0; i < dataLength; ++i) {
    keyValue = key.call(parent, data[i], i, data) + "";
    if (node = nodeByKeyValue.get(keyValue)) {
      update[i] = node;
      node.__data__ = data[i];
      nodeByKeyValue.delete(keyValue);
    } else {
      enter[i] = new EnterNode(parent, data[i]);
    }
  }
  for (i = 0; i < groupLength; ++i) {
    if ((node = group[i]) && nodeByKeyValue.get(keyValues[i]) === node) {
      exit[i] = node;
    }
  }
}
function datum(node) {
  return node.__data__;
}
function data_default(value, key) {
  if (!arguments.length) return Array.from(this, datum);
  var bind = key ? bindKey : bindIndex, parents = this._parents, groups = this._groups;
  if (typeof value !== "function") value = constant_default(value);
  for (var m2 = groups.length, update = new Array(m2), enter = new Array(m2), exit = new Array(m2), j = 0; j < m2; ++j) {
    var parent = parents[j], group = groups[j], groupLength = group.length, data = arraylike(value.call(parent, parent && parent.__data__, j, parents)), dataLength = data.length, enterGroup = enter[j] = new Array(dataLength), updateGroup = update[j] = new Array(dataLength), exitGroup = exit[j] = new Array(groupLength);
    bind(parent, group, enterGroup, updateGroup, exitGroup, data, key);
    for (var i0 = 0, i1 = 0, previous, next; i0 < dataLength; ++i0) {
      if (previous = enterGroup[i0]) {
        if (i0 >= i1) i1 = i0 + 1;
        while (!(next = updateGroup[i1]) && ++i1 < dataLength) ;
        previous._next = next || null;
      }
    }
  }
  update = new Selection(update, parents);
  update._enter = enter;
  update._exit = exit;
  return update;
}
function arraylike(data) {
  return typeof data === "object" && "length" in data ? data : Array.from(data);
}

// node_modules/d3-selection/src/selection/exit.js
function exit_default() {
  return new Selection(this._exit || this._groups.map(sparse_default), this._parents);
}

// node_modules/d3-selection/src/selection/join.js
function join_default(onenter, onupdate, onexit) {
  var enter = this.enter(), update = this, exit = this.exit();
  if (typeof onenter === "function") {
    enter = onenter(enter);
    if (enter) enter = enter.selection();
  } else {
    enter = enter.append(onenter + "");
  }
  if (onupdate != null) {
    update = onupdate(update);
    if (update) update = update.selection();
  }
  if (onexit == null) exit.remove();
  else onexit(exit);
  return enter && update ? enter.merge(update).order() : update;
}

// node_modules/d3-selection/src/selection/merge.js
function merge_default(context) {
  var selection2 = context.selection ? context.selection() : context;
  for (var groups0 = this._groups, groups1 = selection2._groups, m0 = groups0.length, m1 = groups1.length, m2 = Math.min(m0, m1), merges = new Array(m0), j = 0; j < m2; ++j) {
    for (var group0 = groups0[j], group1 = groups1[j], n = group0.length, merge = merges[j] = new Array(n), node, i = 0; i < n; ++i) {
      if (node = group0[i] || group1[i]) {
        merge[i] = node;
      }
    }
  }
  for (; j < m0; ++j) {
    merges[j] = groups0[j];
  }
  return new Selection(merges, this._parents);
}

// node_modules/d3-selection/src/selection/order.js
function order_default() {
  for (var groups = this._groups, j = -1, m2 = groups.length; ++j < m2; ) {
    for (var group = groups[j], i = group.length - 1, next = group[i], node; --i >= 0; ) {
      if (node = group[i]) {
        if (next && node.compareDocumentPosition(next) ^ 4) next.parentNode.insertBefore(node, next);
        next = node;
      }
    }
  }
  return this;
}

// node_modules/d3-selection/src/selection/sort.js
function sort_default(compare2) {
  if (!compare2) compare2 = ascending2;
  function compareNode(a2, b) {
    return a2 && b ? compare2(a2.__data__, b.__data__) : !a2 - !b;
  }
  for (var groups = this._groups, m2 = groups.length, sortgroups = new Array(m2), j = 0; j < m2; ++j) {
    for (var group = groups[j], n = group.length, sortgroup = sortgroups[j] = new Array(n), node, i = 0; i < n; ++i) {
      if (node = group[i]) {
        sortgroup[i] = node;
      }
    }
    sortgroup.sort(compareNode);
  }
  return new Selection(sortgroups, this._parents).order();
}
function ascending2(a2, b) {
  return a2 < b ? -1 : a2 > b ? 1 : a2 >= b ? 0 : NaN;
}

// node_modules/d3-selection/src/selection/call.js
function call_default() {
  var callback = arguments[0];
  arguments[0] = this;
  callback.apply(null, arguments);
  return this;
}

// node_modules/d3-selection/src/selection/nodes.js
function nodes_default() {
  return Array.from(this);
}

// node_modules/d3-selection/src/selection/node.js
function node_default() {
  for (var groups = this._groups, j = 0, m2 = groups.length; j < m2; ++j) {
    for (var group = groups[j], i = 0, n = group.length; i < n; ++i) {
      var node = group[i];
      if (node) return node;
    }
  }
  return null;
}

// node_modules/d3-selection/src/selection/size.js
function size_default() {
  let size = 0;
  for (const node of this) ++size;
  return size;
}

// node_modules/d3-selection/src/selection/empty.js
function empty_default() {
  return !this.node();
}

// node_modules/d3-selection/src/selection/each.js
function each_default(callback) {
  for (var groups = this._groups, j = 0, m2 = groups.length; j < m2; ++j) {
    for (var group = groups[j], i = 0, n = group.length, node; i < n; ++i) {
      if (node = group[i]) callback.call(node, node.__data__, i, group);
    }
  }
  return this;
}

// node_modules/d3-selection/src/selection/attr.js
function attrRemove(name) {
  return function() {
    this.removeAttribute(name);
  };
}
function attrRemoveNS(fullname) {
  return function() {
    this.removeAttributeNS(fullname.space, fullname.local);
  };
}
function attrConstant(name, value) {
  return function() {
    this.setAttribute(name, value);
  };
}
function attrConstantNS(fullname, value) {
  return function() {
    this.setAttributeNS(fullname.space, fullname.local, value);
  };
}
function attrFunction(name, value) {
  return function() {
    var v = value.apply(this, arguments);
    if (v == null) this.removeAttribute(name);
    else this.setAttribute(name, v);
  };
}
function attrFunctionNS(fullname, value) {
  return function() {
    var v = value.apply(this, arguments);
    if (v == null) this.removeAttributeNS(fullname.space, fullname.local);
    else this.setAttributeNS(fullname.space, fullname.local, v);
  };
}
function attr_default(name, value) {
  var fullname = namespace_default(name);
  if (arguments.length < 2) {
    var node = this.node();
    return fullname.local ? node.getAttributeNS(fullname.space, fullname.local) : node.getAttribute(fullname);
  }
  return this.each((value == null ? fullname.local ? attrRemoveNS : attrRemove : typeof value === "function" ? fullname.local ? attrFunctionNS : attrFunction : fullname.local ? attrConstantNS : attrConstant)(fullname, value));
}

// node_modules/d3-selection/src/window.js
function window_default(node) {
  return node.ownerDocument && node.ownerDocument.defaultView || node.document && node || node.defaultView;
}

// node_modules/d3-selection/src/selection/style.js
function styleRemove(name) {
  return function() {
    this.style.removeProperty(name);
  };
}
function styleConstant(name, value, priority) {
  return function() {
    this.style.setProperty(name, value, priority);
  };
}
function styleFunction(name, value, priority) {
  return function() {
    var v = value.apply(this, arguments);
    if (v == null) this.style.removeProperty(name);
    else this.style.setProperty(name, v, priority);
  };
}
function style_default(name, value, priority) {
  return arguments.length > 1 ? this.each((value == null ? styleRemove : typeof value === "function" ? styleFunction : styleConstant)(name, value, priority == null ? "" : priority)) : styleValue(this.node(), name);
}
function styleValue(node, name) {
  return node.style.getPropertyValue(name) || window_default(node).getComputedStyle(node, null).getPropertyValue(name);
}

// node_modules/d3-selection/src/selection/property.js
function propertyRemove(name) {
  return function() {
    delete this[name];
  };
}
function propertyConstant(name, value) {
  return function() {
    this[name] = value;
  };
}
function propertyFunction(name, value) {
  return function() {
    var v = value.apply(this, arguments);
    if (v == null) delete this[name];
    else this[name] = v;
  };
}
function property_default(name, value) {
  return arguments.length > 1 ? this.each((value == null ? propertyRemove : typeof value === "function" ? propertyFunction : propertyConstant)(name, value)) : this.node()[name];
}

// node_modules/d3-selection/src/selection/classed.js
function classArray(string) {
  return string.trim().split(/^|\s+/);
}
function classList(node) {
  return node.classList || new ClassList(node);
}
function ClassList(node) {
  this._node = node;
  this._names = classArray(node.getAttribute("class") || "");
}
ClassList.prototype = {
  add: function(name) {
    var i = this._names.indexOf(name);
    if (i < 0) {
      this._names.push(name);
      this._node.setAttribute("class", this._names.join(" "));
    }
  },
  remove: function(name) {
    var i = this._names.indexOf(name);
    if (i >= 0) {
      this._names.splice(i, 1);
      this._node.setAttribute("class", this._names.join(" "));
    }
  },
  contains: function(name) {
    return this._names.indexOf(name) >= 0;
  }
};
function classedAdd(node, names) {
  var list = classList(node), i = -1, n = names.length;
  while (++i < n) list.add(names[i]);
}
function classedRemove(node, names) {
  var list = classList(node), i = -1, n = names.length;
  while (++i < n) list.remove(names[i]);
}
function classedTrue(names) {
  return function() {
    classedAdd(this, names);
  };
}
function classedFalse(names) {
  return function() {
    classedRemove(this, names);
  };
}
function classedFunction(names, value) {
  return function() {
    (value.apply(this, arguments) ? classedAdd : classedRemove)(this, names);
  };
}
function classed_default(name, value) {
  var names = classArray(name + "");
  if (arguments.length < 2) {
    var list = classList(this.node()), i = -1, n = names.length;
    while (++i < n) if (!list.contains(names[i])) return false;
    return true;
  }
  return this.each((typeof value === "function" ? classedFunction : value ? classedTrue : classedFalse)(names, value));
}

// node_modules/d3-selection/src/selection/text.js
function textRemove() {
  this.textContent = "";
}
function textConstant(value) {
  return function() {
    this.textContent = value;
  };
}
function textFunction(value) {
  return function() {
    var v = value.apply(this, arguments);
    this.textContent = v == null ? "" : v;
  };
}
function text_default(value) {
  return arguments.length ? this.each(value == null ? textRemove : (typeof value === "function" ? textFunction : textConstant)(value)) : this.node().textContent;
}

// node_modules/d3-selection/src/selection/html.js
function htmlRemove() {
  this.innerHTML = "";
}
function htmlConstant(value) {
  return function() {
    this.innerHTML = value;
  };
}
function htmlFunction(value) {
  return function() {
    var v = value.apply(this, arguments);
    this.innerHTML = v == null ? "" : v;
  };
}
function html_default(value) {
  return arguments.length ? this.each(value == null ? htmlRemove : (typeof value === "function" ? htmlFunction : htmlConstant)(value)) : this.node().innerHTML;
}

// node_modules/d3-selection/src/selection/raise.js
function raise() {
  if (this.nextSibling) this.parentNode.appendChild(this);
}
function raise_default() {
  return this.each(raise);
}

// node_modules/d3-selection/src/selection/lower.js
function lower() {
  if (this.previousSibling) this.parentNode.insertBefore(this, this.parentNode.firstChild);
}
function lower_default() {
  return this.each(lower);
}

// node_modules/d3-selection/src/selection/append.js
function append_default(name) {
  var create2 = typeof name === "function" ? name : creator_default(name);
  return this.select(function() {
    return this.appendChild(create2.apply(this, arguments));
  });
}

// node_modules/d3-selection/src/selection/insert.js
function constantNull() {
  return null;
}
function insert_default(name, before) {
  var create2 = typeof name === "function" ? name : creator_default(name), select = before == null ? constantNull : typeof before === "function" ? before : selector_default(before);
  return this.select(function() {
    return this.insertBefore(create2.apply(this, arguments), select.apply(this, arguments) || null);
  });
}

// node_modules/d3-selection/src/selection/remove.js
function remove() {
  var parent = this.parentNode;
  if (parent) parent.removeChild(this);
}
function remove_default() {
  return this.each(remove);
}

// node_modules/d3-selection/src/selection/clone.js
function selection_cloneShallow() {
  var clone = this.cloneNode(false), parent = this.parentNode;
  return parent ? parent.insertBefore(clone, this.nextSibling) : clone;
}
function selection_cloneDeep() {
  var clone = this.cloneNode(true), parent = this.parentNode;
  return parent ? parent.insertBefore(clone, this.nextSibling) : clone;
}
function clone_default(deep) {
  return this.select(deep ? selection_cloneDeep : selection_cloneShallow);
}

// node_modules/d3-selection/src/selection/datum.js
function datum_default(value) {
  return arguments.length ? this.property("__data__", value) : this.node().__data__;
}

// node_modules/d3-selection/src/selection/on.js
function contextListener(listener) {
  return function(event) {
    listener.call(this, event, this.__data__);
  };
}
function parseTypenames2(typenames) {
  return typenames.trim().split(/^|\s+/).map(function(t2) {
    var name = "", i = t2.indexOf(".");
    if (i >= 0) name = t2.slice(i + 1), t2 = t2.slice(0, i);
    return { type: t2, name };
  });
}
function onRemove(typename) {
  return function() {
    var on = this.__on;
    if (!on) return;
    for (var j = 0, i = -1, m2 = on.length, o; j < m2; ++j) {
      if (o = on[j], (!typename.type || o.type === typename.type) && o.name === typename.name) {
        this.removeEventListener(o.type, o.listener, o.options);
      } else {
        on[++i] = o;
      }
    }
    if (++i) on.length = i;
    else delete this.__on;
  };
}
function onAdd(typename, value, options) {
  return function() {
    var on = this.__on, o, listener = contextListener(value);
    if (on) for (var j = 0, m2 = on.length; j < m2; ++j) {
      if ((o = on[j]).type === typename.type && o.name === typename.name) {
        this.removeEventListener(o.type, o.listener, o.options);
        this.addEventListener(o.type, o.listener = listener, o.options = options);
        o.value = value;
        return;
      }
    }
    this.addEventListener(typename.type, listener, options);
    o = { type: typename.type, name: typename.name, value, listener, options };
    if (!on) this.__on = [o];
    else on.push(o);
  };
}
function on_default(typename, value, options) {
  var typenames = parseTypenames2(typename + ""), i, n = typenames.length, t2;
  if (arguments.length < 2) {
    var on = this.node().__on;
    if (on) for (var j = 0, m2 = on.length, o; j < m2; ++j) {
      for (i = 0, o = on[j]; i < n; ++i) {
        if ((t2 = typenames[i]).type === o.type && t2.name === o.name) {
          return o.value;
        }
      }
    }
    return;
  }
  on = value ? onAdd : onRemove;
  for (i = 0; i < n; ++i) this.each(on(typenames[i], value, options));
  return this;
}

// node_modules/d3-selection/src/selection/dispatch.js
function dispatchEvent(node, type2, params) {
  var window2 = window_default(node), event = window2.CustomEvent;
  if (typeof event === "function") {
    event = new event(type2, params);
  } else {
    event = window2.document.createEvent("Event");
    if (params) event.initEvent(type2, params.bubbles, params.cancelable), event.detail = params.detail;
    else event.initEvent(type2, false, false);
  }
  node.dispatchEvent(event);
}
function dispatchConstant(type2, params) {
  return function() {
    return dispatchEvent(this, type2, params);
  };
}
function dispatchFunction(type2, params) {
  return function() {
    return dispatchEvent(this, type2, params.apply(this, arguments));
  };
}
function dispatch_default2(type2, params) {
  return this.each((typeof params === "function" ? dispatchFunction : dispatchConstant)(type2, params));
}

// node_modules/d3-selection/src/selection/iterator.js
function* iterator_default() {
  for (var groups = this._groups, j = 0, m2 = groups.length; j < m2; ++j) {
    for (var group = groups[j], i = 0, n = group.length, node; i < n; ++i) {
      if (node = group[i]) yield node;
    }
  }
}

// node_modules/d3-selection/src/selection/index.js
var root = [null];
function Selection(groups, parents) {
  this._groups = groups;
  this._parents = parents;
}
function selection() {
  return new Selection([[document.documentElement]], root);
}
function selection_selection() {
  return this;
}
Selection.prototype = selection.prototype = {
  constructor: Selection,
  select: select_default,
  selectAll: selectAll_default,
  selectChild: selectChild_default,
  selectChildren: selectChildren_default,
  filter: filter_default,
  data: data_default,
  enter: enter_default,
  exit: exit_default,
  join: join_default,
  merge: merge_default,
  selection: selection_selection,
  order: order_default,
  sort: sort_default,
  call: call_default,
  nodes: nodes_default,
  node: node_default,
  size: size_default,
  empty: empty_default,
  each: each_default,
  attr: attr_default,
  style: style_default,
  property: property_default,
  classed: classed_default,
  text: text_default,
  html: html_default,
  raise: raise_default,
  lower: lower_default,
  append: append_default,
  insert: insert_default,
  remove: remove_default,
  clone: clone_default,
  datum: datum_default,
  on: on_default,
  dispatch: dispatch_default2,
  [Symbol.iterator]: iterator_default
};
var selection_default = selection;

// node_modules/d3-selection/src/select.js
function select_default2(selector) {
  return typeof selector === "string" ? new Selection([[document.querySelector(selector)]], [document.documentElement]) : new Selection([[selector]], root);
}

// node_modules/d3-selection/src/sourceEvent.js
function sourceEvent_default(event) {
  let sourceEvent;
  while (sourceEvent = event.sourceEvent) event = sourceEvent;
  return event;
}

// node_modules/d3-selection/src/pointer.js
function pointer_default(event, node) {
  event = sourceEvent_default(event);
  if (node === void 0) node = event.currentTarget;
  if (node) {
    var svg = node.ownerSVGElement || node;
    if (svg.createSVGPoint) {
      var point2 = svg.createSVGPoint();
      point2.x = event.clientX, point2.y = event.clientY;
      point2 = point2.matrixTransform(node.getScreenCTM().inverse());
      return [point2.x, point2.y];
    }
    if (node.getBoundingClientRect) {
      var rect = node.getBoundingClientRect();
      return [event.clientX - rect.left - node.clientLeft, event.clientY - rect.top - node.clientTop];
    }
  }
  return [event.pageX, event.pageY];
}

// node_modules/d3-drag/src/noevent.js
var nonpassive = { passive: false };
var nonpassivecapture = { capture: true, passive: false };
function nopropagation(event) {
  event.stopImmediatePropagation();
}
function noevent_default(event) {
  event.preventDefault();
  event.stopImmediatePropagation();
}

// node_modules/d3-drag/src/nodrag.js
function nodrag_default(view) {
  var root2 = view.document.documentElement, selection2 = select_default2(view).on("dragstart.drag", noevent_default, nonpassivecapture);
  if ("onselectstart" in root2) {
    selection2.on("selectstart.drag", noevent_default, nonpassivecapture);
  } else {
    root2.__noselect = root2.style.MozUserSelect;
    root2.style.MozUserSelect = "none";
  }
}
function yesdrag(view, noclick) {
  var root2 = view.document.documentElement, selection2 = select_default2(view).on("dragstart.drag", null);
  if (noclick) {
    selection2.on("click.drag", noevent_default, nonpassivecapture);
    setTimeout(function() {
      selection2.on("click.drag", null);
    }, 0);
  }
  if ("onselectstart" in root2) {
    selection2.on("selectstart.drag", null);
  } else {
    root2.style.MozUserSelect = root2.__noselect;
    delete root2.__noselect;
  }
}

// node_modules/d3-drag/src/constant.js
var constant_default2 = (x3) => () => x3;

// node_modules/d3-drag/src/event.js
function DragEvent(type2, {
  sourceEvent,
  subject,
  target,
  identifier,
  active,
  x: x3,
  y: y3,
  dx,
  dy,
  dispatch: dispatch2
}) {
  Object.defineProperties(this, {
    type: { value: type2, enumerable: true, configurable: true },
    sourceEvent: { value: sourceEvent, enumerable: true, configurable: true },
    subject: { value: subject, enumerable: true, configurable: true },
    target: { value: target, enumerable: true, configurable: true },
    identifier: { value: identifier, enumerable: true, configurable: true },
    active: { value: active, enumerable: true, configurable: true },
    x: { value: x3, enumerable: true, configurable: true },
    y: { value: y3, enumerable: true, configurable: true },
    dx: { value: dx, enumerable: true, configurable: true },
    dy: { value: dy, enumerable: true, configurable: true },
    _: { value: dispatch2 }
  });
}
DragEvent.prototype.on = function() {
  var value = this._.on.apply(this._, arguments);
  return value === this._ ? this : value;
};

// node_modules/d3-drag/src/drag.js
function defaultFilter(event) {
  return !event.ctrlKey && !event.button;
}
function defaultContainer() {
  return this.parentNode;
}
function defaultSubject(event, d) {
  return d == null ? { x: event.x, y: event.y } : d;
}
function defaultTouchable() {
  return navigator.maxTouchPoints || "ontouchstart" in this;
}
function drag_default() {
  var filter2 = defaultFilter, container = defaultContainer, subject = defaultSubject, touchable = defaultTouchable, gestures = {}, listeners = dispatch_default("start", "drag", "end"), active = 0, mousedownx, mousedowny, mousemoving, touchending, clickDistance2 = 0;
  function drag(selection2) {
    selection2.on("mousedown.drag", mousedowned).filter(touchable).on("touchstart.drag", touchstarted).on("touchmove.drag", touchmoved, nonpassive).on("touchend.drag touchcancel.drag", touchended).style("touch-action", "none").style("-webkit-tap-highlight-color", "rgba(0,0,0,0)");
  }
  function mousedowned(event, d) {
    if (touchending || !filter2.call(this, event, d)) return;
    var gesture = beforestart(this, container.call(this, event, d), event, d, "mouse");
    if (!gesture) return;
    select_default2(event.view).on("mousemove.drag", mousemoved, nonpassivecapture).on("mouseup.drag", mouseupped, nonpassivecapture);
    nodrag_default(event.view);
    nopropagation(event);
    mousemoving = false;
    mousedownx = event.clientX;
    mousedowny = event.clientY;
    gesture("start", event);
  }
  function mousemoved(event) {
    noevent_default(event);
    if (!mousemoving) {
      var dx = event.clientX - mousedownx, dy = event.clientY - mousedowny;
      mousemoving = dx * dx + dy * dy > clickDistance2;
    }
    gestures.mouse("drag", event);
  }
  function mouseupped(event) {
    select_default2(event.view).on("mousemove.drag mouseup.drag", null);
    yesdrag(event.view, mousemoving);
    noevent_default(event);
    gestures.mouse("end", event);
  }
  function touchstarted(event, d) {
    if (!filter2.call(this, event, d)) return;
    var touches = event.changedTouches, c4 = container.call(this, event, d), n = touches.length, i, gesture;
    for (i = 0; i < n; ++i) {
      if (gesture = beforestart(this, c4, event, d, touches[i].identifier, touches[i])) {
        nopropagation(event);
        gesture("start", event, touches[i]);
      }
    }
  }
  function touchmoved(event) {
    var touches = event.changedTouches, n = touches.length, i, gesture;
    for (i = 0; i < n; ++i) {
      if (gesture = gestures[touches[i].identifier]) {
        noevent_default(event);
        gesture("drag", event, touches[i]);
      }
    }
  }
  function touchended(event) {
    var touches = event.changedTouches, n = touches.length, i, gesture;
    if (touchending) clearTimeout(touchending);
    touchending = setTimeout(function() {
      touchending = null;
    }, 500);
    for (i = 0; i < n; ++i) {
      if (gesture = gestures[touches[i].identifier]) {
        nopropagation(event);
        gesture("end", event, touches[i]);
      }
    }
  }
  function beforestart(that, container2, event, d, identifier, touch) {
    var dispatch2 = listeners.copy(), p = pointer_default(touch || event, container2), dx, dy, s;
    if ((s = subject.call(that, new DragEvent("beforestart", {
      sourceEvent: event,
      target: drag,
      identifier,
      active,
      x: p[0],
      y: p[1],
      dx: 0,
      dy: 0,
      dispatch: dispatch2
    }), d)) == null) return;
    dx = s.x - p[0] || 0;
    dy = s.y - p[1] || 0;
    return function gesture(type2, event2, touch2) {
      var p0 = p, n;
      switch (type2) {
        case "start":
          gestures[identifier] = gesture, n = active++;
          break;
        case "end":
          delete gestures[identifier], --active;
        // falls through
        case "drag":
          p = pointer_default(touch2 || event2, container2), n = active;
          break;
      }
      dispatch2.call(
        type2,
        that,
        new DragEvent(type2, {
          sourceEvent: event2,
          subject: s,
          target: drag,
          identifier,
          active: n,
          x: p[0] + dx,
          y: p[1] + dy,
          dx: p[0] - p0[0],
          dy: p[1] - p0[1],
          dispatch: dispatch2
        }),
        d
      );
    };
  }
  drag.filter = function(_) {
    return arguments.length ? (filter2 = typeof _ === "function" ? _ : constant_default2(!!_), drag) : filter2;
  };
  drag.container = function(_) {
    return arguments.length ? (container = typeof _ === "function" ? _ : constant_default2(_), drag) : container;
  };
  drag.subject = function(_) {
    return arguments.length ? (subject = typeof _ === "function" ? _ : constant_default2(_), drag) : subject;
  };
  drag.touchable = function(_) {
    return arguments.length ? (touchable = typeof _ === "function" ? _ : constant_default2(!!_), drag) : touchable;
  };
  drag.on = function() {
    var value = listeners.on.apply(listeners, arguments);
    return value === listeners ? drag : value;
  };
  drag.clickDistance = function(_) {
    return arguments.length ? (clickDistance2 = (_ = +_) * _, drag) : Math.sqrt(clickDistance2);
  };
  return drag;
}

// node_modules/d3-color/src/define.js
function define_default(constructor, factory, prototype) {
  constructor.prototype = factory.prototype = prototype;
  prototype.constructor = constructor;
}
function extend(parent, definition) {
  var prototype = Object.create(parent.prototype);
  for (var key in definition) prototype[key] = definition[key];
  return prototype;
}

// node_modules/d3-color/src/color.js
function Color() {
}
var darker = 0.7;
var brighter = 1 / darker;
var reI = "\\s*([+-]?\\d+)\\s*";
var reN = "\\s*([+-]?(?:\\d*\\.)?\\d+(?:[eE][+-]?\\d+)?)\\s*";
var reP = "\\s*([+-]?(?:\\d*\\.)?\\d+(?:[eE][+-]?\\d+)?)%\\s*";
var reHex = /^#([0-9a-f]{3,8})$/;
var reRgbInteger = new RegExp(`^rgb\\(${reI},${reI},${reI}\\)$`);
var reRgbPercent = new RegExp(`^rgb\\(${reP},${reP},${reP}\\)$`);
var reRgbaInteger = new RegExp(`^rgba\\(${reI},${reI},${reI},${reN}\\)$`);
var reRgbaPercent = new RegExp(`^rgba\\(${reP},${reP},${reP},${reN}\\)$`);
var reHslPercent = new RegExp(`^hsl\\(${reN},${reP},${reP}\\)$`);
var reHslaPercent = new RegExp(`^hsla\\(${reN},${reP},${reP},${reN}\\)$`);
var named = {
  aliceblue: 15792383,
  antiquewhite: 16444375,
  aqua: 65535,
  aquamarine: 8388564,
  azure: 15794175,
  beige: 16119260,
  bisque: 16770244,
  black: 0,
  blanchedalmond: 16772045,
  blue: 255,
  blueviolet: 9055202,
  brown: 10824234,
  burlywood: 14596231,
  cadetblue: 6266528,
  chartreuse: 8388352,
  chocolate: 13789470,
  coral: 16744272,
  cornflowerblue: 6591981,
  cornsilk: 16775388,
  crimson: 14423100,
  cyan: 65535,
  darkblue: 139,
  darkcyan: 35723,
  darkgoldenrod: 12092939,
  darkgray: 11119017,
  darkgreen: 25600,
  darkgrey: 11119017,
  darkkhaki: 12433259,
  darkmagenta: 9109643,
  darkolivegreen: 5597999,
  darkorange: 16747520,
  darkorchid: 10040012,
  darkred: 9109504,
  darksalmon: 15308410,
  darkseagreen: 9419919,
  darkslateblue: 4734347,
  darkslategray: 3100495,
  darkslategrey: 3100495,
  darkturquoise: 52945,
  darkviolet: 9699539,
  deeppink: 16716947,
  deepskyblue: 49151,
  dimgray: 6908265,
  dimgrey: 6908265,
  dodgerblue: 2003199,
  firebrick: 11674146,
  floralwhite: 16775920,
  forestgreen: 2263842,
  fuchsia: 16711935,
  gainsboro: 14474460,
  ghostwhite: 16316671,
  gold: 16766720,
  goldenrod: 14329120,
  gray: 8421504,
  green: 32768,
  greenyellow: 11403055,
  grey: 8421504,
  honeydew: 15794160,
  hotpink: 16738740,
  indianred: 13458524,
  indigo: 4915330,
  ivory: 16777200,
  khaki: 15787660,
  lavender: 15132410,
  lavenderblush: 16773365,
  lawngreen: 8190976,
  lemonchiffon: 16775885,
  lightblue: 11393254,
  lightcoral: 15761536,
  lightcyan: 14745599,
  lightgoldenrodyellow: 16448210,
  lightgray: 13882323,
  lightgreen: 9498256,
  lightgrey: 13882323,
  lightpink: 16758465,
  lightsalmon: 16752762,
  lightseagreen: 2142890,
  lightskyblue: 8900346,
  lightslategray: 7833753,
  lightslategrey: 7833753,
  lightsteelblue: 11584734,
  lightyellow: 16777184,
  lime: 65280,
  limegreen: 3329330,
  linen: 16445670,
  magenta: 16711935,
  maroon: 8388608,
  mediumaquamarine: 6737322,
  mediumblue: 205,
  mediumorchid: 12211667,
  mediumpurple: 9662683,
  mediumseagreen: 3978097,
  mediumslateblue: 8087790,
  mediumspringgreen: 64154,
  mediumturquoise: 4772300,
  mediumvioletred: 13047173,
  midnightblue: 1644912,
  mintcream: 16121850,
  mistyrose: 16770273,
  moccasin: 16770229,
  navajowhite: 16768685,
  navy: 128,
  oldlace: 16643558,
  olive: 8421376,
  olivedrab: 7048739,
  orange: 16753920,
  orangered: 16729344,
  orchid: 14315734,
  palegoldenrod: 15657130,
  palegreen: 10025880,
  paleturquoise: 11529966,
  palevioletred: 14381203,
  papayawhip: 16773077,
  peachpuff: 16767673,
  peru: 13468991,
  pink: 16761035,
  plum: 14524637,
  powderblue: 11591910,
  purple: 8388736,
  rebeccapurple: 6697881,
  red: 16711680,
  rosybrown: 12357519,
  royalblue: 4286945,
  saddlebrown: 9127187,
  salmon: 16416882,
  sandybrown: 16032864,
  seagreen: 3050327,
  seashell: 16774638,
  sienna: 10506797,
  silver: 12632256,
  skyblue: 8900331,
  slateblue: 6970061,
  slategray: 7372944,
  slategrey: 7372944,
  snow: 16775930,
  springgreen: 65407,
  steelblue: 4620980,
  tan: 13808780,
  teal: 32896,
  thistle: 14204888,
  tomato: 16737095,
  turquoise: 4251856,
  violet: 15631086,
  wheat: 16113331,
  white: 16777215,
  whitesmoke: 16119285,
  yellow: 16776960,
  yellowgreen: 10145074
};
define_default(Color, color, {
  copy(channels) {
    return Object.assign(new this.constructor(), this, channels);
  },
  displayable() {
    return this.rgb().displayable();
  },
  hex: color_formatHex,
  // Deprecated! Use color.formatHex.
  formatHex: color_formatHex,
  formatHex8: color_formatHex8,
  formatHsl: color_formatHsl,
  formatRgb: color_formatRgb,
  toString: color_formatRgb
});
function color_formatHex() {
  return this.rgb().formatHex();
}
function color_formatHex8() {
  return this.rgb().formatHex8();
}
function color_formatHsl() {
  return hslConvert(this).formatHsl();
}
function color_formatRgb() {
  return this.rgb().formatRgb();
}
function color(format2) {
  var m2, l;
  format2 = (format2 + "").trim().toLowerCase();
  return (m2 = reHex.exec(format2)) ? (l = m2[1].length, m2 = parseInt(m2[1], 16), l === 6 ? rgbn(m2) : l === 3 ? new Rgb(m2 >> 8 & 15 | m2 >> 4 & 240, m2 >> 4 & 15 | m2 & 240, (m2 & 15) << 4 | m2 & 15, 1) : l === 8 ? rgba(m2 >> 24 & 255, m2 >> 16 & 255, m2 >> 8 & 255, (m2 & 255) / 255) : l === 4 ? rgba(m2 >> 12 & 15 | m2 >> 8 & 240, m2 >> 8 & 15 | m2 >> 4 & 240, m2 >> 4 & 15 | m2 & 240, ((m2 & 15) << 4 | m2 & 15) / 255) : null) : (m2 = reRgbInteger.exec(format2)) ? new Rgb(m2[1], m2[2], m2[3], 1) : (m2 = reRgbPercent.exec(format2)) ? new Rgb(m2[1] * 255 / 100, m2[2] * 255 / 100, m2[3] * 255 / 100, 1) : (m2 = reRgbaInteger.exec(format2)) ? rgba(m2[1], m2[2], m2[3], m2[4]) : (m2 = reRgbaPercent.exec(format2)) ? rgba(m2[1] * 255 / 100, m2[2] * 255 / 100, m2[3] * 255 / 100, m2[4]) : (m2 = reHslPercent.exec(format2)) ? hsla(m2[1], m2[2] / 100, m2[3] / 100, 1) : (m2 = reHslaPercent.exec(format2)) ? hsla(m2[1], m2[2] / 100, m2[3] / 100, m2[4]) : named.hasOwnProperty(format2) ? rgbn(named[format2]) : format2 === "transparent" ? new Rgb(NaN, NaN, NaN, 0) : null;
}
function rgbn(n) {
  return new Rgb(n >> 16 & 255, n >> 8 & 255, n & 255, 1);
}
function rgba(r, g2, b, a2) {
  if (a2 <= 0) r = g2 = b = NaN;
  return new Rgb(r, g2, b, a2);
}
function rgbConvert(o) {
  if (!(o instanceof Color)) o = color(o);
  if (!o) return new Rgb();
  o = o.rgb();
  return new Rgb(o.r, o.g, o.b, o.opacity);
}
function rgb(r, g2, b, opacity) {
  return arguments.length === 1 ? rgbConvert(r) : new Rgb(r, g2, b, opacity == null ? 1 : opacity);
}
function Rgb(r, g2, b, opacity) {
  this.r = +r;
  this.g = +g2;
  this.b = +b;
  this.opacity = +opacity;
}
define_default(Rgb, rgb, extend(Color, {
  brighter(k) {
    k = k == null ? brighter : Math.pow(brighter, k);
    return new Rgb(this.r * k, this.g * k, this.b * k, this.opacity);
  },
  darker(k) {
    k = k == null ? darker : Math.pow(darker, k);
    return new Rgb(this.r * k, this.g * k, this.b * k, this.opacity);
  },
  rgb() {
    return this;
  },
  clamp() {
    return new Rgb(clampi(this.r), clampi(this.g), clampi(this.b), clampa(this.opacity));
  },
  displayable() {
    return -0.5 <= this.r && this.r < 255.5 && (-0.5 <= this.g && this.g < 255.5) && (-0.5 <= this.b && this.b < 255.5) && (0 <= this.opacity && this.opacity <= 1);
  },
  hex: rgb_formatHex,
  // Deprecated! Use color.formatHex.
  formatHex: rgb_formatHex,
  formatHex8: rgb_formatHex8,
  formatRgb: rgb_formatRgb,
  toString: rgb_formatRgb
}));
function rgb_formatHex() {
  return `#${hex(this.r)}${hex(this.g)}${hex(this.b)}`;
}
function rgb_formatHex8() {
  return `#${hex(this.r)}${hex(this.g)}${hex(this.b)}${hex((isNaN(this.opacity) ? 1 : this.opacity) * 255)}`;
}
function rgb_formatRgb() {
  const a2 = clampa(this.opacity);
  return `${a2 === 1 ? "rgb(" : "rgba("}${clampi(this.r)}, ${clampi(this.g)}, ${clampi(this.b)}${a2 === 1 ? ")" : `, ${a2})`}`;
}
function clampa(opacity) {
  return isNaN(opacity) ? 1 : Math.max(0, Math.min(1, opacity));
}
function clampi(value) {
  return Math.max(0, Math.min(255, Math.round(value) || 0));
}
function hex(value) {
  value = clampi(value);
  return (value < 16 ? "0" : "") + value.toString(16);
}
function hsla(h, s, l, a2) {
  if (a2 <= 0) h = s = l = NaN;
  else if (l <= 0 || l >= 1) h = s = NaN;
  else if (s <= 0) h = NaN;
  return new Hsl(h, s, l, a2);
}
function hslConvert(o) {
  if (o instanceof Hsl) return new Hsl(o.h, o.s, o.l, o.opacity);
  if (!(o instanceof Color)) o = color(o);
  if (!o) return new Hsl();
  if (o instanceof Hsl) return o;
  o = o.rgb();
  var r = o.r / 255, g2 = o.g / 255, b = o.b / 255, min8 = Math.min(r, g2, b), max8 = Math.max(r, g2, b), h = NaN, s = max8 - min8, l = (max8 + min8) / 2;
  if (s) {
    if (r === max8) h = (g2 - b) / s + (g2 < b) * 6;
    else if (g2 === max8) h = (b - r) / s + 2;
    else h = (r - g2) / s + 4;
    s /= l < 0.5 ? max8 + min8 : 2 - max8 - min8;
    h *= 60;
  } else {
    s = l > 0 && l < 1 ? 0 : h;
  }
  return new Hsl(h, s, l, o.opacity);
}
function hsl(h, s, l, opacity) {
  return arguments.length === 1 ? hslConvert(h) : new Hsl(h, s, l, opacity == null ? 1 : opacity);
}
function Hsl(h, s, l, opacity) {
  this.h = +h;
  this.s = +s;
  this.l = +l;
  this.opacity = +opacity;
}
define_default(Hsl, hsl, extend(Color, {
  brighter(k) {
    k = k == null ? brighter : Math.pow(brighter, k);
    return new Hsl(this.h, this.s, this.l * k, this.opacity);
  },
  darker(k) {
    k = k == null ? darker : Math.pow(darker, k);
    return new Hsl(this.h, this.s, this.l * k, this.opacity);
  },
  rgb() {
    var h = this.h % 360 + (this.h < 0) * 360, s = isNaN(h) || isNaN(this.s) ? 0 : this.s, l = this.l, m2 = l + (l < 0.5 ? l : 1 - l) * s, m1 = 2 * l - m2;
    return new Rgb(
      hsl2rgb(h >= 240 ? h - 240 : h + 120, m1, m2),
      hsl2rgb(h, m1, m2),
      hsl2rgb(h < 120 ? h + 240 : h - 120, m1, m2),
      this.opacity
    );
  },
  clamp() {
    return new Hsl(clamph(this.h), clampt(this.s), clampt(this.l), clampa(this.opacity));
  },
  displayable() {
    return (0 <= this.s && this.s <= 1 || isNaN(this.s)) && (0 <= this.l && this.l <= 1) && (0 <= this.opacity && this.opacity <= 1);
  },
  formatHsl() {
    const a2 = clampa(this.opacity);
    return `${a2 === 1 ? "hsl(" : "hsla("}${clamph(this.h)}, ${clampt(this.s) * 100}%, ${clampt(this.l) * 100}%${a2 === 1 ? ")" : `, ${a2})`}`;
  }
}));
function clamph(value) {
  value = (value || 0) % 360;
  return value < 0 ? value + 360 : value;
}
function clampt(value) {
  return Math.max(0, Math.min(1, value || 0));
}
function hsl2rgb(h, m1, m2) {
  return (h < 60 ? m1 + (m2 - m1) * h / 60 : h < 180 ? m2 : h < 240 ? m1 + (m2 - m1) * (240 - h) / 60 : m1) * 255;
}

// node_modules/d3-color/src/math.js
var radians = Math.PI / 180;
var degrees = 180 / Math.PI;

// node_modules/d3-color/src/cubehelix.js
var A = -0.14861;
var B = 1.78277;
var C = -0.29227;
var D = -0.90649;
var E = 1.97294;
var ED = E * D;
var EB = E * B;
var BC_DA = B * C - D * A;
function cubehelixConvert(o) {
  if (o instanceof Cubehelix) return new Cubehelix(o.h, o.s, o.l, o.opacity);
  if (!(o instanceof Rgb)) o = rgbConvert(o);
  var r = o.r / 255, g2 = o.g / 255, b = o.b / 255, l = (BC_DA * b + ED * r - EB * g2) / (BC_DA + ED - EB), bl = b - l, k = (E * (g2 - l) - C * bl) / D, s = Math.sqrt(k * k + bl * bl) / (E * l * (1 - l)), h = s ? Math.atan2(k, bl) * degrees - 120 : NaN;
  return new Cubehelix(h < 0 ? h + 360 : h, s, l, o.opacity);
}
function cubehelix(h, s, l, opacity) {
  return arguments.length === 1 ? cubehelixConvert(h) : new Cubehelix(h, s, l, opacity == null ? 1 : opacity);
}
function Cubehelix(h, s, l, opacity) {
  this.h = +h;
  this.s = +s;
  this.l = +l;
  this.opacity = +opacity;
}
define_default(Cubehelix, cubehelix, extend(Color, {
  brighter(k) {
    k = k == null ? brighter : Math.pow(brighter, k);
    return new Cubehelix(this.h, this.s, this.l * k, this.opacity);
  },
  darker(k) {
    k = k == null ? darker : Math.pow(darker, k);
    return new Cubehelix(this.h, this.s, this.l * k, this.opacity);
  },
  rgb() {
    var h = isNaN(this.h) ? 0 : (this.h + 120) * radians, l = +this.l, a2 = isNaN(this.s) ? 0 : this.s * l * (1 - l), cosh2 = Math.cos(h), sinh2 = Math.sin(h);
    return new Rgb(
      255 * (l + a2 * (A * cosh2 + B * sinh2)),
      255 * (l + a2 * (C * cosh2 + D * sinh2)),
      255 * (l + a2 * (E * cosh2)),
      this.opacity
    );
  }
}));

// node_modules/d3-interpolate/src/basis.js
function basis(t1, v0, v1, v2, v3) {
  var t2 = t1 * t1, t3 = t2 * t1;
  return ((1 - 3 * t1 + 3 * t2 - t3) * v0 + (4 - 6 * t2 + 3 * t3) * v1 + (1 + 3 * t1 + 3 * t2 - 3 * t3) * v2 + t3 * v3) / 6;
}
function basis_default(values) {
  var n = values.length - 1;
  return function(t2) {
    var i = t2 <= 0 ? t2 = 0 : t2 >= 1 ? (t2 = 1, n - 1) : Math.floor(t2 * n), v1 = values[i], v2 = values[i + 1], v0 = i > 0 ? values[i - 1] : 2 * v1 - v2, v3 = i < n - 1 ? values[i + 2] : 2 * v2 - v1;
    return basis((t2 - i / n) * n, v0, v1, v2, v3);
  };
}

// node_modules/d3-interpolate/src/basisClosed.js
function basisClosed_default(values) {
  var n = values.length;
  return function(t2) {
    var i = Math.floor(((t2 %= 1) < 0 ? ++t2 : t2) * n), v0 = values[(i + n - 1) % n], v1 = values[i % n], v2 = values[(i + 1) % n], v3 = values[(i + 2) % n];
    return basis((t2 - i / n) * n, v0, v1, v2, v3);
  };
}

// node_modules/d3-interpolate/src/constant.js
var constant_default3 = (x3) => () => x3;

// node_modules/d3-interpolate/src/color.js
function linear(a2, d) {
  return function(t2) {
    return a2 + t2 * d;
  };
}
function exponential(a2, b, y3) {
  return a2 = Math.pow(a2, y3), b = Math.pow(b, y3) - a2, y3 = 1 / y3, function(t2) {
    return Math.pow(a2 + t2 * b, y3);
  };
}
function hue(a2, b) {
  var d = b - a2;
  return d ? linear(a2, d > 180 || d < -180 ? d - 360 * Math.round(d / 360) : d) : constant_default3(isNaN(a2) ? b : a2);
}
function gamma(y3) {
  return (y3 = +y3) === 1 ? nogamma : function(a2, b) {
    return b - a2 ? exponential(a2, b, y3) : constant_default3(isNaN(a2) ? b : a2);
  };
}
function nogamma(a2, b) {
  var d = b - a2;
  return d ? linear(a2, d) : constant_default3(isNaN(a2) ? b : a2);
}

// node_modules/d3-interpolate/src/rgb.js
var rgb_default = (function rgbGamma(y3) {
  var color2 = gamma(y3);
  function rgb4(start2, end) {
    var r = color2((start2 = rgb(start2)).r, (end = rgb(end)).r), g2 = color2(start2.g, end.g), b = color2(start2.b, end.b), opacity = nogamma(start2.opacity, end.opacity);
    return function(t2) {
      start2.r = r(t2);
      start2.g = g2(t2);
      start2.b = b(t2);
      start2.opacity = opacity(t2);
      return start2 + "";
    };
  }
  rgb4.gamma = rgbGamma;
  return rgb4;
})(1);
function rgbSpline(spline) {
  return function(colors) {
    var n = colors.length, r = new Array(n), g2 = new Array(n), b = new Array(n), i, color2;
    for (i = 0; i < n; ++i) {
      color2 = rgb(colors[i]);
      r[i] = color2.r || 0;
      g2[i] = color2.g || 0;
      b[i] = color2.b || 0;
    }
    r = spline(r);
    g2 = spline(g2);
    b = spline(b);
    color2.opacity = 1;
    return function(t2) {
      color2.r = r(t2);
      color2.g = g2(t2);
      color2.b = b(t2);
      return color2 + "";
    };
  };
}
var rgbBasis = rgbSpline(basis_default);
var rgbBasisClosed = rgbSpline(basisClosed_default);

// node_modules/d3-interpolate/src/numberArray.js
function numberArray_default(a2, b) {
  if (!b) b = [];
  var n = a2 ? Math.min(b.length, a2.length) : 0, c4 = b.slice(), i;
  return function(t2) {
    for (i = 0; i < n; ++i) c4[i] = a2[i] * (1 - t2) + b[i] * t2;
    return c4;
  };
}
function isNumberArray(x3) {
  return ArrayBuffer.isView(x3) && !(x3 instanceof DataView);
}

// node_modules/d3-interpolate/src/array.js
function genericArray(a2, b) {
  var nb = b ? b.length : 0, na = a2 ? Math.min(nb, a2.length) : 0, x3 = new Array(na), c4 = new Array(nb), i;
  for (i = 0; i < na; ++i) x3[i] = value_default(a2[i], b[i]);
  for (; i < nb; ++i) c4[i] = b[i];
  return function(t2) {
    for (i = 0; i < na; ++i) c4[i] = x3[i](t2);
    return c4;
  };
}

// node_modules/d3-interpolate/src/date.js
function date_default(a2, b) {
  var d = /* @__PURE__ */ new Date();
  return a2 = +a2, b = +b, function(t2) {
    return d.setTime(a2 * (1 - t2) + b * t2), d;
  };
}

// node_modules/d3-interpolate/src/number.js
function number_default(a2, b) {
  return a2 = +a2, b = +b, function(t2) {
    return a2 * (1 - t2) + b * t2;
  };
}

// node_modules/d3-interpolate/src/object.js
function object_default(a2, b) {
  var i = {}, c4 = {}, k;
  if (a2 === null || typeof a2 !== "object") a2 = {};
  if (b === null || typeof b !== "object") b = {};
  for (k in b) {
    if (k in a2) {
      i[k] = value_default(a2[k], b[k]);
    } else {
      c4[k] = b[k];
    }
  }
  return function(t2) {
    for (k in i) c4[k] = i[k](t2);
    return c4;
  };
}

// node_modules/d3-interpolate/src/string.js
var reA = /[-+]?(?:\d+\.?\d*|\.?\d+)(?:[eE][-+]?\d+)?/g;
var reB = new RegExp(reA.source, "g");
function zero2(b) {
  return function() {
    return b;
  };
}
function one(b) {
  return function(t2) {
    return b(t2) + "";
  };
}
function string_default(a2, b) {
  var bi = reA.lastIndex = reB.lastIndex = 0, am, bm, bs, i = -1, s = [], q = [];
  a2 = a2 + "", b = b + "";
  while ((am = reA.exec(a2)) && (bm = reB.exec(b))) {
    if ((bs = bm.index) > bi) {
      bs = b.slice(bi, bs);
      if (s[i]) s[i] += bs;
      else s[++i] = bs;
    }
    if ((am = am[0]) === (bm = bm[0])) {
      if (s[i]) s[i] += bm;
      else s[++i] = bm;
    } else {
      s[++i] = null;
      q.push({ i, x: number_default(am, bm) });
    }
    bi = reB.lastIndex;
  }
  if (bi < b.length) {
    bs = b.slice(bi);
    if (s[i]) s[i] += bs;
    else s[++i] = bs;
  }
  return s.length < 2 ? q[0] ? one(q[0].x) : zero2(b) : (b = q.length, function(t2) {
    for (var i2 = 0, o; i2 < b; ++i2) s[(o = q[i2]).i] = o.x(t2);
    return s.join("");
  });
}

// node_modules/d3-interpolate/src/value.js
function value_default(a2, b) {
  var t2 = typeof b, c4;
  return b == null || t2 === "boolean" ? constant_default3(b) : (t2 === "number" ? number_default : t2 === "string" ? (c4 = color(b)) ? (b = c4, rgb_default) : string_default : b instanceof color ? rgb_default : b instanceof Date ? date_default : isNumberArray(b) ? numberArray_default : Array.isArray(b) ? genericArray : typeof b.valueOf !== "function" && typeof b.toString !== "function" || isNaN(b) ? object_default : number_default)(a2, b);
}

// node_modules/d3-interpolate/src/round.js
function round_default(a2, b) {
  return a2 = +a2, b = +b, function(t2) {
    return Math.round(a2 * (1 - t2) + b * t2);
  };
}

// node_modules/d3-interpolate/src/transform/decompose.js
var degrees2 = 180 / Math.PI;
var identity = {
  translateX: 0,
  translateY: 0,
  rotate: 0,
  skewX: 0,
  scaleX: 1,
  scaleY: 1
};
function decompose_default(a2, b, c4, d, e, f) {
  var scaleX, scaleY, skewX;
  if (scaleX = Math.sqrt(a2 * a2 + b * b)) a2 /= scaleX, b /= scaleX;
  if (skewX = a2 * c4 + b * d) c4 -= a2 * skewX, d -= b * skewX;
  if (scaleY = Math.sqrt(c4 * c4 + d * d)) c4 /= scaleY, d /= scaleY, skewX /= scaleY;
  if (a2 * d < b * c4) a2 = -a2, b = -b, skewX = -skewX, scaleX = -scaleX;
  return {
    translateX: e,
    translateY: f,
    rotate: Math.atan2(b, a2) * degrees2,
    skewX: Math.atan(skewX) * degrees2,
    scaleX,
    scaleY
  };
}

// node_modules/d3-interpolate/src/transform/parse.js
var svgNode;
function parseCss(value) {
  const m2 = new (typeof DOMMatrix === "function" ? DOMMatrix : WebKitCSSMatrix)(value + "");
  return m2.isIdentity ? identity : decompose_default(m2.a, m2.b, m2.c, m2.d, m2.e, m2.f);
}
function parseSvg(value) {
  if (value == null) return identity;
  if (!svgNode) svgNode = document.createElementNS("http://www.w3.org/2000/svg", "g");
  svgNode.setAttribute("transform", value);
  if (!(value = svgNode.transform.baseVal.consolidate())) return identity;
  value = value.matrix;
  return decompose_default(value.a, value.b, value.c, value.d, value.e, value.f);
}

// node_modules/d3-interpolate/src/transform/index.js
function interpolateTransform(parse, pxComma, pxParen, degParen) {
  function pop(s) {
    return s.length ? s.pop() + " " : "";
  }
  function translate(xa, ya, xb, yb, s, q) {
    if (xa !== xb || ya !== yb) {
      var i = s.push("translate(", null, pxComma, null, pxParen);
      q.push({ i: i - 4, x: number_default(xa, xb) }, { i: i - 2, x: number_default(ya, yb) });
    } else if (xb || yb) {
      s.push("translate(" + xb + pxComma + yb + pxParen);
    }
  }
  function rotate(a2, b, s, q) {
    if (a2 !== b) {
      if (a2 - b > 180) b += 360;
      else if (b - a2 > 180) a2 += 360;
      q.push({ i: s.push(pop(s) + "rotate(", null, degParen) - 2, x: number_default(a2, b) });
    } else if (b) {
      s.push(pop(s) + "rotate(" + b + degParen);
    }
  }
  function skewX(a2, b, s, q) {
    if (a2 !== b) {
      q.push({ i: s.push(pop(s) + "skewX(", null, degParen) - 2, x: number_default(a2, b) });
    } else if (b) {
      s.push(pop(s) + "skewX(" + b + degParen);
    }
  }
  function scale(xa, ya, xb, yb, s, q) {
    if (xa !== xb || ya !== yb) {
      var i = s.push(pop(s) + "scale(", null, ",", null, ")");
      q.push({ i: i - 4, x: number_default(xa, xb) }, { i: i - 2, x: number_default(ya, yb) });
    } else if (xb !== 1 || yb !== 1) {
      s.push(pop(s) + "scale(" + xb + "," + yb + ")");
    }
  }
  return function(a2, b) {
    var s = [], q = [];
    a2 = parse(a2), b = parse(b);
    translate(a2.translateX, a2.translateY, b.translateX, b.translateY, s, q);
    rotate(a2.rotate, b.rotate, s, q);
    skewX(a2.skewX, b.skewX, s, q);
    scale(a2.scaleX, a2.scaleY, b.scaleX, b.scaleY, s, q);
    a2 = b = null;
    return function(t2) {
      var i = -1, n = q.length, o;
      while (++i < n) s[(o = q[i]).i] = o.x(t2);
      return s.join("");
    };
  };
}
var interpolateTransformCss = interpolateTransform(parseCss, "px, ", "px)", "deg)");
var interpolateTransformSvg = interpolateTransform(parseSvg, ", ", ")", ")");

// node_modules/d3-interpolate/src/zoom.js
var epsilon2 = 1e-12;
function cosh(x3) {
  return ((x3 = Math.exp(x3)) + 1 / x3) / 2;
}
function sinh(x3) {
  return ((x3 = Math.exp(x3)) - 1 / x3) / 2;
}
function tanh(x3) {
  return ((x3 = Math.exp(2 * x3)) - 1) / (x3 + 1);
}
var zoom_default = (function zoomRho(rho, rho2, rho4) {
  function zoom(p0, p1) {
    var ux0 = p0[0], uy0 = p0[1], w0 = p0[2], ux1 = p1[0], uy1 = p1[1], w1 = p1[2], dx = ux1 - ux0, dy = uy1 - uy0, d2 = dx * dx + dy * dy, i, S;
    if (d2 < epsilon2) {
      S = Math.log(w1 / w0) / rho;
      i = function(t2) {
        return [
          ux0 + t2 * dx,
          uy0 + t2 * dy,
          w0 * Math.exp(rho * t2 * S)
        ];
      };
    } else {
      var d1 = Math.sqrt(d2), b0 = (w1 * w1 - w0 * w0 + rho4 * d2) / (2 * w0 * rho2 * d1), b1 = (w1 * w1 - w0 * w0 - rho4 * d2) / (2 * w1 * rho2 * d1), r0 = Math.log(Math.sqrt(b0 * b0 + 1) - b0), r1 = Math.log(Math.sqrt(b1 * b1 + 1) - b1);
      S = (r1 - r0) / rho;
      i = function(t2) {
        var s = t2 * S, coshr0 = cosh(r0), u = w0 / (rho2 * d1) * (coshr0 * tanh(rho * s + r0) - sinh(r0));
        return [
          ux0 + u * dx,
          uy0 + u * dy,
          w0 * coshr0 / cosh(rho * s + r0)
        ];
      };
    }
    i.duration = S * 1e3 * rho / Math.SQRT2;
    return i;
  }
  zoom.rho = function(_) {
    var _1 = Math.max(1e-3, +_), _2 = _1 * _1, _4 = _2 * _2;
    return zoomRho(_1, _2, _4);
  };
  return zoom;
})(Math.SQRT2, 2, 4);

// node_modules/d3-interpolate/src/cubehelix.js
function cubehelix2(hue2) {
  return (function cubehelixGamma(y3) {
    y3 = +y3;
    function cubehelix3(start2, end) {
      var h = hue2((start2 = cubehelix(start2)).h, (end = cubehelix(end)).h), s = nogamma(start2.s, end.s), l = nogamma(start2.l, end.l), opacity = nogamma(start2.opacity, end.opacity);
      return function(t2) {
        start2.h = h(t2);
        start2.s = s(t2);
        start2.l = l(Math.pow(t2, y3));
        start2.opacity = opacity(t2);
        return start2 + "";
      };
    }
    cubehelix3.gamma = cubehelixGamma;
    return cubehelix3;
  })(1);
}
var cubehelix_default = cubehelix2(hue);
var cubehelixLong = cubehelix2(nogamma);

// node_modules/d3-timer/src/timer.js
var frame = 0;
var timeout = 0;
var interval = 0;
var pokeDelay = 1e3;
var taskHead;
var taskTail;
var clockLast = 0;
var clockNow = 0;
var clockSkew = 0;
var clock = typeof performance === "object" && performance.now ? performance : Date;
var setFrame = typeof window === "object" && window.requestAnimationFrame ? window.requestAnimationFrame.bind(window) : function(f) {
  setTimeout(f, 17);
};
function now() {
  return clockNow || (setFrame(clearNow), clockNow = clock.now() + clockSkew);
}
function clearNow() {
  clockNow = 0;
}
function Timer() {
  this._call = this._time = this._next = null;
}
Timer.prototype = timer.prototype = {
  constructor: Timer,
  restart: function(callback, delay, time) {
    if (typeof callback !== "function") throw new TypeError("callback is not a function");
    time = (time == null ? now() : +time) + (delay == null ? 0 : +delay);
    if (!this._next && taskTail !== this) {
      if (taskTail) taskTail._next = this;
      else taskHead = this;
      taskTail = this;
    }
    this._call = callback;
    this._time = time;
    sleep();
  },
  stop: function() {
    if (this._call) {
      this._call = null;
      this._time = Infinity;
      sleep();
    }
  }
};
function timer(callback, delay, time) {
  var t2 = new Timer();
  t2.restart(callback, delay, time);
  return t2;
}
function timerFlush() {
  now();
  ++frame;
  var t2 = taskHead, e;
  while (t2) {
    if ((e = clockNow - t2._time) >= 0) t2._call.call(void 0, e);
    t2 = t2._next;
  }
  --frame;
}
function wake() {
  clockNow = (clockLast = clock.now()) + clockSkew;
  frame = timeout = 0;
  try {
    timerFlush();
  } finally {
    frame = 0;
    nap();
    clockNow = 0;
  }
}
function poke() {
  var now2 = clock.now(), delay = now2 - clockLast;
  if (delay > pokeDelay) clockSkew -= delay, clockLast = now2;
}
function nap() {
  var t0, t1 = taskHead, t2, time = Infinity;
  while (t1) {
    if (t1._call) {
      if (time > t1._time) time = t1._time;
      t0 = t1, t1 = t1._next;
    } else {
      t2 = t1._next, t1._next = null;
      t1 = t0 ? t0._next = t2 : taskHead = t2;
    }
  }
  taskTail = t0;
  sleep(time);
}
function sleep(time) {
  if (frame) return;
  if (timeout) timeout = clearTimeout(timeout);
  var delay = time - clockNow;
  if (delay > 24) {
    if (time < Infinity) timeout = setTimeout(wake, time - clock.now() - clockSkew);
    if (interval) interval = clearInterval(interval);
  } else {
    if (!interval) clockLast = clock.now(), interval = setInterval(poke, pokeDelay);
    frame = 1, setFrame(wake);
  }
}

// node_modules/d3-timer/src/timeout.js
function timeout_default(callback, delay, time) {
  var t2 = new Timer();
  delay = delay == null ? 0 : +delay;
  t2.restart((elapsed) => {
    t2.stop();
    callback(elapsed + delay);
  }, delay, time);
  return t2;
}

// node_modules/d3-transition/src/transition/schedule.js
var emptyOn = dispatch_default("start", "end", "cancel", "interrupt");
var emptyTween = [];
var CREATED = 0;
var SCHEDULED = 1;
var STARTING = 2;
var STARTED = 3;
var RUNNING = 4;
var ENDING = 5;
var ENDED = 6;
function schedule_default(node, name, id2, index2, group, timing) {
  var schedules = node.__transition;
  if (!schedules) node.__transition = {};
  else if (id2 in schedules) return;
  create(node, id2, {
    name,
    index: index2,
    // For context during callback.
    group,
    // For context during callback.
    on: emptyOn,
    tween: emptyTween,
    time: timing.time,
    delay: timing.delay,
    duration: timing.duration,
    ease: timing.ease,
    timer: null,
    state: CREATED
  });
}
function init(node, id2) {
  var schedule = get2(node, id2);
  if (schedule.state > CREATED) throw new Error("too late; already scheduled");
  return schedule;
}
function set2(node, id2) {
  var schedule = get2(node, id2);
  if (schedule.state > STARTED) throw new Error("too late; already running");
  return schedule;
}
function get2(node, id2) {
  var schedule = node.__transition;
  if (!schedule || !(schedule = schedule[id2])) throw new Error("transition not found");
  return schedule;
}
function create(node, id2, self) {
  var schedules = node.__transition, tween;
  schedules[id2] = self;
  self.timer = timer(schedule, 0, self.time);
  function schedule(elapsed) {
    self.state = SCHEDULED;
    self.timer.restart(start2, self.delay, self.time);
    if (self.delay <= elapsed) start2(elapsed - self.delay);
  }
  function start2(elapsed) {
    var i, j, n, o;
    if (self.state !== SCHEDULED) return stop();
    for (i in schedules) {
      o = schedules[i];
      if (o.name !== self.name) continue;
      if (o.state === STARTED) return timeout_default(start2);
      if (o.state === RUNNING) {
        o.state = ENDED;
        o.timer.stop();
        o.on.call("interrupt", node, node.__data__, o.index, o.group);
        delete schedules[i];
      } else if (+i < id2) {
        o.state = ENDED;
        o.timer.stop();
        o.on.call("cancel", node, node.__data__, o.index, o.group);
        delete schedules[i];
      }
    }
    timeout_default(function() {
      if (self.state === STARTED) {
        self.state = RUNNING;
        self.timer.restart(tick, self.delay, self.time);
        tick(elapsed);
      }
    });
    self.state = STARTING;
    self.on.call("start", node, node.__data__, self.index, self.group);
    if (self.state !== STARTING) return;
    self.state = STARTED;
    tween = new Array(n = self.tween.length);
    for (i = 0, j = -1; i < n; ++i) {
      if (o = self.tween[i].value.call(node, node.__data__, self.index, self.group)) {
        tween[++j] = o;
      }
    }
    tween.length = j + 1;
  }
  function tick(elapsed) {
    var t2 = elapsed < self.duration ? self.ease.call(null, elapsed / self.duration) : (self.timer.restart(stop), self.state = ENDING, 1), i = -1, n = tween.length;
    while (++i < n) {
      tween[i].call(node, t2);
    }
    if (self.state === ENDING) {
      self.on.call("end", node, node.__data__, self.index, self.group);
      stop();
    }
  }
  function stop() {
    self.state = ENDED;
    self.timer.stop();
    delete schedules[id2];
    for (var i in schedules) return;
    delete node.__transition;
  }
}

// node_modules/d3-transition/src/interrupt.js
function interrupt_default(node, name) {
  var schedules = node.__transition, schedule, active, empty2 = true, i;
  if (!schedules) return;
  name = name == null ? null : name + "";
  for (i in schedules) {
    if ((schedule = schedules[i]).name !== name) {
      empty2 = false;
      continue;
    }
    active = schedule.state > STARTING && schedule.state < ENDING;
    schedule.state = ENDED;
    schedule.timer.stop();
    schedule.on.call(active ? "interrupt" : "cancel", node, node.__data__, schedule.index, schedule.group);
    delete schedules[i];
  }
  if (empty2) delete node.__transition;
}

// node_modules/d3-transition/src/selection/interrupt.js
function interrupt_default2(name) {
  return this.each(function() {
    interrupt_default(this, name);
  });
}

// node_modules/d3-transition/src/transition/tween.js
function tweenRemove(id2, name) {
  var tween0, tween1;
  return function() {
    var schedule = set2(this, id2), tween = schedule.tween;
    if (tween !== tween0) {
      tween1 = tween0 = tween;
      for (var i = 0, n = tween1.length; i < n; ++i) {
        if (tween1[i].name === name) {
          tween1 = tween1.slice();
          tween1.splice(i, 1);
          break;
        }
      }
    }
    schedule.tween = tween1;
  };
}
function tweenFunction(id2, name, value) {
  var tween0, tween1;
  if (typeof value !== "function") throw new Error();
  return function() {
    var schedule = set2(this, id2), tween = schedule.tween;
    if (tween !== tween0) {
      tween1 = (tween0 = tween).slice();
      for (var t2 = { name, value }, i = 0, n = tween1.length; i < n; ++i) {
        if (tween1[i].name === name) {
          tween1[i] = t2;
          break;
        }
      }
      if (i === n) tween1.push(t2);
    }
    schedule.tween = tween1;
  };
}
function tween_default(name, value) {
  var id2 = this._id;
  name += "";
  if (arguments.length < 2) {
    var tween = get2(this.node(), id2).tween;
    for (var i = 0, n = tween.length, t2; i < n; ++i) {
      if ((t2 = tween[i]).name === name) {
        return t2.value;
      }
    }
    return null;
  }
  return this.each((value == null ? tweenRemove : tweenFunction)(id2, name, value));
}
function tweenValue(transition2, name, value) {
  var id2 = transition2._id;
  transition2.each(function() {
    var schedule = set2(this, id2);
    (schedule.value || (schedule.value = {}))[name] = value.apply(this, arguments);
  });
  return function(node) {
    return get2(node, id2).value[name];
  };
}

// node_modules/d3-transition/src/transition/interpolate.js
function interpolate_default(a2, b) {
  var c4;
  return (typeof b === "number" ? number_default : b instanceof color ? rgb_default : (c4 = color(b)) ? (b = c4, rgb_default) : string_default)(a2, b);
}

// node_modules/d3-transition/src/transition/attr.js
function attrRemove2(name) {
  return function() {
    this.removeAttribute(name);
  };
}
function attrRemoveNS2(fullname) {
  return function() {
    this.removeAttributeNS(fullname.space, fullname.local);
  };
}
function attrConstant2(name, interpolate, value1) {
  var string00, string1 = value1 + "", interpolate0;
  return function() {
    var string0 = this.getAttribute(name);
    return string0 === string1 ? null : string0 === string00 ? interpolate0 : interpolate0 = interpolate(string00 = string0, value1);
  };
}
function attrConstantNS2(fullname, interpolate, value1) {
  var string00, string1 = value1 + "", interpolate0;
  return function() {
    var string0 = this.getAttributeNS(fullname.space, fullname.local);
    return string0 === string1 ? null : string0 === string00 ? interpolate0 : interpolate0 = interpolate(string00 = string0, value1);
  };
}
function attrFunction2(name, interpolate, value) {
  var string00, string10, interpolate0;
  return function() {
    var string0, value1 = value(this), string1;
    if (value1 == null) return void this.removeAttribute(name);
    string0 = this.getAttribute(name);
    string1 = value1 + "";
    return string0 === string1 ? null : string0 === string00 && string1 === string10 ? interpolate0 : (string10 = string1, interpolate0 = interpolate(string00 = string0, value1));
  };
}
function attrFunctionNS2(fullname, interpolate, value) {
  var string00, string10, interpolate0;
  return function() {
    var string0, value1 = value(this), string1;
    if (value1 == null) return void this.removeAttributeNS(fullname.space, fullname.local);
    string0 = this.getAttributeNS(fullname.space, fullname.local);
    string1 = value1 + "";
    return string0 === string1 ? null : string0 === string00 && string1 === string10 ? interpolate0 : (string10 = string1, interpolate0 = interpolate(string00 = string0, value1));
  };
}
function attr_default2(name, value) {
  var fullname = namespace_default(name), i = fullname === "transform" ? interpolateTransformSvg : interpolate_default;
  return this.attrTween(name, typeof value === "function" ? (fullname.local ? attrFunctionNS2 : attrFunction2)(fullname, i, tweenValue(this, "attr." + name, value)) : value == null ? (fullname.local ? attrRemoveNS2 : attrRemove2)(fullname) : (fullname.local ? attrConstantNS2 : attrConstant2)(fullname, i, value));
}

// node_modules/d3-transition/src/transition/attrTween.js
function attrInterpolate(name, i) {
  return function(t2) {
    this.setAttribute(name, i.call(this, t2));
  };
}
function attrInterpolateNS(fullname, i) {
  return function(t2) {
    this.setAttributeNS(fullname.space, fullname.local, i.call(this, t2));
  };
}
function attrTweenNS(fullname, value) {
  var t0, i0;
  function tween() {
    var i = value.apply(this, arguments);
    if (i !== i0) t0 = (i0 = i) && attrInterpolateNS(fullname, i);
    return t0;
  }
  tween._value = value;
  return tween;
}
function attrTween(name, value) {
  var t0, i0;
  function tween() {
    var i = value.apply(this, arguments);
    if (i !== i0) t0 = (i0 = i) && attrInterpolate(name, i);
    return t0;
  }
  tween._value = value;
  return tween;
}
function attrTween_default(name, value) {
  var key = "attr." + name;
  if (arguments.length < 2) return (key = this.tween(key)) && key._value;
  if (value == null) return this.tween(key, null);
  if (typeof value !== "function") throw new Error();
  var fullname = namespace_default(name);
  return this.tween(key, (fullname.local ? attrTweenNS : attrTween)(fullname, value));
}

// node_modules/d3-transition/src/transition/delay.js
function delayFunction(id2, value) {
  return function() {
    init(this, id2).delay = +value.apply(this, arguments);
  };
}
function delayConstant(id2, value) {
  return value = +value, function() {
    init(this, id2).delay = value;
  };
}
function delay_default(value) {
  var id2 = this._id;
  return arguments.length ? this.each((typeof value === "function" ? delayFunction : delayConstant)(id2, value)) : get2(this.node(), id2).delay;
}

// node_modules/d3-transition/src/transition/duration.js
function durationFunction(id2, value) {
  return function() {
    set2(this, id2).duration = +value.apply(this, arguments);
  };
}
function durationConstant(id2, value) {
  return value = +value, function() {
    set2(this, id2).duration = value;
  };
}
function duration_default(value) {
  var id2 = this._id;
  return arguments.length ? this.each((typeof value === "function" ? durationFunction : durationConstant)(id2, value)) : get2(this.node(), id2).duration;
}

// node_modules/d3-transition/src/transition/ease.js
function easeConstant(id2, value) {
  if (typeof value !== "function") throw new Error();
  return function() {
    set2(this, id2).ease = value;
  };
}
function ease_default(value) {
  var id2 = this._id;
  return arguments.length ? this.each(easeConstant(id2, value)) : get2(this.node(), id2).ease;
}

// node_modules/d3-transition/src/transition/easeVarying.js
function easeVarying(id2, value) {
  return function() {
    var v = value.apply(this, arguments);
    if (typeof v !== "function") throw new Error();
    set2(this, id2).ease = v;
  };
}
function easeVarying_default(value) {
  if (typeof value !== "function") throw new Error();
  return this.each(easeVarying(this._id, value));
}

// node_modules/d3-transition/src/transition/filter.js
function filter_default2(match) {
  if (typeof match !== "function") match = matcher_default(match);
  for (var groups = this._groups, m2 = groups.length, subgroups = new Array(m2), j = 0; j < m2; ++j) {
    for (var group = groups[j], n = group.length, subgroup = subgroups[j] = [], node, i = 0; i < n; ++i) {
      if ((node = group[i]) && match.call(node, node.__data__, i, group)) {
        subgroup.push(node);
      }
    }
  }
  return new Transition(subgroups, this._parents, this._name, this._id);
}

// node_modules/d3-transition/src/transition/merge.js
function merge_default2(transition2) {
  if (transition2._id !== this._id) throw new Error();
  for (var groups0 = this._groups, groups1 = transition2._groups, m0 = groups0.length, m1 = groups1.length, m2 = Math.min(m0, m1), merges = new Array(m0), j = 0; j < m2; ++j) {
    for (var group0 = groups0[j], group1 = groups1[j], n = group0.length, merge = merges[j] = new Array(n), node, i = 0; i < n; ++i) {
      if (node = group0[i] || group1[i]) {
        merge[i] = node;
      }
    }
  }
  for (; j < m0; ++j) {
    merges[j] = groups0[j];
  }
  return new Transition(merges, this._parents, this._name, this._id);
}

// node_modules/d3-transition/src/transition/on.js
function start(name) {
  return (name + "").trim().split(/^|\s+/).every(function(t2) {
    var i = t2.indexOf(".");
    if (i >= 0) t2 = t2.slice(0, i);
    return !t2 || t2 === "start";
  });
}
function onFunction(id2, name, listener) {
  var on0, on1, sit = start(name) ? init : set2;
  return function() {
    var schedule = sit(this, id2), on = schedule.on;
    if (on !== on0) (on1 = (on0 = on).copy()).on(name, listener);
    schedule.on = on1;
  };
}
function on_default2(name, listener) {
  var id2 = this._id;
  return arguments.length < 2 ? get2(this.node(), id2).on.on(name) : this.each(onFunction(id2, name, listener));
}

// node_modules/d3-transition/src/transition/remove.js
function removeFunction(id2) {
  return function() {
    var parent = this.parentNode;
    for (var i in this.__transition) if (+i !== id2) return;
    if (parent) parent.removeChild(this);
  };
}
function remove_default2() {
  return this.on("end.remove", removeFunction(this._id));
}

// node_modules/d3-transition/src/transition/select.js
function select_default3(select) {
  var name = this._name, id2 = this._id;
  if (typeof select !== "function") select = selector_default(select);
  for (var groups = this._groups, m2 = groups.length, subgroups = new Array(m2), j = 0; j < m2; ++j) {
    for (var group = groups[j], n = group.length, subgroup = subgroups[j] = new Array(n), node, subnode, i = 0; i < n; ++i) {
      if ((node = group[i]) && (subnode = select.call(node, node.__data__, i, group))) {
        if ("__data__" in node) subnode.__data__ = node.__data__;
        subgroup[i] = subnode;
        schedule_default(subgroup[i], name, id2, i, subgroup, get2(node, id2));
      }
    }
  }
  return new Transition(subgroups, this._parents, name, id2);
}

// node_modules/d3-transition/src/transition/selectAll.js
function selectAll_default2(select) {
  var name = this._name, id2 = this._id;
  if (typeof select !== "function") select = selectorAll_default(select);
  for (var groups = this._groups, m2 = groups.length, subgroups = [], parents = [], j = 0; j < m2; ++j) {
    for (var group = groups[j], n = group.length, node, i = 0; i < n; ++i) {
      if (node = group[i]) {
        for (var children2 = select.call(node, node.__data__, i, group), child, inherit2 = get2(node, id2), k = 0, l = children2.length; k < l; ++k) {
          if (child = children2[k]) {
            schedule_default(child, name, id2, k, children2, inherit2);
          }
        }
        subgroups.push(children2);
        parents.push(node);
      }
    }
  }
  return new Transition(subgroups, parents, name, id2);
}

// node_modules/d3-transition/src/transition/selection.js
var Selection2 = selection_default.prototype.constructor;
function selection_default2() {
  return new Selection2(this._groups, this._parents);
}

// node_modules/d3-transition/src/transition/style.js
function styleNull(name, interpolate) {
  var string00, string10, interpolate0;
  return function() {
    var string0 = styleValue(this, name), string1 = (this.style.removeProperty(name), styleValue(this, name));
    return string0 === string1 ? null : string0 === string00 && string1 === string10 ? interpolate0 : interpolate0 = interpolate(string00 = string0, string10 = string1);
  };
}
function styleRemove2(name) {
  return function() {
    this.style.removeProperty(name);
  };
}
function styleConstant2(name, interpolate, value1) {
  var string00, string1 = value1 + "", interpolate0;
  return function() {
    var string0 = styleValue(this, name);
    return string0 === string1 ? null : string0 === string00 ? interpolate0 : interpolate0 = interpolate(string00 = string0, value1);
  };
}
function styleFunction2(name, interpolate, value) {
  var string00, string10, interpolate0;
  return function() {
    var string0 = styleValue(this, name), value1 = value(this), string1 = value1 + "";
    if (value1 == null) string1 = value1 = (this.style.removeProperty(name), styleValue(this, name));
    return string0 === string1 ? null : string0 === string00 && string1 === string10 ? interpolate0 : (string10 = string1, interpolate0 = interpolate(string00 = string0, value1));
  };
}
function styleMaybeRemove(id2, name) {
  var on0, on1, listener0, key = "style." + name, event = "end." + key, remove2;
  return function() {
    var schedule = set2(this, id2), on = schedule.on, listener = schedule.value[key] == null ? remove2 || (remove2 = styleRemove2(name)) : void 0;
    if (on !== on0 || listener0 !== listener) (on1 = (on0 = on).copy()).on(event, listener0 = listener);
    schedule.on = on1;
  };
}
function style_default2(name, value, priority) {
  var i = (name += "") === "transform" ? interpolateTransformCss : interpolate_default;
  return value == null ? this.styleTween(name, styleNull(name, i)).on("end.style." + name, styleRemove2(name)) : typeof value === "function" ? this.styleTween(name, styleFunction2(name, i, tweenValue(this, "style." + name, value))).each(styleMaybeRemove(this._id, name)) : this.styleTween(name, styleConstant2(name, i, value), priority).on("end.style." + name, null);
}

// node_modules/d3-transition/src/transition/styleTween.js
function styleInterpolate(name, i, priority) {
  return function(t2) {
    this.style.setProperty(name, i.call(this, t2), priority);
  };
}
function styleTween(name, value, priority) {
  var t2, i0;
  function tween() {
    var i = value.apply(this, arguments);
    if (i !== i0) t2 = (i0 = i) && styleInterpolate(name, i, priority);
    return t2;
  }
  tween._value = value;
  return tween;
}
function styleTween_default(name, value, priority) {
  var key = "style." + (name += "");
  if (arguments.length < 2) return (key = this.tween(key)) && key._value;
  if (value == null) return this.tween(key, null);
  if (typeof value !== "function") throw new Error();
  return this.tween(key, styleTween(name, value, priority == null ? "" : priority));
}

// node_modules/d3-transition/src/transition/text.js
function textConstant2(value) {
  return function() {
    this.textContent = value;
  };
}
function textFunction2(value) {
  return function() {
    var value1 = value(this);
    this.textContent = value1 == null ? "" : value1;
  };
}
function text_default2(value) {
  return this.tween("text", typeof value === "function" ? textFunction2(tweenValue(this, "text", value)) : textConstant2(value == null ? "" : value + ""));
}

// node_modules/d3-transition/src/transition/textTween.js
function textInterpolate(i) {
  return function(t2) {
    this.textContent = i.call(this, t2);
  };
}
function textTween(value) {
  var t0, i0;
  function tween() {
    var i = value.apply(this, arguments);
    if (i !== i0) t0 = (i0 = i) && textInterpolate(i);
    return t0;
  }
  tween._value = value;
  return tween;
}
function textTween_default(value) {
  var key = "text";
  if (arguments.length < 1) return (key = this.tween(key)) && key._value;
  if (value == null) return this.tween(key, null);
  if (typeof value !== "function") throw new Error();
  return this.tween(key, textTween(value));
}

// node_modules/d3-transition/src/transition/transition.js
function transition_default() {
  var name = this._name, id0 = this._id, id1 = newId();
  for (var groups = this._groups, m2 = groups.length, j = 0; j < m2; ++j) {
    for (var group = groups[j], n = group.length, node, i = 0; i < n; ++i) {
      if (node = group[i]) {
        var inherit2 = get2(node, id0);
        schedule_default(node, name, id1, i, group, {
          time: inherit2.time + inherit2.delay + inherit2.duration,
          delay: 0,
          duration: inherit2.duration,
          ease: inherit2.ease
        });
      }
    }
  }
  return new Transition(groups, this._parents, name, id1);
}

// node_modules/d3-transition/src/transition/end.js
function end_default() {
  var on0, on1, that = this, id2 = that._id, size = that.size();
  return new Promise(function(resolve, reject) {
    var cancel = { value: reject }, end = { value: function() {
      if (--size === 0) resolve();
    } };
    that.each(function() {
      var schedule = set2(this, id2), on = schedule.on;
      if (on !== on0) {
        on1 = (on0 = on).copy();
        on1._.cancel.push(cancel);
        on1._.interrupt.push(cancel);
        on1._.end.push(end);
      }
      schedule.on = on1;
    });
    if (size === 0) resolve();
  });
}

// node_modules/d3-transition/src/transition/index.js
var id = 0;
function Transition(groups, parents, name, id2) {
  this._groups = groups;
  this._parents = parents;
  this._name = name;
  this._id = id2;
}
function transition(name) {
  return selection_default().transition(name);
}
function newId() {
  return ++id;
}
var selection_prototype = selection_default.prototype;
Transition.prototype = transition.prototype = {
  constructor: Transition,
  select: select_default3,
  selectAll: selectAll_default2,
  selectChild: selection_prototype.selectChild,
  selectChildren: selection_prototype.selectChildren,
  filter: filter_default2,
  merge: merge_default2,
  selection: selection_default2,
  transition: transition_default,
  call: selection_prototype.call,
  nodes: selection_prototype.nodes,
  node: selection_prototype.node,
  size: selection_prototype.size,
  empty: selection_prototype.empty,
  each: selection_prototype.each,
  on: on_default2,
  attr: attr_default2,
  attrTween: attrTween_default,
  style: style_default2,
  styleTween: styleTween_default,
  text: text_default2,
  textTween: textTween_default,
  remove: remove_default2,
  tween: tween_default,
  delay: delay_default,
  duration: duration_default,
  ease: ease_default,
  easeVarying: easeVarying_default,
  end: end_default,
  [Symbol.iterator]: selection_prototype[Symbol.iterator]
};

// node_modules/d3-ease/src/cubic.js
function cubicInOut(t2) {
  return ((t2 *= 2) <= 1 ? t2 * t2 * t2 : (t2 -= 2) * t2 * t2 + 2) / 2;
}

// node_modules/d3-transition/src/selection/transition.js
var defaultTiming = {
  time: null,
  // Set on use.
  delay: 0,
  duration: 250,
  ease: cubicInOut
};
function inherit(node, id2) {
  var timing;
  while (!(timing = node.__transition) || !(timing = timing[id2])) {
    if (!(node = node.parentNode)) {
      throw new Error(`transition ${id2} not found`);
    }
  }
  return timing;
}
function transition_default2(name) {
  var id2, timing;
  if (name instanceof Transition) {
    id2 = name._id, name = name._name;
  } else {
    id2 = newId(), (timing = defaultTiming).time = now(), name = name == null ? null : name + "";
  }
  for (var groups = this._groups, m2 = groups.length, j = 0; j < m2; ++j) {
    for (var group = groups[j], n = group.length, node, i = 0; i < n; ++i) {
      if (node = group[i]) {
        schedule_default(node, name, id2, i, group, timing || inherit(node, id2));
      }
    }
  }
  return new Transition(groups, this._parents, name, id2);
}

// node_modules/d3-transition/src/selection/index.js
selection_default.prototype.interrupt = interrupt_default2;
selection_default.prototype.transition = transition_default2;

// node_modules/d3-brush/src/brush.js
var { abs, max, min } = Math;
function number1(e) {
  return [+e[0], +e[1]];
}
function number22(e) {
  return [number1(e[0]), number1(e[1])];
}
var X = {
  name: "x",
  handles: ["w", "e"].map(type),
  input: function(x3, e) {
    return x3 == null ? null : [[+x3[0], e[0][1]], [+x3[1], e[1][1]]];
  },
  output: function(xy) {
    return xy && [xy[0][0], xy[1][0]];
  }
};
var Y = {
  name: "y",
  handles: ["n", "s"].map(type),
  input: function(y3, e) {
    return y3 == null ? null : [[e[0][0], +y3[0]], [e[1][0], +y3[1]]];
  },
  output: function(xy) {
    return xy && [xy[0][1], xy[1][1]];
  }
};
var XY = {
  name: "xy",
  handles: ["n", "w", "e", "s", "nw", "ne", "sw", "se"].map(type),
  input: function(xy) {
    return xy == null ? null : number22(xy);
  },
  output: function(xy) {
    return xy;
  }
};
function type(t2) {
  return { type: t2 };
}

// node_modules/d3-path/src/path.js
var pi = Math.PI;
var tau = 2 * pi;
var epsilon3 = 1e-6;
var tauEpsilon = tau - epsilon3;
function append(strings) {
  this._ += strings[0];
  for (let i = 1, n = strings.length; i < n; ++i) {
    this._ += arguments[i] + strings[i];
  }
}
function appendRound(digits2) {
  let d = Math.floor(digits2);
  if (!(d >= 0)) throw new Error(`invalid digits: ${digits2}`);
  if (d > 15) return append;
  const k = 10 ** d;
  return function(strings) {
    this._ += strings[0];
    for (let i = 1, n = strings.length; i < n; ++i) {
      this._ += Math.round(arguments[i] * k) / k + strings[i];
    }
  };
}
var Path = class {
  constructor(digits2) {
    this._x0 = this._y0 = // start of current subpath
    this._x1 = this._y1 = null;
    this._ = "";
    this._append = digits2 == null ? append : appendRound(digits2);
  }
  moveTo(x3, y3) {
    this._append`M${this._x0 = this._x1 = +x3},${this._y0 = this._y1 = +y3}`;
  }
  closePath() {
    if (this._x1 !== null) {
      this._x1 = this._x0, this._y1 = this._y0;
      this._append`Z`;
    }
  }
  lineTo(x3, y3) {
    this._append`L${this._x1 = +x3},${this._y1 = +y3}`;
  }
  quadraticCurveTo(x1, y1, x3, y3) {
    this._append`Q${+x1},${+y1},${this._x1 = +x3},${this._y1 = +y3}`;
  }
  bezierCurveTo(x1, y1, x22, y22, x3, y3) {
    this._append`C${+x1},${+y1},${+x22},${+y22},${this._x1 = +x3},${this._y1 = +y3}`;
  }
  arcTo(x1, y1, x22, y22, r) {
    x1 = +x1, y1 = +y1, x22 = +x22, y22 = +y22, r = +r;
    if (r < 0) throw new Error(`negative radius: ${r}`);
    let x0 = this._x1, y0 = this._y1, x21 = x22 - x1, y21 = y22 - y1, x01 = x0 - x1, y01 = y0 - y1, l01_2 = x01 * x01 + y01 * y01;
    if (this._x1 === null) {
      this._append`M${this._x1 = x1},${this._y1 = y1}`;
    } else if (!(l01_2 > epsilon3)) ;
    else if (!(Math.abs(y01 * x21 - y21 * x01) > epsilon3) || !r) {
      this._append`L${this._x1 = x1},${this._y1 = y1}`;
    } else {
      let x20 = x22 - x0, y20 = y22 - y0, l21_2 = x21 * x21 + y21 * y21, l20_2 = x20 * x20 + y20 * y20, l21 = Math.sqrt(l21_2), l01 = Math.sqrt(l01_2), l = r * Math.tan((pi - Math.acos((l21_2 + l01_2 - l20_2) / (2 * l21 * l01))) / 2), t01 = l / l01, t21 = l / l21;
      if (Math.abs(t01 - 1) > epsilon3) {
        this._append`L${x1 + t01 * x01},${y1 + t01 * y01}`;
      }
      this._append`A${r},${r},0,0,${+(y01 * x20 > x01 * y20)},${this._x1 = x1 + t21 * x21},${this._y1 = y1 + t21 * y21}`;
    }
  }
  arc(x3, y3, r, a0, a1, ccw) {
    x3 = +x3, y3 = +y3, r = +r, ccw = !!ccw;
    if (r < 0) throw new Error(`negative radius: ${r}`);
    let dx = r * Math.cos(a0), dy = r * Math.sin(a0), x0 = x3 + dx, y0 = y3 + dy, cw = 1 ^ ccw, da = ccw ? a0 - a1 : a1 - a0;
    if (this._x1 === null) {
      this._append`M${x0},${y0}`;
    } else if (Math.abs(this._x1 - x0) > epsilon3 || Math.abs(this._y1 - y0) > epsilon3) {
      this._append`L${x0},${y0}`;
    }
    if (!r) return;
    if (da < 0) da = da % tau + tau;
    if (da > tauEpsilon) {
      this._append`A${r},${r},0,1,${cw},${x3 - dx},${y3 - dy}A${r},${r},0,1,${cw},${this._x1 = x0},${this._y1 = y0}`;
    } else if (da > epsilon3) {
      this._append`A${r},${r},0,${+(da >= pi)},${cw},${this._x1 = x3 + r * Math.cos(a1)},${this._y1 = y3 + r * Math.sin(a1)}`;
    }
  }
  rect(x3, y3, w, h) {
    this._append`M${this._x0 = this._x1 = +x3},${this._y0 = this._y1 = +y3}h${w = +w}v${+h}h${-w}Z`;
  }
  toString() {
    return this._;
  }
};
function path() {
  return new Path();
}
path.prototype = Path.prototype;

// node_modules/d3-quadtree/src/add.js
function add_default(d) {
  const x3 = +this._x.call(null, d), y3 = +this._y.call(null, d);
  return add(this.cover(x3, y3), x3, y3, d);
}
function add(tree, x3, y3, d) {
  if (isNaN(x3) || isNaN(y3)) return tree;
  var parent, node = tree._root, leaf = { data: d }, x0 = tree._x0, y0 = tree._y0, x1 = tree._x1, y1 = tree._y1, xm, ym, xp, yp, right2, bottom2, i, j;
  if (!node) return tree._root = leaf, tree;
  while (node.length) {
    if (right2 = x3 >= (xm = (x0 + x1) / 2)) x0 = xm;
    else x1 = xm;
    if (bottom2 = y3 >= (ym = (y0 + y1) / 2)) y0 = ym;
    else y1 = ym;
    if (parent = node, !(node = node[i = bottom2 << 1 | right2])) return parent[i] = leaf, tree;
  }
  xp = +tree._x.call(null, node.data);
  yp = +tree._y.call(null, node.data);
  if (x3 === xp && y3 === yp) return leaf.next = node, parent ? parent[i] = leaf : tree._root = leaf, tree;
  do {
    parent = parent ? parent[i] = new Array(4) : tree._root = new Array(4);
    if (right2 = x3 >= (xm = (x0 + x1) / 2)) x0 = xm;
    else x1 = xm;
    if (bottom2 = y3 >= (ym = (y0 + y1) / 2)) y0 = ym;
    else y1 = ym;
  } while ((i = bottom2 << 1 | right2) === (j = (yp >= ym) << 1 | xp >= xm));
  return parent[j] = node, parent[i] = leaf, tree;
}
function addAll(data) {
  var d, i, n = data.length, x3, y3, xz = new Array(n), yz = new Array(n), x0 = Infinity, y0 = Infinity, x1 = -Infinity, y1 = -Infinity;
  for (i = 0; i < n; ++i) {
    if (isNaN(x3 = +this._x.call(null, d = data[i])) || isNaN(y3 = +this._y.call(null, d))) continue;
    xz[i] = x3;
    yz[i] = y3;
    if (x3 < x0) x0 = x3;
    if (x3 > x1) x1 = x3;
    if (y3 < y0) y0 = y3;
    if (y3 > y1) y1 = y3;
  }
  if (x0 > x1 || y0 > y1) return this;
  this.cover(x0, y0).cover(x1, y1);
  for (i = 0; i < n; ++i) {
    add(this, xz[i], yz[i], data[i]);
  }
  return this;
}

// node_modules/d3-quadtree/src/cover.js
function cover_default(x3, y3) {
  if (isNaN(x3 = +x3) || isNaN(y3 = +y3)) return this;
  var x0 = this._x0, y0 = this._y0, x1 = this._x1, y1 = this._y1;
  if (isNaN(x0)) {
    x1 = (x0 = Math.floor(x3)) + 1;
    y1 = (y0 = Math.floor(y3)) + 1;
  } else {
    var z = x1 - x0 || 1, node = this._root, parent, i;
    while (x0 > x3 || x3 >= x1 || y0 > y3 || y3 >= y1) {
      i = (y3 < y0) << 1 | x3 < x0;
      parent = new Array(4), parent[i] = node, node = parent, z *= 2;
      switch (i) {
        case 0:
          x1 = x0 + z, y1 = y0 + z;
          break;
        case 1:
          x0 = x1 - z, y1 = y0 + z;
          break;
        case 2:
          x1 = x0 + z, y0 = y1 - z;
          break;
        case 3:
          x0 = x1 - z, y0 = y1 - z;
          break;
      }
    }
    if (this._root && this._root.length) this._root = node;
  }
  this._x0 = x0;
  this._y0 = y0;
  this._x1 = x1;
  this._y1 = y1;
  return this;
}

// node_modules/d3-quadtree/src/data.js
function data_default2() {
  var data = [];
  this.visit(function(node) {
    if (!node.length) do
      data.push(node.data);
    while (node = node.next);
  });
  return data;
}

// node_modules/d3-quadtree/src/extent.js
function extent_default(_) {
  return arguments.length ? this.cover(+_[0][0], +_[0][1]).cover(+_[1][0], +_[1][1]) : isNaN(this._x0) ? void 0 : [[this._x0, this._y0], [this._x1, this._y1]];
}

// node_modules/d3-quadtree/src/quad.js
function quad_default(node, x0, y0, x1, y1) {
  this.node = node;
  this.x0 = x0;
  this.y0 = y0;
  this.x1 = x1;
  this.y1 = y1;
}

// node_modules/d3-quadtree/src/find.js
function find_default(x3, y3, radius) {
  var data, x0 = this._x0, y0 = this._y0, x1, y1, x22, y22, x32 = this._x1, y32 = this._y1, quads = [], node = this._root, q, i;
  if (node) quads.push(new quad_default(node, x0, y0, x32, y32));
  if (radius == null) radius = Infinity;
  else {
    x0 = x3 - radius, y0 = y3 - radius;
    x32 = x3 + radius, y32 = y3 + radius;
    radius *= radius;
  }
  while (q = quads.pop()) {
    if (!(node = q.node) || (x1 = q.x0) > x32 || (y1 = q.y0) > y32 || (x22 = q.x1) < x0 || (y22 = q.y1) < y0) continue;
    if (node.length) {
      var xm = (x1 + x22) / 2, ym = (y1 + y22) / 2;
      quads.push(
        new quad_default(node[3], xm, ym, x22, y22),
        new quad_default(node[2], x1, ym, xm, y22),
        new quad_default(node[1], xm, y1, x22, ym),
        new quad_default(node[0], x1, y1, xm, ym)
      );
      if (i = (y3 >= ym) << 1 | x3 >= xm) {
        q = quads[quads.length - 1];
        quads[quads.length - 1] = quads[quads.length - 1 - i];
        quads[quads.length - 1 - i] = q;
      }
    } else {
      var dx = x3 - +this._x.call(null, node.data), dy = y3 - +this._y.call(null, node.data), d2 = dx * dx + dy * dy;
      if (d2 < radius) {
        var d = Math.sqrt(radius = d2);
        x0 = x3 - d, y0 = y3 - d;
        x32 = x3 + d, y32 = y3 + d;
        data = node.data;
      }
    }
  }
  return data;
}

// node_modules/d3-quadtree/src/remove.js
function remove_default3(d) {
  if (isNaN(x3 = +this._x.call(null, d)) || isNaN(y3 = +this._y.call(null, d))) return this;
  var parent, node = this._root, retainer, previous, next, x0 = this._x0, y0 = this._y0, x1 = this._x1, y1 = this._y1, x3, y3, xm, ym, right2, bottom2, i, j;
  if (!node) return this;
  if (node.length) while (true) {
    if (right2 = x3 >= (xm = (x0 + x1) / 2)) x0 = xm;
    else x1 = xm;
    if (bottom2 = y3 >= (ym = (y0 + y1) / 2)) y0 = ym;
    else y1 = ym;
    if (!(parent = node, node = node[i = bottom2 << 1 | right2])) return this;
    if (!node.length) break;
    if (parent[i + 1 & 3] || parent[i + 2 & 3] || parent[i + 3 & 3]) retainer = parent, j = i;
  }
  while (node.data !== d) if (!(previous = node, node = node.next)) return this;
  if (next = node.next) delete node.next;
  if (previous) return next ? previous.next = next : delete previous.next, this;
  if (!parent) return this._root = next, this;
  next ? parent[i] = next : delete parent[i];
  if ((node = parent[0] || parent[1] || parent[2] || parent[3]) && node === (parent[3] || parent[2] || parent[1] || parent[0]) && !node.length) {
    if (retainer) retainer[j] = node;
    else this._root = node;
  }
  return this;
}
function removeAll(data) {
  for (var i = 0, n = data.length; i < n; ++i) this.remove(data[i]);
  return this;
}

// node_modules/d3-quadtree/src/root.js
function root_default() {
  return this._root;
}

// node_modules/d3-quadtree/src/size.js
function size_default2() {
  var size = 0;
  this.visit(function(node) {
    if (!node.length) do
      ++size;
    while (node = node.next);
  });
  return size;
}

// node_modules/d3-quadtree/src/visit.js
function visit_default(callback) {
  var quads = [], q, node = this._root, child, x0, y0, x1, y1;
  if (node) quads.push(new quad_default(node, this._x0, this._y0, this._x1, this._y1));
  while (q = quads.pop()) {
    if (!callback(node = q.node, x0 = q.x0, y0 = q.y0, x1 = q.x1, y1 = q.y1) && node.length) {
      var xm = (x0 + x1) / 2, ym = (y0 + y1) / 2;
      if (child = node[3]) quads.push(new quad_default(child, xm, ym, x1, y1));
      if (child = node[2]) quads.push(new quad_default(child, x0, ym, xm, y1));
      if (child = node[1]) quads.push(new quad_default(child, xm, y0, x1, ym));
      if (child = node[0]) quads.push(new quad_default(child, x0, y0, xm, ym));
    }
  }
  return this;
}

// node_modules/d3-quadtree/src/visitAfter.js
function visitAfter_default(callback) {
  var quads = [], next = [], q;
  if (this._root) quads.push(new quad_default(this._root, this._x0, this._y0, this._x1, this._y1));
  while (q = quads.pop()) {
    var node = q.node;
    if (node.length) {
      var child, x0 = q.x0, y0 = q.y0, x1 = q.x1, y1 = q.y1, xm = (x0 + x1) / 2, ym = (y0 + y1) / 2;
      if (child = node[0]) quads.push(new quad_default(child, x0, y0, xm, ym));
      if (child = node[1]) quads.push(new quad_default(child, xm, y0, x1, ym));
      if (child = node[2]) quads.push(new quad_default(child, x0, ym, xm, y1));
      if (child = node[3]) quads.push(new quad_default(child, xm, ym, x1, y1));
    }
    next.push(q);
  }
  while (q = next.pop()) {
    callback(q.node, q.x0, q.y0, q.x1, q.y1);
  }
  return this;
}

// node_modules/d3-quadtree/src/x.js
function defaultX(d) {
  return d[0];
}
function x_default(_) {
  return arguments.length ? (this._x = _, this) : this._x;
}

// node_modules/d3-quadtree/src/y.js
function defaultY(d) {
  return d[1];
}
function y_default(_) {
  return arguments.length ? (this._y = _, this) : this._y;
}

// node_modules/d3-quadtree/src/quadtree.js
function quadtree(nodes, x3, y3) {
  var tree = new Quadtree(x3 == null ? defaultX : x3, y3 == null ? defaultY : y3, NaN, NaN, NaN, NaN);
  return nodes == null ? tree : tree.addAll(nodes);
}
function Quadtree(x3, y3, x0, y0, x1, y1) {
  this._x = x3;
  this._y = y3;
  this._x0 = x0;
  this._y0 = y0;
  this._x1 = x1;
  this._y1 = y1;
  this._root = void 0;
}
function leaf_copy(leaf) {
  var copy2 = { data: leaf.data }, next = copy2;
  while (leaf = leaf.next) next = next.next = { data: leaf.data };
  return copy2;
}
var treeProto = quadtree.prototype = Quadtree.prototype;
treeProto.copy = function() {
  var copy2 = new Quadtree(this._x, this._y, this._x0, this._y0, this._x1, this._y1), node = this._root, nodes, child;
  if (!node) return copy2;
  if (!node.length) return copy2._root = leaf_copy(node), copy2;
  nodes = [{ source: node, target: copy2._root = new Array(4) }];
  while (node = nodes.pop()) {
    for (var i = 0; i < 4; ++i) {
      if (child = node.source[i]) {
        if (child.length) nodes.push({ source: child, target: node.target[i] = new Array(4) });
        else node.target[i] = leaf_copy(child);
      }
    }
  }
  return copy2;
};
treeProto.add = add_default;
treeProto.addAll = addAll;
treeProto.cover = cover_default;
treeProto.data = data_default2;
treeProto.extent = extent_default;
treeProto.find = find_default;
treeProto.remove = remove_default3;
treeProto.removeAll = removeAll;
treeProto.root = root_default;
treeProto.size = size_default2;
treeProto.visit = visit_default;
treeProto.visitAfter = visitAfter_default;
treeProto.x = x_default;
treeProto.y = y_default;

// node_modules/d3-force/src/constant.js
function constant_default5(x3) {
  return function() {
    return x3;
  };
}

// node_modules/d3-force/src/jiggle.js
function jiggle_default(random2) {
  return (random2() - 0.5) * 1e-6;
}

// node_modules/d3-force/src/collide.js
function x(d) {
  return d.x + d.vx;
}
function y(d) {
  return d.y + d.vy;
}
function collide_default(radius) {
  var nodes, radii, random2, strength = 1, iterations = 1;
  if (typeof radius !== "function") radius = constant_default5(radius == null ? 1 : +radius);
  function force() {
    var i, n = nodes.length, tree, node, xi, yi, ri, ri2;
    for (var k = 0; k < iterations; ++k) {
      tree = quadtree(nodes, x, y).visitAfter(prepare);
      for (i = 0; i < n; ++i) {
        node = nodes[i];
        ri = radii[node.index], ri2 = ri * ri;
        xi = node.x + node.vx;
        yi = node.y + node.vy;
        tree.visit(apply);
      }
    }
    function apply(quad, x0, y0, x1, y1) {
      var data = quad.data, rj = quad.r, r = ri + rj;
      if (data) {
        if (data.index > node.index) {
          var x3 = xi - data.x - data.vx, y3 = yi - data.y - data.vy, l = x3 * x3 + y3 * y3;
          if (l < r * r) {
            if (x3 === 0) x3 = jiggle_default(random2), l += x3 * x3;
            if (y3 === 0) y3 = jiggle_default(random2), l += y3 * y3;
            l = (r - (l = Math.sqrt(l))) / l * strength;
            node.vx += (x3 *= l) * (r = (rj *= rj) / (ri2 + rj));
            node.vy += (y3 *= l) * r;
            data.vx -= x3 * (r = 1 - r);
            data.vy -= y3 * r;
          }
        }
        return;
      }
      return x0 > xi + r || x1 < xi - r || y0 > yi + r || y1 < yi - r;
    }
  }
  function prepare(quad) {
    if (quad.data) return quad.r = radii[quad.data.index];
    for (var i = quad.r = 0; i < 4; ++i) {
      if (quad[i] && quad[i].r > quad.r) {
        quad.r = quad[i].r;
      }
    }
  }
  function initialize() {
    if (!nodes) return;
    var i, n = nodes.length, node;
    radii = new Array(n);
    for (i = 0; i < n; ++i) node = nodes[i], radii[node.index] = +radius(node, i, nodes);
  }
  force.initialize = function(_nodes, _random) {
    nodes = _nodes;
    random2 = _random;
    initialize();
  };
  force.iterations = function(_) {
    return arguments.length ? (iterations = +_, force) : iterations;
  };
  force.strength = function(_) {
    return arguments.length ? (strength = +_, force) : strength;
  };
  force.radius = function(_) {
    return arguments.length ? (radius = typeof _ === "function" ? _ : constant_default5(+_), initialize(), force) : radius;
  };
  return force;
}

// node_modules/d3-force/src/link.js
function index(d) {
  return d.index;
}
function find2(nodeById, nodeId) {
  var node = nodeById.get(nodeId);
  if (!node) throw new Error("node not found: " + nodeId);
  return node;
}
function link_default(links) {
  var id2 = index, strength = defaultStrength, strengths, distance = constant_default5(30), distances, nodes, count2, bias, random2, iterations = 1;
  if (links == null) links = [];
  function defaultStrength(link) {
    return 1 / Math.min(count2[link.source.index], count2[link.target.index]);
  }
  function force(alpha) {
    for (var k = 0, n = links.length; k < iterations; ++k) {
      for (var i = 0, link, source, target, x3, y3, l, b; i < n; ++i) {
        link = links[i], source = link.source, target = link.target;
        x3 = target.x + target.vx - source.x - source.vx || jiggle_default(random2);
        y3 = target.y + target.vy - source.y - source.vy || jiggle_default(random2);
        l = Math.sqrt(x3 * x3 + y3 * y3);
        l = (l - distances[i]) / l * alpha * strengths[i];
        x3 *= l, y3 *= l;
        target.vx -= x3 * (b = bias[i]);
        target.vy -= y3 * b;
        source.vx += x3 * (b = 1 - b);
        source.vy += y3 * b;
      }
    }
  }
  function initialize() {
    if (!nodes) return;
    var i, n = nodes.length, m2 = links.length, nodeById = new Map(nodes.map((d, i2) => [id2(d, i2, nodes), d])), link;
    for (i = 0, count2 = new Array(n); i < m2; ++i) {
      link = links[i], link.index = i;
      if (typeof link.source !== "object") link.source = find2(nodeById, link.source);
      if (typeof link.target !== "object") link.target = find2(nodeById, link.target);
      count2[link.source.index] = (count2[link.source.index] || 0) + 1;
      count2[link.target.index] = (count2[link.target.index] || 0) + 1;
    }
    for (i = 0, bias = new Array(m2); i < m2; ++i) {
      link = links[i], bias[i] = count2[link.source.index] / (count2[link.source.index] + count2[link.target.index]);
    }
    strengths = new Array(m2), initializeStrength();
    distances = new Array(m2), initializeDistance();
  }
  function initializeStrength() {
    if (!nodes) return;
    for (var i = 0, n = links.length; i < n; ++i) {
      strengths[i] = +strength(links[i], i, links);
    }
  }
  function initializeDistance() {
    if (!nodes) return;
    for (var i = 0, n = links.length; i < n; ++i) {
      distances[i] = +distance(links[i], i, links);
    }
  }
  force.initialize = function(_nodes, _random) {
    nodes = _nodes;
    random2 = _random;
    initialize();
  };
  force.links = function(_) {
    return arguments.length ? (links = _, initialize(), force) : links;
  };
  force.id = function(_) {
    return arguments.length ? (id2 = _, force) : id2;
  };
  force.iterations = function(_) {
    return arguments.length ? (iterations = +_, force) : iterations;
  };
  force.strength = function(_) {
    return arguments.length ? (strength = typeof _ === "function" ? _ : constant_default5(+_), initializeStrength(), force) : strength;
  };
  force.distance = function(_) {
    return arguments.length ? (distance = typeof _ === "function" ? _ : constant_default5(+_), initializeDistance(), force) : distance;
  };
  return force;
}

// node_modules/d3-force/src/lcg.js
var a = 1664525;
var c = 1013904223;
var m = 4294967296;
function lcg_default() {
  let s = 1;
  return () => (s = (a * s + c) % m) / m;
}

// node_modules/d3-force/src/simulation.js
function x2(d) {
  return d.x;
}
function y2(d) {
  return d.y;
}
var initialRadius = 10;
var initialAngle = Math.PI * (3 - Math.sqrt(5));
function simulation_default(nodes) {
  var simulation, alpha = 1, alphaMin = 1e-3, alphaDecay = 1 - Math.pow(alphaMin, 1 / 300), alphaTarget = 0, velocityDecay = 0.6, forces = /* @__PURE__ */ new Map(), stepper = timer(step), event = dispatch_default("tick", "end"), random2 = lcg_default();
  if (nodes == null) nodes = [];
  function step() {
    tick();
    event.call("tick", simulation);
    if (alpha < alphaMin) {
      stepper.stop();
      event.call("end", simulation);
    }
  }
  function tick(iterations) {
    var i, n = nodes.length, node;
    if (iterations === void 0) iterations = 1;
    for (var k = 0; k < iterations; ++k) {
      alpha += (alphaTarget - alpha) * alphaDecay;
      forces.forEach(function(force) {
        force(alpha);
      });
      for (i = 0; i < n; ++i) {
        node = nodes[i];
        if (node.fx == null) node.x += node.vx *= velocityDecay;
        else node.x = node.fx, node.vx = 0;
        if (node.fy == null) node.y += node.vy *= velocityDecay;
        else node.y = node.fy, node.vy = 0;
      }
    }
    return simulation;
  }
  function initializeNodes() {
    for (var i = 0, n = nodes.length, node; i < n; ++i) {
      node = nodes[i], node.index = i;
      if (node.fx != null) node.x = node.fx;
      if (node.fy != null) node.y = node.fy;
      if (isNaN(node.x) || isNaN(node.y)) {
        var radius = initialRadius * Math.sqrt(0.5 + i), angle = i * initialAngle;
        node.x = radius * Math.cos(angle);
        node.y = radius * Math.sin(angle);
      }
      if (isNaN(node.vx) || isNaN(node.vy)) {
        node.vx = node.vy = 0;
      }
    }
  }
  function initializeForce(force) {
    if (force.initialize) force.initialize(nodes, random2);
    return force;
  }
  initializeNodes();
  return simulation = {
    tick,
    restart: function() {
      return stepper.restart(step), simulation;
    },
    stop: function() {
      return stepper.stop(), simulation;
    },
    nodes: function(_) {
      return arguments.length ? (nodes = _, initializeNodes(), forces.forEach(initializeForce), simulation) : nodes;
    },
    alpha: function(_) {
      return arguments.length ? (alpha = +_, simulation) : alpha;
    },
    alphaMin: function(_) {
      return arguments.length ? (alphaMin = +_, simulation) : alphaMin;
    },
    alphaDecay: function(_) {
      return arguments.length ? (alphaDecay = +_, simulation) : +alphaDecay;
    },
    alphaTarget: function(_) {
      return arguments.length ? (alphaTarget = +_, simulation) : alphaTarget;
    },
    velocityDecay: function(_) {
      return arguments.length ? (velocityDecay = 1 - _, simulation) : 1 - velocityDecay;
    },
    randomSource: function(_) {
      return arguments.length ? (random2 = _, forces.forEach(initializeForce), simulation) : random2;
    },
    force: function(name, _) {
      return arguments.length > 1 ? (_ == null ? forces.delete(name) : forces.set(name, initializeForce(_)), simulation) : forces.get(name);
    },
    find: function(x3, y3, radius) {
      var i = 0, n = nodes.length, dx, dy, d2, node, closest;
      if (radius == null) radius = Infinity;
      else radius *= radius;
      for (i = 0; i < n; ++i) {
        node = nodes[i];
        dx = x3 - node.x;
        dy = y3 - node.y;
        d2 = dx * dx + dy * dy;
        if (d2 < radius) closest = node, radius = d2;
      }
      return closest;
    },
    on: function(name, _) {
      return arguments.length > 1 ? (event.on(name, _), simulation) : event.on(name);
    }
  };
}

// node_modules/d3-force/src/manyBody.js
function manyBody_default() {
  var nodes, node, random2, alpha, strength = constant_default5(-30), strengths, distanceMin2 = 1, distanceMax2 = Infinity, theta2 = 0.81;
  function force(_) {
    var i, n = nodes.length, tree = quadtree(nodes, x2, y2).visitAfter(accumulate);
    for (alpha = _, i = 0; i < n; ++i) node = nodes[i], tree.visit(apply);
  }
  function initialize() {
    if (!nodes) return;
    var i, n = nodes.length, node2;
    strengths = new Array(n);
    for (i = 0; i < n; ++i) node2 = nodes[i], strengths[node2.index] = +strength(node2, i, nodes);
  }
  function accumulate(quad) {
    var strength2 = 0, q, c4, weight = 0, x3, y3, i;
    if (quad.length) {
      for (x3 = y3 = i = 0; i < 4; ++i) {
        if ((q = quad[i]) && (c4 = Math.abs(q.value))) {
          strength2 += q.value, weight += c4, x3 += c4 * q.x, y3 += c4 * q.y;
        }
      }
      quad.x = x3 / weight;
      quad.y = y3 / weight;
    } else {
      q = quad;
      q.x = q.data.x;
      q.y = q.data.y;
      do
        strength2 += strengths[q.data.index];
      while (q = q.next);
    }
    quad.value = strength2;
  }
  function apply(quad, x1, _, x22) {
    if (!quad.value) return true;
    var x3 = quad.x - node.x, y3 = quad.y - node.y, w = x22 - x1, l = x3 * x3 + y3 * y3;
    if (w * w / theta2 < l) {
      if (l < distanceMax2) {
        if (x3 === 0) x3 = jiggle_default(random2), l += x3 * x3;
        if (y3 === 0) y3 = jiggle_default(random2), l += y3 * y3;
        if (l < distanceMin2) l = Math.sqrt(distanceMin2 * l);
        node.vx += x3 * quad.value * alpha / l;
        node.vy += y3 * quad.value * alpha / l;
      }
      return true;
    } else if (quad.length || l >= distanceMax2) return;
    if (quad.data !== node || quad.next) {
      if (x3 === 0) x3 = jiggle_default(random2), l += x3 * x3;
      if (y3 === 0) y3 = jiggle_default(random2), l += y3 * y3;
      if (l < distanceMin2) l = Math.sqrt(distanceMin2 * l);
    }
    do
      if (quad.data !== node) {
        w = strengths[quad.data.index] * alpha / l;
        node.vx += x3 * w;
        node.vy += y3 * w;
      }
    while (quad = quad.next);
  }
  force.initialize = function(_nodes, _random) {
    nodes = _nodes;
    random2 = _random;
    initialize();
  };
  force.strength = function(_) {
    return arguments.length ? (strength = typeof _ === "function" ? _ : constant_default5(+_), initialize(), force) : strength;
  };
  force.distanceMin = function(_) {
    return arguments.length ? (distanceMin2 = _ * _, force) : Math.sqrt(distanceMin2);
  };
  force.distanceMax = function(_) {
    return arguments.length ? (distanceMax2 = _ * _, force) : Math.sqrt(distanceMax2);
  };
  force.theta = function(_) {
    return arguments.length ? (theta2 = _ * _, force) : Math.sqrt(theta2);
  };
  return force;
}

// node_modules/d3-force/src/x.js
function x_default2(x3) {
  var strength = constant_default5(0.1), nodes, strengths, xz;
  if (typeof x3 !== "function") x3 = constant_default5(x3 == null ? 0 : +x3);
  function force(alpha) {
    for (var i = 0, n = nodes.length, node; i < n; ++i) {
      node = nodes[i], node.vx += (xz[i] - node.x) * strengths[i] * alpha;
    }
  }
  function initialize() {
    if (!nodes) return;
    var i, n = nodes.length;
    strengths = new Array(n);
    xz = new Array(n);
    for (i = 0; i < n; ++i) {
      strengths[i] = isNaN(xz[i] = +x3(nodes[i], i, nodes)) ? 0 : +strength(nodes[i], i, nodes);
    }
  }
  force.initialize = function(_) {
    nodes = _;
    initialize();
  };
  force.strength = function(_) {
    return arguments.length ? (strength = typeof _ === "function" ? _ : constant_default5(+_), initialize(), force) : strength;
  };
  force.x = function(_) {
    return arguments.length ? (x3 = typeof _ === "function" ? _ : constant_default5(+_), initialize(), force) : x3;
  };
  return force;
}

// node_modules/d3-force/src/y.js
function y_default2(y3) {
  var strength = constant_default5(0.1), nodes, strengths, yz;
  if (typeof y3 !== "function") y3 = constant_default5(y3 == null ? 0 : +y3);
  function force(alpha) {
    for (var i = 0, n = nodes.length, node; i < n; ++i) {
      node = nodes[i], node.vy += (yz[i] - node.y) * strengths[i] * alpha;
    }
  }
  function initialize() {
    if (!nodes) return;
    var i, n = nodes.length;
    strengths = new Array(n);
    yz = new Array(n);
    for (i = 0; i < n; ++i) {
      strengths[i] = isNaN(yz[i] = +y3(nodes[i], i, nodes)) ? 0 : +strength(nodes[i], i, nodes);
    }
  }
  force.initialize = function(_) {
    nodes = _;
    initialize();
  };
  force.strength = function(_) {
    return arguments.length ? (strength = typeof _ === "function" ? _ : constant_default5(+_), initialize(), force) : strength;
  };
  force.y = function(_) {
    return arguments.length ? (y3 = typeof _ === "function" ? _ : constant_default5(+_), initialize(), force) : y3;
  };
  return force;
}

// node_modules/d3-format/src/formatDecimal.js
function formatDecimal_default(x3) {
  return Math.abs(x3 = Math.round(x3)) >= 1e21 ? x3.toLocaleString("en").replace(/,/g, "") : x3.toString(10);
}
function formatDecimalParts(x3, p) {
  if (!isFinite(x3) || x3 === 0) return null;
  var i = (x3 = p ? x3.toExponential(p - 1) : x3.toExponential()).indexOf("e"), coefficient = x3.slice(0, i);
  return [
    coefficient.length > 1 ? coefficient[0] + coefficient.slice(2) : coefficient,
    +x3.slice(i + 1)
  ];
}

// node_modules/d3-format/src/exponent.js
function exponent_default(x3) {
  return x3 = formatDecimalParts(Math.abs(x3)), x3 ? x3[1] : NaN;
}

// node_modules/d3-format/src/formatGroup.js
function formatGroup_default(grouping, thousands) {
  return function(value, width) {
    var i = value.length, t2 = [], j = 0, g2 = grouping[0], length = 0;
    while (i > 0 && g2 > 0) {
      if (length + g2 + 1 > width) g2 = Math.max(1, width - length);
      t2.push(value.substring(i -= g2, i + g2));
      if ((length += g2 + 1) > width) break;
      g2 = grouping[j = (j + 1) % grouping.length];
    }
    return t2.reverse().join(thousands);
  };
}

// node_modules/d3-format/src/formatNumerals.js
function formatNumerals_default(numerals) {
  return function(value) {
    return value.replace(/[0-9]/g, function(i) {
      return numerals[+i];
    });
  };
}

// node_modules/d3-format/src/formatSpecifier.js
var re = /^(?:(.)?([<>=^]))?([+\-( ])?([$#])?(0)?(\d+)?(,)?(\.\d+)?(~)?([a-z%])?$/i;
function formatSpecifier(specifier) {
  if (!(match = re.exec(specifier))) throw new Error("invalid format: " + specifier);
  var match;
  return new FormatSpecifier({
    fill: match[1],
    align: match[2],
    sign: match[3],
    symbol: match[4],
    zero: match[5],
    width: match[6],
    comma: match[7],
    precision: match[8] && match[8].slice(1),
    trim: match[9],
    type: match[10]
  });
}
formatSpecifier.prototype = FormatSpecifier.prototype;
function FormatSpecifier(specifier) {
  this.fill = specifier.fill === void 0 ? " " : specifier.fill + "";
  this.align = specifier.align === void 0 ? ">" : specifier.align + "";
  this.sign = specifier.sign === void 0 ? "-" : specifier.sign + "";
  this.symbol = specifier.symbol === void 0 ? "" : specifier.symbol + "";
  this.zero = !!specifier.zero;
  this.width = specifier.width === void 0 ? void 0 : +specifier.width;
  this.comma = !!specifier.comma;
  this.precision = specifier.precision === void 0 ? void 0 : +specifier.precision;
  this.trim = !!specifier.trim;
  this.type = specifier.type === void 0 ? "" : specifier.type + "";
}
FormatSpecifier.prototype.toString = function() {
  return this.fill + this.align + this.sign + this.symbol + (this.zero ? "0" : "") + (this.width === void 0 ? "" : Math.max(1, this.width | 0)) + (this.comma ? "," : "") + (this.precision === void 0 ? "" : "." + Math.max(0, this.precision | 0)) + (this.trim ? "~" : "") + this.type;
};

// node_modules/d3-format/src/formatTrim.js
function formatTrim_default(s) {
  out: for (var n = s.length, i = 1, i0 = -1, i1; i < n; ++i) {
    switch (s[i]) {
      case ".":
        i0 = i1 = i;
        break;
      case "0":
        if (i0 === 0) i0 = i;
        i1 = i;
        break;
      default:
        if (!+s[i]) break out;
        if (i0 > 0) i0 = 0;
        break;
    }
  }
  return i0 > 0 ? s.slice(0, i0) + s.slice(i1 + 1) : s;
}

// node_modules/d3-format/src/formatPrefixAuto.js
var prefixExponent;
function formatPrefixAuto_default(x3, p) {
  var d = formatDecimalParts(x3, p);
  if (!d) return prefixExponent = void 0, x3.toPrecision(p);
  var coefficient = d[0], exponent = d[1], i = exponent - (prefixExponent = Math.max(-8, Math.min(8, Math.floor(exponent / 3))) * 3) + 1, n = coefficient.length;
  return i === n ? coefficient : i > n ? coefficient + new Array(i - n + 1).join("0") : i > 0 ? coefficient.slice(0, i) + "." + coefficient.slice(i) : "0." + new Array(1 - i).join("0") + formatDecimalParts(x3, Math.max(0, p + i - 1))[0];
}

// node_modules/d3-format/src/formatRounded.js
function formatRounded_default(x3, p) {
  var d = formatDecimalParts(x3, p);
  if (!d) return x3 + "";
  var coefficient = d[0], exponent = d[1];
  return exponent < 0 ? "0." + new Array(-exponent).join("0") + coefficient : coefficient.length > exponent + 1 ? coefficient.slice(0, exponent + 1) + "." + coefficient.slice(exponent + 1) : coefficient + new Array(exponent - coefficient.length + 2).join("0");
}

// node_modules/d3-format/src/formatTypes.js
var formatTypes_default = {
  "%": (x3, p) => (x3 * 100).toFixed(p),
  "b": (x3) => Math.round(x3).toString(2),
  "c": (x3) => x3 + "",
  "d": formatDecimal_default,
  "e": (x3, p) => x3.toExponential(p),
  "f": (x3, p) => x3.toFixed(p),
  "g": (x3, p) => x3.toPrecision(p),
  "o": (x3) => Math.round(x3).toString(8),
  "p": (x3, p) => formatRounded_default(x3 * 100, p),
  "r": formatRounded_default,
  "s": formatPrefixAuto_default,
  "X": (x3) => Math.round(x3).toString(16).toUpperCase(),
  "x": (x3) => Math.round(x3).toString(16)
};

// node_modules/d3-format/src/identity.js
function identity_default2(x3) {
  return x3;
}

// node_modules/d3-format/src/locale.js
var map = Array.prototype.map;
var prefixes = ["y", "z", "a", "f", "p", "n", "\xB5", "m", "", "k", "M", "G", "T", "P", "E", "Z", "Y"];
function locale_default(locale2) {
  var group = locale2.grouping === void 0 || locale2.thousands === void 0 ? identity_default2 : formatGroup_default(map.call(locale2.grouping, Number), locale2.thousands + ""), currencyPrefix = locale2.currency === void 0 ? "" : locale2.currency[0] + "", currencySuffix = locale2.currency === void 0 ? "" : locale2.currency[1] + "", decimal = locale2.decimal === void 0 ? "." : locale2.decimal + "", numerals = locale2.numerals === void 0 ? identity_default2 : formatNumerals_default(map.call(locale2.numerals, String)), percent = locale2.percent === void 0 ? "%" : locale2.percent + "", minus = locale2.minus === void 0 ? "\u2212" : locale2.minus + "", nan = locale2.nan === void 0 ? "NaN" : locale2.nan + "";
  function newFormat(specifier, options) {
    specifier = formatSpecifier(specifier);
    var fill = specifier.fill, align = specifier.align, sign = specifier.sign, symbol = specifier.symbol, zero3 = specifier.zero, width = specifier.width, comma = specifier.comma, precision = specifier.precision, trim = specifier.trim, type2 = specifier.type;
    if (type2 === "n") comma = true, type2 = "g";
    else if (!formatTypes_default[type2]) precision === void 0 && (precision = 12), trim = true, type2 = "g";
    if (zero3 || fill === "0" && align === "=") zero3 = true, fill = "0", align = "=";
    var prefix = (options && options.prefix !== void 0 ? options.prefix : "") + (symbol === "$" ? currencyPrefix : symbol === "#" && /[boxX]/.test(type2) ? "0" + type2.toLowerCase() : ""), suffix = (symbol === "$" ? currencySuffix : /[%p]/.test(type2) ? percent : "") + (options && options.suffix !== void 0 ? options.suffix : "");
    var formatType = formatTypes_default[type2], maybeSuffix = /[defgprs%]/.test(type2);
    precision = precision === void 0 ? 6 : /[gprs]/.test(type2) ? Math.max(1, Math.min(21, precision)) : Math.max(0, Math.min(20, precision));
    function format2(value) {
      var valuePrefix = prefix, valueSuffix = suffix, i, n, c4;
      if (type2 === "c") {
        valueSuffix = formatType(value) + valueSuffix;
        value = "";
      } else {
        value = +value;
        var valueNegative = value < 0 || 1 / value < 0;
        value = isNaN(value) ? nan : formatType(Math.abs(value), precision);
        if (trim) value = formatTrim_default(value);
        if (valueNegative && +value === 0 && sign !== "+") valueNegative = false;
        valuePrefix = (valueNegative ? sign === "(" ? sign : minus : sign === "-" || sign === "(" ? "" : sign) + valuePrefix;
        valueSuffix = (type2 === "s" && !isNaN(value) && prefixExponent !== void 0 ? prefixes[8 + prefixExponent / 3] : "") + valueSuffix + (valueNegative && sign === "(" ? ")" : "");
        if (maybeSuffix) {
          i = -1, n = value.length;
          while (++i < n) {
            if (c4 = value.charCodeAt(i), 48 > c4 || c4 > 57) {
              valueSuffix = (c4 === 46 ? decimal + value.slice(i + 1) : value.slice(i)) + valueSuffix;
              value = value.slice(0, i);
              break;
            }
          }
        }
      }
      if (comma && !zero3) value = group(value, Infinity);
      var length = valuePrefix.length + value.length + valueSuffix.length, padding = length < width ? new Array(width - length + 1).join(fill) : "";
      if (comma && zero3) value = group(padding + value, padding.length ? width - valueSuffix.length : Infinity), padding = "";
      switch (align) {
        case "<":
          value = valuePrefix + value + valueSuffix + padding;
          break;
        case "=":
          value = valuePrefix + padding + value + valueSuffix;
          break;
        case "^":
          value = padding.slice(0, length = padding.length >> 1) + valuePrefix + value + valueSuffix + padding.slice(length);
          break;
        default:
          value = padding + valuePrefix + value + valueSuffix;
          break;
      }
      return numerals(value);
    }
    format2.toString = function() {
      return specifier + "";
    };
    return format2;
  }
  function formatPrefix2(specifier, value) {
    var e = Math.max(-8, Math.min(8, Math.floor(exponent_default(value) / 3))) * 3, k = Math.pow(10, -e), f = newFormat((specifier = formatSpecifier(specifier), specifier.type = "f", specifier), { suffix: prefixes[8 + e / 3] });
    return function(value2) {
      return f(k * value2);
    };
  }
  return {
    format: newFormat,
    formatPrefix: formatPrefix2
  };
}

// node_modules/d3-format/src/defaultLocale.js
var locale;
var format;
var formatPrefix;
defaultLocale({
  thousands: ",",
  grouping: [3],
  currency: ["$", ""]
});
function defaultLocale(definition) {
  locale = locale_default(definition);
  format = locale.format;
  formatPrefix = locale.formatPrefix;
  return locale;
}

// node_modules/d3-format/src/precisionFixed.js
function precisionFixed_default(step) {
  return Math.max(0, -exponent_default(Math.abs(step)));
}

// node_modules/d3-format/src/precisionPrefix.js
function precisionPrefix_default(step, value) {
  return Math.max(0, Math.max(-8, Math.min(8, Math.floor(exponent_default(value) / 3))) * 3 - exponent_default(Math.abs(step)));
}

// node_modules/d3-format/src/precisionRound.js
function precisionRound_default(step, max8) {
  step = Math.abs(step), max8 = Math.abs(max8) - step;
  return Math.max(0, exponent_default(max8) - exponent_default(step)) + 1;
}

// node_modules/d3-hierarchy/src/hierarchy/count.js
function count(node) {
  var sum2 = 0, children2 = node.children, i = children2 && children2.length;
  if (!i) sum2 = 1;
  else while (--i >= 0) sum2 += children2[i].value;
  node.value = sum2;
}
function count_default() {
  return this.eachAfter(count);
}

// node_modules/d3-hierarchy/src/hierarchy/each.js
function each_default2(callback, that) {
  let index2 = -1;
  for (const node of this) {
    callback.call(that, node, ++index2, this);
  }
  return this;
}

// node_modules/d3-hierarchy/src/hierarchy/eachBefore.js
function eachBefore_default(callback, that) {
  var node = this, nodes = [node], children2, i, index2 = -1;
  while (node = nodes.pop()) {
    callback.call(that, node, ++index2, this);
    if (children2 = node.children) {
      for (i = children2.length - 1; i >= 0; --i) {
        nodes.push(children2[i]);
      }
    }
  }
  return this;
}

// node_modules/d3-hierarchy/src/hierarchy/eachAfter.js
function eachAfter_default(callback, that) {
  var node = this, nodes = [node], next = [], children2, i, n, index2 = -1;
  while (node = nodes.pop()) {
    next.push(node);
    if (children2 = node.children) {
      for (i = 0, n = children2.length; i < n; ++i) {
        nodes.push(children2[i]);
      }
    }
  }
  while (node = next.pop()) {
    callback.call(that, node, ++index2, this);
  }
  return this;
}

// node_modules/d3-hierarchy/src/hierarchy/find.js
function find_default2(callback, that) {
  let index2 = -1;
  for (const node of this) {
    if (callback.call(that, node, ++index2, this)) {
      return node;
    }
  }
}

// node_modules/d3-hierarchy/src/hierarchy/sum.js
function sum_default(value) {
  return this.eachAfter(function(node) {
    var sum2 = +value(node.data) || 0, children2 = node.children, i = children2 && children2.length;
    while (--i >= 0) sum2 += children2[i].value;
    node.value = sum2;
  });
}

// node_modules/d3-hierarchy/src/hierarchy/sort.js
function sort_default2(compare2) {
  return this.eachBefore(function(node) {
    if (node.children) {
      node.children.sort(compare2);
    }
  });
}

// node_modules/d3-hierarchy/src/hierarchy/path.js
function path_default(end) {
  var start2 = this, ancestor = leastCommonAncestor(start2, end), nodes = [start2];
  while (start2 !== ancestor) {
    start2 = start2.parent;
    nodes.push(start2);
  }
  var k = nodes.length;
  while (end !== ancestor) {
    nodes.splice(k, 0, end);
    end = end.parent;
  }
  return nodes;
}
function leastCommonAncestor(a2, b) {
  if (a2 === b) return a2;
  var aNodes = a2.ancestors(), bNodes = b.ancestors(), c4 = null;
  a2 = aNodes.pop();
  b = bNodes.pop();
  while (a2 === b) {
    c4 = a2;
    a2 = aNodes.pop();
    b = bNodes.pop();
  }
  return c4;
}

// node_modules/d3-hierarchy/src/hierarchy/ancestors.js
function ancestors_default() {
  var node = this, nodes = [node];
  while (node = node.parent) {
    nodes.push(node);
  }
  return nodes;
}

// node_modules/d3-hierarchy/src/hierarchy/descendants.js
function descendants_default() {
  return Array.from(this);
}

// node_modules/d3-hierarchy/src/hierarchy/leaves.js
function leaves_default() {
  var leaves = [];
  this.eachBefore(function(node) {
    if (!node.children) {
      leaves.push(node);
    }
  });
  return leaves;
}

// node_modules/d3-hierarchy/src/hierarchy/links.js
function links_default() {
  var root2 = this, links = [];
  root2.each(function(node) {
    if (node !== root2) {
      links.push({ source: node.parent, target: node });
    }
  });
  return links;
}

// node_modules/d3-hierarchy/src/hierarchy/iterator.js
function* iterator_default2() {
  var node = this, current, next = [node], children2, i, n;
  do {
    current = next.reverse(), next = [];
    while (node = current.pop()) {
      yield node;
      if (children2 = node.children) {
        for (i = 0, n = children2.length; i < n; ++i) {
          next.push(children2[i]);
        }
      }
    }
  } while (next.length);
}

// node_modules/d3-hierarchy/src/hierarchy/index.js
function hierarchy(data, children2) {
  if (data instanceof Map) {
    data = [void 0, data];
    if (children2 === void 0) children2 = mapChildren;
  } else if (children2 === void 0) {
    children2 = objectChildren;
  }
  var root2 = new Node(data), node, nodes = [root2], child, childs, i, n;
  while (node = nodes.pop()) {
    if ((childs = children2(node.data)) && (n = (childs = Array.from(childs)).length)) {
      node.children = childs;
      for (i = n - 1; i >= 0; --i) {
        nodes.push(child = childs[i] = new Node(childs[i]));
        child.parent = node;
        child.depth = node.depth + 1;
      }
    }
  }
  return root2.eachBefore(computeHeight);
}
function node_copy() {
  return hierarchy(this).eachBefore(copyData);
}
function objectChildren(d) {
  return d.children;
}
function mapChildren(d) {
  return Array.isArray(d) ? d[1] : null;
}
function copyData(node) {
  if (node.data.value !== void 0) node.value = node.data.value;
  node.data = node.data.data;
}
function computeHeight(node) {
  var height = 0;
  do
    node.height = height;
  while ((node = node.parent) && node.height < ++height);
}
function Node(data) {
  this.data = data;
  this.depth = this.height = 0;
  this.parent = null;
}
Node.prototype = hierarchy.prototype = {
  constructor: Node,
  count: count_default,
  each: each_default2,
  eachAfter: eachAfter_default,
  eachBefore: eachBefore_default,
  find: find_default2,
  sum: sum_default,
  sort: sort_default2,
  path: path_default,
  ancestors: ancestors_default,
  descendants: descendants_default,
  leaves: leaves_default,
  links: links_default,
  copy: node_copy,
  [Symbol.iterator]: iterator_default2
};

// node_modules/d3-hierarchy/src/treemap/round.js
function round_default2(node) {
  node.x0 = Math.round(node.x0);
  node.y0 = Math.round(node.y0);
  node.x1 = Math.round(node.x1);
  node.y1 = Math.round(node.y1);
}

// node_modules/d3-hierarchy/src/treemap/dice.js
function dice_default(parent, x0, y0, x1, y1) {
  var nodes = parent.children, node, i = -1, n = nodes.length, k = parent.value && (x1 - x0) / parent.value;
  while (++i < n) {
    node = nodes[i], node.y0 = y0, node.y1 = y1;
    node.x0 = x0, node.x1 = x0 += node.value * k;
  }
}

// node_modules/d3-hierarchy/src/partition.js
function partition_default() {
  var dx = 1, dy = 1, padding = 0, round7 = false;
  function partition(root2) {
    var n = root2.height + 1;
    root2.x0 = root2.y0 = padding;
    root2.x1 = dx;
    root2.y1 = dy / n;
    root2.eachBefore(positionNode(dy, n));
    if (round7) root2.eachBefore(round_default2);
    return root2;
  }
  function positionNode(dy2, n) {
    return function(node) {
      if (node.children) {
        dice_default(node, node.x0, dy2 * (node.depth + 1) / n, node.x1, dy2 * (node.depth + 2) / n);
      }
      var x0 = node.x0, y0 = node.y0, x1 = node.x1 - padding, y1 = node.y1 - padding;
      if (x1 < x0) x0 = x1 = (x0 + x1) / 2;
      if (y1 < y0) y0 = y1 = (y0 + y1) / 2;
      node.x0 = x0;
      node.y0 = y0;
      node.x1 = x1;
      node.y1 = y1;
    };
  }
  partition.round = function(x3) {
    return arguments.length ? (round7 = !!x3, partition) : round7;
  };
  partition.size = function(x3) {
    return arguments.length ? (dx = +x3[0], dy = +x3[1], partition) : [dx, dy];
  };
  partition.padding = function(x3) {
    return arguments.length ? (padding = +x3, partition) : padding;
  };
  return partition;
}

// node_modules/d3-scale/src/init.js
function initRange(domain, range2) {
  switch (arguments.length) {
    case 0:
      break;
    case 1:
      this.range(domain);
      break;
    default:
      this.range(range2).domain(domain);
      break;
  }
  return this;
}

// node_modules/d3-scale/src/ordinal.js
var implicit = Symbol("implicit");
function ordinal() {
  var index2 = new InternMap(), domain = [], range2 = [], unknown = implicit;
  function scale(d) {
    let i = index2.get(d);
    if (i === void 0) {
      if (unknown !== implicit) return unknown;
      index2.set(d, i = domain.push(d) - 1);
    }
    return range2[i % range2.length];
  }
  scale.domain = function(_) {
    if (!arguments.length) return domain.slice();
    domain = [], index2 = new InternMap();
    for (const value of _) {
      if (index2.has(value)) continue;
      index2.set(value, domain.push(value) - 1);
    }
    return scale;
  };
  scale.range = function(_) {
    return arguments.length ? (range2 = Array.from(_), scale) : range2.slice();
  };
  scale.unknown = function(_) {
    return arguments.length ? (unknown = _, scale) : unknown;
  };
  scale.copy = function() {
    return ordinal(domain, range2).unknown(unknown);
  };
  initRange.apply(scale, arguments);
  return scale;
}

// node_modules/d3-scale/src/band.js
function band() {
  var scale = ordinal().unknown(void 0), domain = scale.domain, ordinalRange = scale.range, r0 = 0, r1 = 1, step, bandwidth, round7 = false, paddingInner = 0, paddingOuter = 0, align = 0.5;
  delete scale.unknown;
  function rescale() {
    var n = domain().length, reverse = r1 < r0, start2 = reverse ? r1 : r0, stop = reverse ? r0 : r1;
    step = (stop - start2) / Math.max(1, n - paddingInner + paddingOuter * 2);
    if (round7) step = Math.floor(step);
    start2 += (stop - start2 - step * (n - paddingInner)) * align;
    bandwidth = step * (1 - paddingInner);
    if (round7) start2 = Math.round(start2), bandwidth = Math.round(bandwidth);
    var values = range(n).map(function(i) {
      return start2 + step * i;
    });
    return ordinalRange(reverse ? values.reverse() : values);
  }
  scale.domain = function(_) {
    return arguments.length ? (domain(_), rescale()) : domain();
  };
  scale.range = function(_) {
    return arguments.length ? ([r0, r1] = _, r0 = +r0, r1 = +r1, rescale()) : [r0, r1];
  };
  scale.rangeRound = function(_) {
    return [r0, r1] = _, r0 = +r0, r1 = +r1, round7 = true, rescale();
  };
  scale.bandwidth = function() {
    return bandwidth;
  };
  scale.step = function() {
    return step;
  };
  scale.round = function(_) {
    return arguments.length ? (round7 = !!_, rescale()) : round7;
  };
  scale.padding = function(_) {
    return arguments.length ? (paddingInner = Math.min(1, paddingOuter = +_), rescale()) : paddingInner;
  };
  scale.paddingInner = function(_) {
    return arguments.length ? (paddingInner = Math.min(1, _), rescale()) : paddingInner;
  };
  scale.paddingOuter = function(_) {
    return arguments.length ? (paddingOuter = +_, rescale()) : paddingOuter;
  };
  scale.align = function(_) {
    return arguments.length ? (align = Math.max(0, Math.min(1, _)), rescale()) : align;
  };
  scale.copy = function() {
    return band(domain(), [r0, r1]).round(round7).paddingInner(paddingInner).paddingOuter(paddingOuter).align(align);
  };
  return initRange.apply(rescale(), arguments);
}

// node_modules/d3-scale/src/constant.js
function constants(x3) {
  return function() {
    return x3;
  };
}

// node_modules/d3-scale/src/number.js
function number3(x3) {
  return +x3;
}

// node_modules/d3-scale/src/continuous.js
var unit = [0, 1];
function identity2(x3) {
  return x3;
}
function normalize(a2, b) {
  return (b -= a2 = +a2) ? function(x3) {
    return (x3 - a2) / b;
  } : constants(isNaN(b) ? NaN : 0.5);
}
function clamper(a2, b) {
  var t2;
  if (a2 > b) t2 = a2, a2 = b, b = t2;
  return function(x3) {
    return Math.max(a2, Math.min(b, x3));
  };
}
function bimap(domain, range2, interpolate) {
  var d0 = domain[0], d1 = domain[1], r0 = range2[0], r1 = range2[1];
  if (d1 < d0) d0 = normalize(d1, d0), r0 = interpolate(r1, r0);
  else d0 = normalize(d0, d1), r0 = interpolate(r0, r1);
  return function(x3) {
    return r0(d0(x3));
  };
}
function polymap(domain, range2, interpolate) {
  var j = Math.min(domain.length, range2.length) - 1, d = new Array(j), r = new Array(j), i = -1;
  if (domain[j] < domain[0]) {
    domain = domain.slice().reverse();
    range2 = range2.slice().reverse();
  }
  while (++i < j) {
    d[i] = normalize(domain[i], domain[i + 1]);
    r[i] = interpolate(range2[i], range2[i + 1]);
  }
  return function(x3) {
    var i2 = bisect_default(domain, x3, 1, j) - 1;
    return r[i2](d[i2](x3));
  };
}
function copy(source, target) {
  return target.domain(source.domain()).range(source.range()).interpolate(source.interpolate()).clamp(source.clamp()).unknown(source.unknown());
}
function transformer() {
  var domain = unit, range2 = unit, interpolate = value_default, transform2, untransform, unknown, clamp = identity2, piecewise, output, input;
  function rescale() {
    var n = Math.min(domain.length, range2.length);
    if (clamp !== identity2) clamp = clamper(domain[0], domain[n - 1]);
    piecewise = n > 2 ? polymap : bimap;
    output = input = null;
    return scale;
  }
  function scale(x3) {
    return x3 == null || isNaN(x3 = +x3) ? unknown : (output || (output = piecewise(domain.map(transform2), range2, interpolate)))(transform2(clamp(x3)));
  }
  scale.invert = function(y3) {
    return clamp(untransform((input || (input = piecewise(range2, domain.map(transform2), number_default)))(y3)));
  };
  scale.domain = function(_) {
    return arguments.length ? (domain = Array.from(_, number3), rescale()) : domain.slice();
  };
  scale.range = function(_) {
    return arguments.length ? (range2 = Array.from(_), rescale()) : range2.slice();
  };
  scale.rangeRound = function(_) {
    return range2 = Array.from(_), interpolate = round_default, rescale();
  };
  scale.clamp = function(_) {
    return arguments.length ? (clamp = _ ? true : identity2, rescale()) : clamp !== identity2;
  };
  scale.interpolate = function(_) {
    return arguments.length ? (interpolate = _, rescale()) : interpolate;
  };
  scale.unknown = function(_) {
    return arguments.length ? (unknown = _, scale) : unknown;
  };
  return function(t2, u) {
    transform2 = t2, untransform = u;
    return rescale();
  };
}
function continuous() {
  return transformer()(identity2, identity2);
}

// node_modules/d3-scale/src/tickFormat.js
function tickFormat(start2, stop, count2, specifier) {
  var step = tickStep(start2, stop, count2), precision;
  specifier = formatSpecifier(specifier == null ? ",f" : specifier);
  switch (specifier.type) {
    case "s": {
      var value = Math.max(Math.abs(start2), Math.abs(stop));
      if (specifier.precision == null && !isNaN(precision = precisionPrefix_default(step, value))) specifier.precision = precision;
      return formatPrefix(specifier, value);
    }
    case "":
    case "e":
    case "g":
    case "p":
    case "r": {
      if (specifier.precision == null && !isNaN(precision = precisionRound_default(step, Math.max(Math.abs(start2), Math.abs(stop))))) specifier.precision = precision - (specifier.type === "e");
      break;
    }
    case "f":
    case "%": {
      if (specifier.precision == null && !isNaN(precision = precisionFixed_default(step))) specifier.precision = precision - (specifier.type === "%") * 2;
      break;
    }
  }
  return format(specifier);
}

// node_modules/d3-scale/src/linear.js
function linearish(scale) {
  var domain = scale.domain;
  scale.ticks = function(count2) {
    var d = domain();
    return ticks(d[0], d[d.length - 1], count2 == null ? 10 : count2);
  };
  scale.tickFormat = function(count2, specifier) {
    var d = domain();
    return tickFormat(d[0], d[d.length - 1], count2 == null ? 10 : count2, specifier);
  };
  scale.nice = function(count2) {
    if (count2 == null) count2 = 10;
    var d = domain();
    var i0 = 0;
    var i1 = d.length - 1;
    var start2 = d[i0];
    var stop = d[i1];
    var prestep;
    var step;
    var maxIter = 10;
    if (stop < start2) {
      step = start2, start2 = stop, stop = step;
      step = i0, i0 = i1, i1 = step;
    }
    while (maxIter-- > 0) {
      step = tickIncrement(start2, stop, count2);
      if (step === prestep) {
        d[i0] = start2;
        d[i1] = stop;
        return domain(d);
      } else if (step > 0) {
        start2 = Math.floor(start2 / step) * step;
        stop = Math.ceil(stop / step) * step;
      } else if (step < 0) {
        start2 = Math.ceil(start2 * step) / step;
        stop = Math.floor(stop * step) / step;
      } else {
        break;
      }
      prestep = step;
    }
    return scale;
  };
  return scale;
}
function linear2() {
  var scale = continuous();
  scale.copy = function() {
    return copy(scale, linear2());
  };
  initRange.apply(scale, arguments);
  return linearish(scale);
}

// node_modules/d3-scale/src/quantize.js
function quantize() {
  var x0 = 0, x1 = 1, n = 1, domain = [0.5], range2 = [0, 1], unknown;
  function scale(x3) {
    return x3 != null && x3 <= x3 ? range2[bisect_default(domain, x3, 0, n)] : unknown;
  }
  function rescale() {
    var i = -1;
    domain = new Array(n);
    while (++i < n) domain[i] = ((i + 1) * x1 - (i - n) * x0) / (n + 1);
    return scale;
  }
  scale.domain = function(_) {
    return arguments.length ? ([x0, x1] = _, x0 = +x0, x1 = +x1, rescale()) : [x0, x1];
  };
  scale.range = function(_) {
    return arguments.length ? (n = (range2 = Array.from(_)).length - 1, rescale()) : range2.slice();
  };
  scale.invertExtent = function(y3) {
    var i = range2.indexOf(y3);
    return i < 0 ? [NaN, NaN] : i < 1 ? [x0, domain[0]] : i >= n ? [domain[n - 1], x1] : [domain[i - 1], domain[i]];
  };
  scale.unknown = function(_) {
    return arguments.length ? (unknown = _, scale) : scale;
  };
  scale.thresholds = function() {
    return domain.slice();
  };
  scale.copy = function() {
    return quantize().domain([x0, x1]).range(range2).unknown(unknown);
  };
  return initRange.apply(linearish(scale), arguments);
}

// node_modules/d3-scale/src/threshold.js
function threshold() {
  var domain = [0.5], range2 = [0, 1], unknown, n = 1;
  function scale(x3) {
    return x3 != null && x3 <= x3 ? range2[bisect_default(domain, x3, 0, n)] : unknown;
  }
  scale.domain = function(_) {
    return arguments.length ? (domain = Array.from(_), n = Math.min(domain.length, range2.length - 1), scale) : domain.slice();
  };
  scale.range = function(_) {
    return arguments.length ? (range2 = Array.from(_), n = Math.min(domain.length, range2.length - 1), scale) : range2.slice();
  };
  scale.invertExtent = function(y3) {
    var i = range2.indexOf(y3);
    return [domain[i - 1], domain[i]];
  };
  scale.unknown = function(_) {
    return arguments.length ? (unknown = _, scale) : unknown;
  };
  scale.copy = function() {
    return threshold().domain(domain).range(range2).unknown(unknown);
  };
  return initRange.apply(scale, arguments);
}

// node_modules/d3-scale-chromatic/src/index.js
var src_exports = {};
__export(src_exports, {
  interpolateBlues: () => Blues_default,
  interpolateBrBG: () => BrBG_default,
  interpolateBuGn: () => BuGn_default,
  interpolateBuPu: () => BuPu_default,
  interpolateCividis: () => cividis_default,
  interpolateCool: () => cool,
  interpolateCubehelixDefault: () => cubehelix_default2,
  interpolateGnBu: () => GnBu_default,
  interpolateGreens: () => Greens_default,
  interpolateGreys: () => Greys_default,
  interpolateInferno: () => inferno,
  interpolateMagma: () => magma,
  interpolateOrRd: () => OrRd_default,
  interpolateOranges: () => Oranges_default,
  interpolatePRGn: () => PRGn_default,
  interpolatePiYG: () => PiYG_default,
  interpolatePlasma: () => plasma,
  interpolatePuBu: () => PuBu_default,
  interpolatePuBuGn: () => PuBuGn_default,
  interpolatePuOr: () => PuOr_default,
  interpolatePuRd: () => PuRd_default,
  interpolatePurples: () => Purples_default,
  interpolateRainbow: () => rainbow_default,
  interpolateRdBu: () => RdBu_default,
  interpolateRdGy: () => RdGy_default,
  interpolateRdPu: () => RdPu_default,
  interpolateRdYlBu: () => RdYlBu_default,
  interpolateRdYlGn: () => RdYlGn_default,
  interpolateReds: () => Reds_default,
  interpolateSinebow: () => sinebow_default,
  interpolateSpectral: () => Spectral_default,
  interpolateTurbo: () => turbo_default,
  interpolateViridis: () => viridis_default,
  interpolateWarm: () => warm,
  interpolateYlGn: () => YlGn_default,
  interpolateYlGnBu: () => YlGnBu_default,
  interpolateYlOrBr: () => YlOrBr_default,
  interpolateYlOrRd: () => YlOrRd_default,
  schemeAccent: () => Accent_default,
  schemeBlues: () => scheme22,
  schemeBrBG: () => scheme,
  schemeBuGn: () => scheme10,
  schemeBuPu: () => scheme11,
  schemeCategory10: () => category10_default,
  schemeDark2: () => Dark2_default,
  schemeGnBu: () => scheme12,
  schemeGreens: () => scheme23,
  schemeGreys: () => scheme24,
  schemeObservable10: () => observable10_default,
  schemeOrRd: () => scheme13,
  schemeOranges: () => scheme27,
  schemePRGn: () => scheme2,
  schemePaired: () => Paired_default,
  schemePastel1: () => Pastel1_default,
  schemePastel2: () => Pastel2_default,
  schemePiYG: () => scheme3,
  schemePuBu: () => scheme15,
  schemePuBuGn: () => scheme14,
  schemePuOr: () => scheme4,
  schemePuRd: () => scheme16,
  schemePurples: () => scheme25,
  schemeRdBu: () => scheme5,
  schemeRdGy: () => scheme6,
  schemeRdPu: () => scheme17,
  schemeRdYlBu: () => scheme7,
  schemeRdYlGn: () => scheme8,
  schemeReds: () => scheme26,
  schemeSet1: () => Set1_default,
  schemeSet2: () => Set2_default,
  schemeSet3: () => Set3_default,
  schemeSpectral: () => scheme9,
  schemeTableau10: () => Tableau10_default,
  schemeYlGn: () => scheme19,
  schemeYlGnBu: () => scheme18,
  schemeYlOrBr: () => scheme20,
  schemeYlOrRd: () => scheme21
});

// node_modules/d3-scale-chromatic/src/colors.js
function colors_default(specifier) {
  var n = specifier.length / 6 | 0, colors = new Array(n), i = 0;
  while (i < n) colors[i] = "#" + specifier.slice(i * 6, ++i * 6);
  return colors;
}

// node_modules/d3-scale-chromatic/src/categorical/category10.js
var category10_default = colors_default("1f77b4ff7f0e2ca02cd627289467bd8c564be377c27f7f7fbcbd2217becf");

// node_modules/d3-scale-chromatic/src/categorical/Accent.js
var Accent_default = colors_default("7fc97fbeaed4fdc086ffff99386cb0f0027fbf5b17666666");

// node_modules/d3-scale-chromatic/src/categorical/Dark2.js
var Dark2_default = colors_default("1b9e77d95f027570b3e7298a66a61ee6ab02a6761d666666");

// node_modules/d3-scale-chromatic/src/categorical/observable10.js
var observable10_default = colors_default("4269d0efb118ff725c6cc5b03ca951ff8ab7a463f297bbf59c6b4e9498a0");

// node_modules/d3-scale-chromatic/src/categorical/Paired.js
var Paired_default = colors_default("a6cee31f78b4b2df8a33a02cfb9a99e31a1cfdbf6fff7f00cab2d66a3d9affff99b15928");

// node_modules/d3-scale-chromatic/src/categorical/Pastel1.js
var Pastel1_default = colors_default("fbb4aeb3cde3ccebc5decbe4fed9a6ffffcce5d8bdfddaecf2f2f2");

// node_modules/d3-scale-chromatic/src/categorical/Pastel2.js
var Pastel2_default = colors_default("b3e2cdfdcdaccbd5e8f4cae4e6f5c9fff2aef1e2cccccccc");

// node_modules/d3-scale-chromatic/src/categorical/Set1.js
var Set1_default = colors_default("e41a1c377eb84daf4a984ea3ff7f00ffff33a65628f781bf999999");

// node_modules/d3-scale-chromatic/src/categorical/Set2.js
var Set2_default = colors_default("66c2a5fc8d628da0cbe78ac3a6d854ffd92fe5c494b3b3b3");

// node_modules/d3-scale-chromatic/src/categorical/Set3.js
var Set3_default = colors_default("8dd3c7ffffb3bebadafb807280b1d3fdb462b3de69fccde5d9d9d9bc80bdccebc5ffed6f");

// node_modules/d3-scale-chromatic/src/categorical/Tableau10.js
var Tableau10_default = colors_default("4e79a7f28e2ce1575976b7b259a14fedc949af7aa1ff9da79c755fbab0ab");

// node_modules/d3-scale-chromatic/src/ramp.js
var ramp_default = (scheme28) => rgbBasis(scheme28[scheme28.length - 1]);

// node_modules/d3-scale-chromatic/src/diverging/BrBG.js
var scheme = new Array(3).concat(
  "d8b365f5f5f55ab4ac",
  "a6611adfc27d80cdc1018571",
  "a6611adfc27df5f5f580cdc1018571",
  "8c510ad8b365f6e8c3c7eae55ab4ac01665e",
  "8c510ad8b365f6e8c3f5f5f5c7eae55ab4ac01665e",
  "8c510abf812ddfc27df6e8c3c7eae580cdc135978f01665e",
  "8c510abf812ddfc27df6e8c3f5f5f5c7eae580cdc135978f01665e",
  "5430058c510abf812ddfc27df6e8c3c7eae580cdc135978f01665e003c30",
  "5430058c510abf812ddfc27df6e8c3f5f5f5c7eae580cdc135978f01665e003c30"
).map(colors_default);
var BrBG_default = ramp_default(scheme);

// node_modules/d3-scale-chromatic/src/diverging/PRGn.js
var scheme2 = new Array(3).concat(
  "af8dc3f7f7f77fbf7b",
  "7b3294c2a5cfa6dba0008837",
  "7b3294c2a5cff7f7f7a6dba0008837",
  "762a83af8dc3e7d4e8d9f0d37fbf7b1b7837",
  "762a83af8dc3e7d4e8f7f7f7d9f0d37fbf7b1b7837",
  "762a839970abc2a5cfe7d4e8d9f0d3a6dba05aae611b7837",
  "762a839970abc2a5cfe7d4e8f7f7f7d9f0d3a6dba05aae611b7837",
  "40004b762a839970abc2a5cfe7d4e8d9f0d3a6dba05aae611b783700441b",
  "40004b762a839970abc2a5cfe7d4e8f7f7f7d9f0d3a6dba05aae611b783700441b"
).map(colors_default);
var PRGn_default = ramp_default(scheme2);

// node_modules/d3-scale-chromatic/src/diverging/PiYG.js
var scheme3 = new Array(3).concat(
  "e9a3c9f7f7f7a1d76a",
  "d01c8bf1b6dab8e1864dac26",
  "d01c8bf1b6daf7f7f7b8e1864dac26",
  "c51b7de9a3c9fde0efe6f5d0a1d76a4d9221",
  "c51b7de9a3c9fde0eff7f7f7e6f5d0a1d76a4d9221",
  "c51b7dde77aef1b6dafde0efe6f5d0b8e1867fbc414d9221",
  "c51b7dde77aef1b6dafde0eff7f7f7e6f5d0b8e1867fbc414d9221",
  "8e0152c51b7dde77aef1b6dafde0efe6f5d0b8e1867fbc414d9221276419",
  "8e0152c51b7dde77aef1b6dafde0eff7f7f7e6f5d0b8e1867fbc414d9221276419"
).map(colors_default);
var PiYG_default = ramp_default(scheme3);

// node_modules/d3-scale-chromatic/src/diverging/PuOr.js
var scheme4 = new Array(3).concat(
  "998ec3f7f7f7f1a340",
  "5e3c99b2abd2fdb863e66101",
  "5e3c99b2abd2f7f7f7fdb863e66101",
  "542788998ec3d8daebfee0b6f1a340b35806",
  "542788998ec3d8daebf7f7f7fee0b6f1a340b35806",
  "5427888073acb2abd2d8daebfee0b6fdb863e08214b35806",
  "5427888073acb2abd2d8daebf7f7f7fee0b6fdb863e08214b35806",
  "2d004b5427888073acb2abd2d8daebfee0b6fdb863e08214b358067f3b08",
  "2d004b5427888073acb2abd2d8daebf7f7f7fee0b6fdb863e08214b358067f3b08"
).map(colors_default);
var PuOr_default = ramp_default(scheme4);

// node_modules/d3-scale-chromatic/src/diverging/RdBu.js
var scheme5 = new Array(3).concat(
  "ef8a62f7f7f767a9cf",
  "ca0020f4a58292c5de0571b0",
  "ca0020f4a582f7f7f792c5de0571b0",
  "b2182bef8a62fddbc7d1e5f067a9cf2166ac",
  "b2182bef8a62fddbc7f7f7f7d1e5f067a9cf2166ac",
  "b2182bd6604df4a582fddbc7d1e5f092c5de4393c32166ac",
  "b2182bd6604df4a582fddbc7f7f7f7d1e5f092c5de4393c32166ac",
  "67001fb2182bd6604df4a582fddbc7d1e5f092c5de4393c32166ac053061",
  "67001fb2182bd6604df4a582fddbc7f7f7f7d1e5f092c5de4393c32166ac053061"
).map(colors_default);
var RdBu_default = ramp_default(scheme5);

// node_modules/d3-scale-chromatic/src/diverging/RdGy.js
var scheme6 = new Array(3).concat(
  "ef8a62ffffff999999",
  "ca0020f4a582bababa404040",
  "ca0020f4a582ffffffbababa404040",
  "b2182bef8a62fddbc7e0e0e09999994d4d4d",
  "b2182bef8a62fddbc7ffffffe0e0e09999994d4d4d",
  "b2182bd6604df4a582fddbc7e0e0e0bababa8787874d4d4d",
  "b2182bd6604df4a582fddbc7ffffffe0e0e0bababa8787874d4d4d",
  "67001fb2182bd6604df4a582fddbc7e0e0e0bababa8787874d4d4d1a1a1a",
  "67001fb2182bd6604df4a582fddbc7ffffffe0e0e0bababa8787874d4d4d1a1a1a"
).map(colors_default);
var RdGy_default = ramp_default(scheme6);

// node_modules/d3-scale-chromatic/src/diverging/RdYlBu.js
var scheme7 = new Array(3).concat(
  "fc8d59ffffbf91bfdb",
  "d7191cfdae61abd9e92c7bb6",
  "d7191cfdae61ffffbfabd9e92c7bb6",
  "d73027fc8d59fee090e0f3f891bfdb4575b4",
  "d73027fc8d59fee090ffffbfe0f3f891bfdb4575b4",
  "d73027f46d43fdae61fee090e0f3f8abd9e974add14575b4",
  "d73027f46d43fdae61fee090ffffbfe0f3f8abd9e974add14575b4",
  "a50026d73027f46d43fdae61fee090e0f3f8abd9e974add14575b4313695",
  "a50026d73027f46d43fdae61fee090ffffbfe0f3f8abd9e974add14575b4313695"
).map(colors_default);
var RdYlBu_default = ramp_default(scheme7);

// node_modules/d3-scale-chromatic/src/diverging/RdYlGn.js
var scheme8 = new Array(3).concat(
  "fc8d59ffffbf91cf60",
  "d7191cfdae61a6d96a1a9641",
  "d7191cfdae61ffffbfa6d96a1a9641",
  "d73027fc8d59fee08bd9ef8b91cf601a9850",
  "d73027fc8d59fee08bffffbfd9ef8b91cf601a9850",
  "d73027f46d43fdae61fee08bd9ef8ba6d96a66bd631a9850",
  "d73027f46d43fdae61fee08bffffbfd9ef8ba6d96a66bd631a9850",
  "a50026d73027f46d43fdae61fee08bd9ef8ba6d96a66bd631a9850006837",
  "a50026d73027f46d43fdae61fee08bffffbfd9ef8ba6d96a66bd631a9850006837"
).map(colors_default);
var RdYlGn_default = ramp_default(scheme8);

// node_modules/d3-scale-chromatic/src/diverging/Spectral.js
var scheme9 = new Array(3).concat(
  "fc8d59ffffbf99d594",
  "d7191cfdae61abdda42b83ba",
  "d7191cfdae61ffffbfabdda42b83ba",
  "d53e4ffc8d59fee08be6f59899d5943288bd",
  "d53e4ffc8d59fee08bffffbfe6f59899d5943288bd",
  "d53e4ff46d43fdae61fee08be6f598abdda466c2a53288bd",
  "d53e4ff46d43fdae61fee08bffffbfe6f598abdda466c2a53288bd",
  "9e0142d53e4ff46d43fdae61fee08be6f598abdda466c2a53288bd5e4fa2",
  "9e0142d53e4ff46d43fdae61fee08bffffbfe6f598abdda466c2a53288bd5e4fa2"
).map(colors_default);
var Spectral_default = ramp_default(scheme9);

// node_modules/d3-scale-chromatic/src/sequential-multi/BuGn.js
var scheme10 = new Array(3).concat(
  "e5f5f999d8c92ca25f",
  "edf8fbb2e2e266c2a4238b45",
  "edf8fbb2e2e266c2a42ca25f006d2c",
  "edf8fbccece699d8c966c2a42ca25f006d2c",
  "edf8fbccece699d8c966c2a441ae76238b45005824",
  "f7fcfde5f5f9ccece699d8c966c2a441ae76238b45005824",
  "f7fcfde5f5f9ccece699d8c966c2a441ae76238b45006d2c00441b"
).map(colors_default);
var BuGn_default = ramp_default(scheme10);

// node_modules/d3-scale-chromatic/src/sequential-multi/BuPu.js
var scheme11 = new Array(3).concat(
  "e0ecf49ebcda8856a7",
  "edf8fbb3cde38c96c688419d",
  "edf8fbb3cde38c96c68856a7810f7c",
  "edf8fbbfd3e69ebcda8c96c68856a7810f7c",
  "edf8fbbfd3e69ebcda8c96c68c6bb188419d6e016b",
  "f7fcfde0ecf4bfd3e69ebcda8c96c68c6bb188419d6e016b",
  "f7fcfde0ecf4bfd3e69ebcda8c96c68c6bb188419d810f7c4d004b"
).map(colors_default);
var BuPu_default = ramp_default(scheme11);

// node_modules/d3-scale-chromatic/src/sequential-multi/GnBu.js
var scheme12 = new Array(3).concat(
  "e0f3dba8ddb543a2ca",
  "f0f9e8bae4bc7bccc42b8cbe",
  "f0f9e8bae4bc7bccc443a2ca0868ac",
  "f0f9e8ccebc5a8ddb57bccc443a2ca0868ac",
  "f0f9e8ccebc5a8ddb57bccc44eb3d32b8cbe08589e",
  "f7fcf0e0f3dbccebc5a8ddb57bccc44eb3d32b8cbe08589e",
  "f7fcf0e0f3dbccebc5a8ddb57bccc44eb3d32b8cbe0868ac084081"
).map(colors_default);
var GnBu_default = ramp_default(scheme12);

// node_modules/d3-scale-chromatic/src/sequential-multi/OrRd.js
var scheme13 = new Array(3).concat(
  "fee8c8fdbb84e34a33",
  "fef0d9fdcc8afc8d59d7301f",
  "fef0d9fdcc8afc8d59e34a33b30000",
  "fef0d9fdd49efdbb84fc8d59e34a33b30000",
  "fef0d9fdd49efdbb84fc8d59ef6548d7301f990000",
  "fff7ecfee8c8fdd49efdbb84fc8d59ef6548d7301f990000",
  "fff7ecfee8c8fdd49efdbb84fc8d59ef6548d7301fb300007f0000"
).map(colors_default);
var OrRd_default = ramp_default(scheme13);

// node_modules/d3-scale-chromatic/src/sequential-multi/PuBuGn.js
var scheme14 = new Array(3).concat(
  "ece2f0a6bddb1c9099",
  "f6eff7bdc9e167a9cf02818a",
  "f6eff7bdc9e167a9cf1c9099016c59",
  "f6eff7d0d1e6a6bddb67a9cf1c9099016c59",
  "f6eff7d0d1e6a6bddb67a9cf3690c002818a016450",
  "fff7fbece2f0d0d1e6a6bddb67a9cf3690c002818a016450",
  "fff7fbece2f0d0d1e6a6bddb67a9cf3690c002818a016c59014636"
).map(colors_default);
var PuBuGn_default = ramp_default(scheme14);

// node_modules/d3-scale-chromatic/src/sequential-multi/PuBu.js
var scheme15 = new Array(3).concat(
  "ece7f2a6bddb2b8cbe",
  "f1eef6bdc9e174a9cf0570b0",
  "f1eef6bdc9e174a9cf2b8cbe045a8d",
  "f1eef6d0d1e6a6bddb74a9cf2b8cbe045a8d",
  "f1eef6d0d1e6a6bddb74a9cf3690c00570b0034e7b",
  "fff7fbece7f2d0d1e6a6bddb74a9cf3690c00570b0034e7b",
  "fff7fbece7f2d0d1e6a6bddb74a9cf3690c00570b0045a8d023858"
).map(colors_default);
var PuBu_default = ramp_default(scheme15);

// node_modules/d3-scale-chromatic/src/sequential-multi/PuRd.js
var scheme16 = new Array(3).concat(
  "e7e1efc994c7dd1c77",
  "f1eef6d7b5d8df65b0ce1256",
  "f1eef6d7b5d8df65b0dd1c77980043",
  "f1eef6d4b9dac994c7df65b0dd1c77980043",
  "f1eef6d4b9dac994c7df65b0e7298ace125691003f",
  "f7f4f9e7e1efd4b9dac994c7df65b0e7298ace125691003f",
  "f7f4f9e7e1efd4b9dac994c7df65b0e7298ace125698004367001f"
).map(colors_default);
var PuRd_default = ramp_default(scheme16);

// node_modules/d3-scale-chromatic/src/sequential-multi/RdPu.js
var scheme17 = new Array(3).concat(
  "fde0ddfa9fb5c51b8a",
  "feebe2fbb4b9f768a1ae017e",
  "feebe2fbb4b9f768a1c51b8a7a0177",
  "feebe2fcc5c0fa9fb5f768a1c51b8a7a0177",
  "feebe2fcc5c0fa9fb5f768a1dd3497ae017e7a0177",
  "fff7f3fde0ddfcc5c0fa9fb5f768a1dd3497ae017e7a0177",
  "fff7f3fde0ddfcc5c0fa9fb5f768a1dd3497ae017e7a017749006a"
).map(colors_default);
var RdPu_default = ramp_default(scheme17);

// node_modules/d3-scale-chromatic/src/sequential-multi/YlGnBu.js
var scheme18 = new Array(3).concat(
  "edf8b17fcdbb2c7fb8",
  "ffffcca1dab441b6c4225ea8",
  "ffffcca1dab441b6c42c7fb8253494",
  "ffffccc7e9b47fcdbb41b6c42c7fb8253494",
  "ffffccc7e9b47fcdbb41b6c41d91c0225ea80c2c84",
  "ffffd9edf8b1c7e9b47fcdbb41b6c41d91c0225ea80c2c84",
  "ffffd9edf8b1c7e9b47fcdbb41b6c41d91c0225ea8253494081d58"
).map(colors_default);
var YlGnBu_default = ramp_default(scheme18);

// node_modules/d3-scale-chromatic/src/sequential-multi/YlGn.js
var scheme19 = new Array(3).concat(
  "f7fcb9addd8e31a354",
  "ffffccc2e69978c679238443",
  "ffffccc2e69978c67931a354006837",
  "ffffccd9f0a3addd8e78c67931a354006837",
  "ffffccd9f0a3addd8e78c67941ab5d238443005a32",
  "ffffe5f7fcb9d9f0a3addd8e78c67941ab5d238443005a32",
  "ffffe5f7fcb9d9f0a3addd8e78c67941ab5d238443006837004529"
).map(colors_default);
var YlGn_default = ramp_default(scheme19);

// node_modules/d3-scale-chromatic/src/sequential-multi/YlOrBr.js
var scheme20 = new Array(3).concat(
  "fff7bcfec44fd95f0e",
  "ffffd4fed98efe9929cc4c02",
  "ffffd4fed98efe9929d95f0e993404",
  "ffffd4fee391fec44ffe9929d95f0e993404",
  "ffffd4fee391fec44ffe9929ec7014cc4c028c2d04",
  "ffffe5fff7bcfee391fec44ffe9929ec7014cc4c028c2d04",
  "ffffe5fff7bcfee391fec44ffe9929ec7014cc4c02993404662506"
).map(colors_default);
var YlOrBr_default = ramp_default(scheme20);

// node_modules/d3-scale-chromatic/src/sequential-multi/YlOrRd.js
var scheme21 = new Array(3).concat(
  "ffeda0feb24cf03b20",
  "ffffb2fecc5cfd8d3ce31a1c",
  "ffffb2fecc5cfd8d3cf03b20bd0026",
  "ffffb2fed976feb24cfd8d3cf03b20bd0026",
  "ffffb2fed976feb24cfd8d3cfc4e2ae31a1cb10026",
  "ffffccffeda0fed976feb24cfd8d3cfc4e2ae31a1cb10026",
  "ffffccffeda0fed976feb24cfd8d3cfc4e2ae31a1cbd0026800026"
).map(colors_default);
var YlOrRd_default = ramp_default(scheme21);

// node_modules/d3-scale-chromatic/src/sequential-single/Blues.js
var scheme22 = new Array(3).concat(
  "deebf79ecae13182bd",
  "eff3ffbdd7e76baed62171b5",
  "eff3ffbdd7e76baed63182bd08519c",
  "eff3ffc6dbef9ecae16baed63182bd08519c",
  "eff3ffc6dbef9ecae16baed64292c62171b5084594",
  "f7fbffdeebf7c6dbef9ecae16baed64292c62171b5084594",
  "f7fbffdeebf7c6dbef9ecae16baed64292c62171b508519c08306b"
).map(colors_default);
var Blues_default = ramp_default(scheme22);

// node_modules/d3-scale-chromatic/src/sequential-single/Greens.js
var scheme23 = new Array(3).concat(
  "e5f5e0a1d99b31a354",
  "edf8e9bae4b374c476238b45",
  "edf8e9bae4b374c47631a354006d2c",
  "edf8e9c7e9c0a1d99b74c47631a354006d2c",
  "edf8e9c7e9c0a1d99b74c47641ab5d238b45005a32",
  "f7fcf5e5f5e0c7e9c0a1d99b74c47641ab5d238b45005a32",
  "f7fcf5e5f5e0c7e9c0a1d99b74c47641ab5d238b45006d2c00441b"
).map(colors_default);
var Greens_default = ramp_default(scheme23);

// node_modules/d3-scale-chromatic/src/sequential-single/Greys.js
var scheme24 = new Array(3).concat(
  "f0f0f0bdbdbd636363",
  "f7f7f7cccccc969696525252",
  "f7f7f7cccccc969696636363252525",
  "f7f7f7d9d9d9bdbdbd969696636363252525",
  "f7f7f7d9d9d9bdbdbd969696737373525252252525",
  "fffffff0f0f0d9d9d9bdbdbd969696737373525252252525",
  "fffffff0f0f0d9d9d9bdbdbd969696737373525252252525000000"
).map(colors_default);
var Greys_default = ramp_default(scheme24);

// node_modules/d3-scale-chromatic/src/sequential-single/Purples.js
var scheme25 = new Array(3).concat(
  "efedf5bcbddc756bb1",
  "f2f0f7cbc9e29e9ac86a51a3",
  "f2f0f7cbc9e29e9ac8756bb154278f",
  "f2f0f7dadaebbcbddc9e9ac8756bb154278f",
  "f2f0f7dadaebbcbddc9e9ac8807dba6a51a34a1486",
  "fcfbfdefedf5dadaebbcbddc9e9ac8807dba6a51a34a1486",
  "fcfbfdefedf5dadaebbcbddc9e9ac8807dba6a51a354278f3f007d"
).map(colors_default);
var Purples_default = ramp_default(scheme25);

// node_modules/d3-scale-chromatic/src/sequential-single/Reds.js
var scheme26 = new Array(3).concat(
  "fee0d2fc9272de2d26",
  "fee5d9fcae91fb6a4acb181d",
  "fee5d9fcae91fb6a4ade2d26a50f15",
  "fee5d9fcbba1fc9272fb6a4ade2d26a50f15",
  "fee5d9fcbba1fc9272fb6a4aef3b2ccb181d99000d",
  "fff5f0fee0d2fcbba1fc9272fb6a4aef3b2ccb181d99000d",
  "fff5f0fee0d2fcbba1fc9272fb6a4aef3b2ccb181da50f1567000d"
).map(colors_default);
var Reds_default = ramp_default(scheme26);

// node_modules/d3-scale-chromatic/src/sequential-single/Oranges.js
var scheme27 = new Array(3).concat(
  "fee6cefdae6be6550d",
  "feeddefdbe85fd8d3cd94701",
  "feeddefdbe85fd8d3ce6550da63603",
  "feeddefdd0a2fdae6bfd8d3ce6550da63603",
  "feeddefdd0a2fdae6bfd8d3cf16913d948018c2d04",
  "fff5ebfee6cefdd0a2fdae6bfd8d3cf16913d948018c2d04",
  "fff5ebfee6cefdd0a2fdae6bfd8d3cf16913d94801a636037f2704"
).map(colors_default);
var Oranges_default = ramp_default(scheme27);

// node_modules/d3-scale-chromatic/src/sequential-multi/cividis.js
function cividis_default(t2) {
  t2 = Math.max(0, Math.min(1, t2));
  return "rgb(" + Math.max(0, Math.min(255, Math.round(-4.54 - t2 * (35.34 - t2 * (2381.73 - t2 * (6402.7 - t2 * (7024.72 - t2 * 2710.57))))))) + ", " + Math.max(0, Math.min(255, Math.round(32.49 + t2 * (170.73 + t2 * (52.82 - t2 * (131.46 - t2 * (176.58 - t2 * 67.37))))))) + ", " + Math.max(0, Math.min(255, Math.round(81.24 + t2 * (442.36 - t2 * (2482.43 - t2 * (6167.24 - t2 * (6614.94 - t2 * 2475.67))))))) + ")";
}

// node_modules/d3-scale-chromatic/src/sequential-multi/cubehelix.js
var cubehelix_default2 = cubehelixLong(cubehelix(300, 0.5, 0), cubehelix(-240, 0.5, 1));

// node_modules/d3-scale-chromatic/src/sequential-multi/rainbow.js
var warm = cubehelixLong(cubehelix(-100, 0.75, 0.35), cubehelix(80, 1.5, 0.8));
var cool = cubehelixLong(cubehelix(260, 0.75, 0.35), cubehelix(80, 1.5, 0.8));
var c2 = cubehelix();
function rainbow_default(t2) {
  if (t2 < 0 || t2 > 1) t2 -= Math.floor(t2);
  var ts = Math.abs(t2 - 0.5);
  c2.h = 360 * t2 - 100;
  c2.s = 1.5 - 1.5 * ts;
  c2.l = 0.8 - 0.9 * ts;
  return c2 + "";
}

// node_modules/d3-scale-chromatic/src/sequential-multi/sinebow.js
var c3 = rgb();
var pi_1_3 = Math.PI / 3;
var pi_2_3 = Math.PI * 2 / 3;
function sinebow_default(t2) {
  var x3;
  t2 = (0.5 - t2) * Math.PI;
  c3.r = 255 * (x3 = Math.sin(t2)) * x3;
  c3.g = 255 * (x3 = Math.sin(t2 + pi_1_3)) * x3;
  c3.b = 255 * (x3 = Math.sin(t2 + pi_2_3)) * x3;
  return c3 + "";
}

// node_modules/d3-scale-chromatic/src/sequential-multi/turbo.js
function turbo_default(t2) {
  t2 = Math.max(0, Math.min(1, t2));
  return "rgb(" + Math.max(0, Math.min(255, Math.round(34.61 + t2 * (1172.33 - t2 * (10793.56 - t2 * (33300.12 - t2 * (38394.49 - t2 * 14825.05))))))) + ", " + Math.max(0, Math.min(255, Math.round(23.31 + t2 * (557.33 + t2 * (1225.33 - t2 * (3574.96 - t2 * (1073.77 + t2 * 707.56))))))) + ", " + Math.max(0, Math.min(255, Math.round(27.2 + t2 * (3211.1 - t2 * (15327.97 - t2 * (27814 - t2 * (22569.18 - t2 * 6838.66))))))) + ")";
}

// node_modules/d3-scale-chromatic/src/sequential-multi/viridis.js
function ramp(range2) {
  var n = range2.length;
  return function(t2) {
    return range2[Math.max(0, Math.min(n - 1, Math.floor(t2 * n)))];
  };
}
var viridis_default = ramp(colors_default("44015444025645045745055946075a46085c460a5d460b5e470d60470e6147106347116447136548146748166848176948186a481a6c481b6d481c6e481d6f481f70482071482173482374482475482576482677482878482979472a7a472c7a472d7b472e7c472f7d46307e46327e46337f463480453581453781453882443983443a83443b84433d84433e85423f854240864241864142874144874045884046883f47883f48893e49893e4a893e4c8a3d4d8a3d4e8a3c4f8a3c508b3b518b3b528b3a538b3a548c39558c39568c38588c38598c375a8c375b8d365c8d365d8d355e8d355f8d34608d34618d33628d33638d32648e32658e31668e31678e31688e30698e306a8e2f6b8e2f6c8e2e6d8e2e6e8e2e6f8e2d708e2d718e2c718e2c728e2c738e2b748e2b758e2a768e2a778e2a788e29798e297a8e297b8e287c8e287d8e277e8e277f8e27808e26818e26828e26828e25838e25848e25858e24868e24878e23888e23898e238a8d228b8d228c8d228d8d218e8d218f8d21908d21918c20928c20928c20938c1f948c1f958b1f968b1f978b1f988b1f998a1f9a8a1e9b8a1e9c891e9d891f9e891f9f881fa0881fa1881fa1871fa28720a38620a48621a58521a68522a78522a88423a98324aa8325ab8225ac8226ad8127ad8128ae8029af7f2ab07f2cb17e2db27d2eb37c2fb47c31b57b32b67a34b67935b77937b87838b9773aba763bbb753dbc743fbc7340bd7242be7144bf7046c06f48c16e4ac16d4cc26c4ec36b50c46a52c56954c56856c66758c7655ac8645cc8635ec96260ca6063cb5f65cb5e67cc5c69cd5b6ccd5a6ece5870cf5773d05675d05477d1537ad1517cd2507fd34e81d34d84d44b86d54989d5488bd6468ed64590d74393d74195d84098d83e9bd93c9dd93ba0da39a2da37a5db36a8db34aadc32addc30b0dd2fb2dd2db5de2bb8de29bade28bddf26c0df25c2df23c5e021c8e020cae11fcde11dd0e11cd2e21bd5e21ad8e219dae319dde318dfe318e2e418e5e419e7e419eae51aece51befe51cf1e51df4e61ef6e620f8e621fbe723fde725"));
var magma = ramp(colors_default("00000401000501010601010802010902020b02020d03030f03031204041405041606051806051a07061c08071e0907200a08220b09240c09260d0a290e0b2b100b2d110c2f120d31130d34140e36150e38160f3b180f3d19103f1a10421c10441d11471e114920114b21114e22115024125325125527125829115a2a115c2c115f2d11612f116331116533106734106936106b38106c390f6e3b0f703d0f713f0f72400f74420f75440f764510774710784910784a10794c117a4e117b4f127b51127c52137c54137d56147d57157e59157e5a167e5c167f5d177f5f187f601880621980641a80651a80671b80681c816a1c816b1d816d1d816e1e81701f81721f817320817521817621817822817922827b23827c23827e24828025828125818326818426818627818827818928818b29818c29818e2a81902a81912b81932b80942c80962c80982d80992d809b2e7f9c2e7f9e2f7fa02f7fa1307ea3307ea5317ea6317da8327daa337dab337cad347cae347bb0357bb2357bb3367ab5367ab73779b83779ba3878bc3978bd3977bf3a77c03a76c23b75c43c75c53c74c73d73c83e73ca3e72cc3f71cd4071cf4070d0416fd2426fd3436ed5446dd6456cd8456cd9466bdb476adc4869de4968df4a68e04c67e24d66e34e65e44f64e55064e75263e85362e95462ea5661eb5760ec5860ed5a5fee5b5eef5d5ef05f5ef1605df2625df2645cf3655cf4675cf4695cf56b5cf66c5cf66e5cf7705cf7725cf8745cf8765cf9785df9795df97b5dfa7d5efa7f5efa815ffb835ffb8560fb8761fc8961fc8a62fc8c63fc8e64fc9065fd9266fd9467fd9668fd9869fd9a6afd9b6bfe9d6cfe9f6dfea16efea36ffea571fea772fea973feaa74feac76feae77feb078feb27afeb47bfeb67cfeb77efeb97ffebb81febd82febf84fec185fec287fec488fec68afec88cfeca8dfecc8ffecd90fecf92fed194fed395fed597fed799fed89afdda9cfddc9efddea0fde0a1fde2a3fde3a5fde5a7fde7a9fde9aafdebacfcecaefceeb0fcf0b2fcf2b4fcf4b6fcf6b8fcf7b9fcf9bbfcfbbdfcfdbf"));
var inferno = ramp(colors_default("00000401000501010601010802010a02020c02020e03021004031204031405041706041907051b08051d09061f0a07220b07240c08260d08290e092b10092d110a30120a32140b34150b37160b39180c3c190c3e1b0c411c0c431e0c451f0c48210c4a230c4c240c4f260c51280b53290b552b0b572d0b592f0a5b310a5c320a5e340a5f3609613809623909633b09643d09653e0966400a67420a68440a68450a69470b6a490b6a4a0c6b4c0c6b4d0d6c4f0d6c510e6c520e6d540f6d550f6d57106e59106e5a116e5c126e5d126e5f136e61136e62146e64156e65156e67166e69166e6a176e6c186e6d186e6f196e71196e721a6e741a6e751b6e771c6d781c6d7a1d6d7c1d6d7d1e6d7f1e6c801f6c82206c84206b85216b87216b88226a8a226a8c23698d23698f24699025689225689326679526679727669827669a28659b29649d29649f2a63a02a63a22b62a32c61a52c60a62d60a82e5fa92e5eab2f5ead305dae305cb0315bb1325ab3325ab43359b63458b73557b93556ba3655bc3754bd3853bf3952c03a51c13a50c33b4fc43c4ec63d4dc73e4cc83f4bca404acb4149cc4248ce4347cf4446d04545d24644d34743d44842d54a41d74b3fd84c3ed94d3dda4e3cdb503bdd513ade5238df5337e05536e15635e25734e35933e45a31e55c30e65d2fe75e2ee8602de9612bea632aeb6429eb6628ec6726ed6925ee6a24ef6c23ef6e21f06f20f1711ff1731df2741cf3761bf37819f47918f57b17f57d15f67e14f68013f78212f78410f8850ff8870ef8890cf98b0bf98c0af98e09fa9008fa9207fa9407fb9606fb9706fb9906fb9b06fb9d07fc9f07fca108fca309fca50afca60cfca80dfcaa0ffcac11fcae12fcb014fcb216fcb418fbb61afbb81dfbba1ffbbc21fbbe23fac026fac228fac42afac62df9c72ff9c932f9cb35f8cd37f8cf3af7d13df7d340f6d543f6d746f5d949f5db4cf4dd4ff4df53f4e156f3e35af3e55df2e661f2e865f2ea69f1ec6df1ed71f1ef75f1f179f2f27df2f482f3f586f3f68af4f88ef5f992f6fa96f8fb9af9fc9dfafda1fcffa4"));
var plasma = ramp(colors_default("0d088710078813078916078a19068c1b068d1d068e20068f2206902406912605912805922a05932c05942e05952f059631059733059735049837049938049a3a049a3c049b3e049c3f049c41049d43039e44039e46039f48039f4903a04b03a14c02a14e02a25002a25102a35302a35502a45601a45801a45901a55b01a55c01a65e01a66001a66100a76300a76400a76600a76700a86900a86a00a86c00a86e00a86f00a87100a87201a87401a87501a87701a87801a87a02a87b02a87d03a87e03a88004a88104a78305a78405a78606a68707a68808a68a09a58b0aa58d0ba58e0ca48f0da4910ea3920fa39410a29511a19613a19814a099159f9a169f9c179e9d189d9e199da01a9ca11b9ba21d9aa31e9aa51f99a62098a72197a82296aa2395ab2494ac2694ad2793ae2892b02991b12a90b22b8fb32c8eb42e8db52f8cb6308bb7318ab83289ba3388bb3488bc3587bd3786be3885bf3984c03a83c13b82c23c81c33d80c43e7fc5407ec6417dc7427cc8437bc9447aca457acb4679cc4778cc4977cd4a76ce4b75cf4c74d04d73d14e72d24f71d35171d45270d5536fd5546ed6556dd7566cd8576bd9586ada5a6ada5b69db5c68dc5d67dd5e66de5f65de6164df6263e06363e16462e26561e26660e3685fe4695ee56a5de56b5de66c5ce76e5be76f5ae87059e97158e97257ea7457eb7556eb7655ec7754ed7953ed7a52ee7b51ef7c51ef7e50f07f4ff0804ef1814df1834cf2844bf3854bf3874af48849f48948f58b47f58c46f68d45f68f44f79044f79143f79342f89441f89540f9973ff9983ef99a3efa9b3dfa9c3cfa9e3bfb9f3afba139fba238fca338fca537fca636fca835fca934fdab33fdac33fdae32fdaf31fdb130fdb22ffdb42ffdb52efeb72dfeb82cfeba2cfebb2bfebd2afebe2afec029fdc229fdc328fdc527fdc627fdc827fdca26fdcb26fccd25fcce25fcd025fcd225fbd324fbd524fbd724fad824fada24f9dc24f9dd25f8df25f8e125f7e225f7e425f6e626f6e826f5e926f5eb27f4ed27f3ee27f3f027f2f227f1f426f1f525f0f724f0f921"));

// node_modules/d3-shape/src/constant.js
function constant_default6(x3) {
  return function constant() {
    return x3;
  };
}

// node_modules/d3-shape/src/math.js
var abs2 = Math.abs;
var atan2 = Math.atan2;
var cos = Math.cos;
var max2 = Math.max;
var min2 = Math.min;
var sin = Math.sin;
var sqrt = Math.sqrt;
var epsilon4 = 1e-12;
var pi2 = Math.PI;
var halfPi = pi2 / 2;
var tau2 = 2 * pi2;
function acos(x3) {
  return x3 > 1 ? 0 : x3 < -1 ? pi2 : Math.acos(x3);
}
function asin(x3) {
  return x3 >= 1 ? halfPi : x3 <= -1 ? -halfPi : Math.asin(x3);
}

// node_modules/d3-shape/src/path.js
function withPath(shape) {
  let digits2 = 3;
  shape.digits = function(_) {
    if (!arguments.length) return digits2;
    if (_ == null) {
      digits2 = null;
    } else {
      const d = Math.floor(_);
      if (!(d >= 0)) throw new RangeError(`invalid digits: ${_}`);
      digits2 = d;
    }
    return shape;
  };
  return () => new Path(digits2);
}

// node_modules/d3-shape/src/arc.js
function arcInnerRadius(d) {
  return d.innerRadius;
}
function arcOuterRadius(d) {
  return d.outerRadius;
}
function arcStartAngle(d) {
  return d.startAngle;
}
function arcEndAngle(d) {
  return d.endAngle;
}
function arcPadAngle(d) {
  return d && d.padAngle;
}
function intersect(x0, y0, x1, y1, x22, y22, x3, y3) {
  var x10 = x1 - x0, y10 = y1 - y0, x32 = x3 - x22, y32 = y3 - y22, t2 = y32 * x10 - x32 * y10;
  if (t2 * t2 < epsilon4) return;
  t2 = (x32 * (y0 - y22) - y32 * (x0 - x22)) / t2;
  return [x0 + t2 * x10, y0 + t2 * y10];
}
function cornerTangents(x0, y0, x1, y1, r1, rc, cw) {
  var x01 = x0 - x1, y01 = y0 - y1, lo = (cw ? rc : -rc) / sqrt(x01 * x01 + y01 * y01), ox = lo * y01, oy = -lo * x01, x11 = x0 + ox, y11 = y0 + oy, x10 = x1 + ox, y10 = y1 + oy, x00 = (x11 + x10) / 2, y00 = (y11 + y10) / 2, dx = x10 - x11, dy = y10 - y11, d2 = dx * dx + dy * dy, r = r1 - rc, D2 = x11 * y10 - x10 * y11, d = (dy < 0 ? -1 : 1) * sqrt(max2(0, r * r * d2 - D2 * D2)), cx0 = (D2 * dy - dx * d) / d2, cy0 = (-D2 * dx - dy * d) / d2, cx1 = (D2 * dy + dx * d) / d2, cy1 = (-D2 * dx + dy * d) / d2, dx0 = cx0 - x00, dy0 = cy0 - y00, dx1 = cx1 - x00, dy1 = cy1 - y00;
  if (dx0 * dx0 + dy0 * dy0 > dx1 * dx1 + dy1 * dy1) cx0 = cx1, cy0 = cy1;
  return {
    cx: cx0,
    cy: cy0,
    x01: -ox,
    y01: -oy,
    x11: cx0 * (r1 / r - 1),
    y11: cy0 * (r1 / r - 1)
  };
}
function arc_default() {
  var innerRadius = arcInnerRadius, outerRadius = arcOuterRadius, cornerRadius = constant_default6(0), padRadius = null, startAngle = arcStartAngle, endAngle = arcEndAngle, padAngle = arcPadAngle, context = null, path2 = withPath(arc);
  function arc() {
    var buffer, r, r0 = +innerRadius.apply(this, arguments), r1 = +outerRadius.apply(this, arguments), a0 = startAngle.apply(this, arguments) - halfPi, a1 = endAngle.apply(this, arguments) - halfPi, da = abs2(a1 - a0), cw = a1 > a0;
    if (!context) context = buffer = path2();
    if (r1 < r0) r = r1, r1 = r0, r0 = r;
    if (!(r1 > epsilon4)) context.moveTo(0, 0);
    else if (da > tau2 - epsilon4) {
      context.moveTo(r1 * cos(a0), r1 * sin(a0));
      context.arc(0, 0, r1, a0, a1, !cw);
      if (r0 > epsilon4) {
        context.moveTo(r0 * cos(a1), r0 * sin(a1));
        context.arc(0, 0, r0, a1, a0, cw);
      }
    } else {
      var a01 = a0, a11 = a1, a00 = a0, a10 = a1, da0 = da, da1 = da, ap = padAngle.apply(this, arguments) / 2, rp = ap > epsilon4 && (padRadius ? +padRadius.apply(this, arguments) : sqrt(r0 * r0 + r1 * r1)), rc = min2(abs2(r1 - r0) / 2, +cornerRadius.apply(this, arguments)), rc0 = rc, rc1 = rc, t0, t1;
      if (rp > epsilon4) {
        var p0 = asin(rp / r0 * sin(ap)), p1 = asin(rp / r1 * sin(ap));
        if ((da0 -= p0 * 2) > epsilon4) p0 *= cw ? 1 : -1, a00 += p0, a10 -= p0;
        else da0 = 0, a00 = a10 = (a0 + a1) / 2;
        if ((da1 -= p1 * 2) > epsilon4) p1 *= cw ? 1 : -1, a01 += p1, a11 -= p1;
        else da1 = 0, a01 = a11 = (a0 + a1) / 2;
      }
      var x01 = r1 * cos(a01), y01 = r1 * sin(a01), x10 = r0 * cos(a10), y10 = r0 * sin(a10);
      if (rc > epsilon4) {
        var x11 = r1 * cos(a11), y11 = r1 * sin(a11), x00 = r0 * cos(a00), y00 = r0 * sin(a00), oc;
        if (da < pi2) {
          if (oc = intersect(x01, y01, x00, y00, x11, y11, x10, y10)) {
            var ax = x01 - oc[0], ay = y01 - oc[1], bx = x11 - oc[0], by = y11 - oc[1], kc = 1 / sin(acos((ax * bx + ay * by) / (sqrt(ax * ax + ay * ay) * sqrt(bx * bx + by * by))) / 2), lc = sqrt(oc[0] * oc[0] + oc[1] * oc[1]);
            rc0 = min2(rc, (r0 - lc) / (kc - 1));
            rc1 = min2(rc, (r1 - lc) / (kc + 1));
          } else {
            rc0 = rc1 = 0;
          }
        }
      }
      if (!(da1 > epsilon4)) context.moveTo(x01, y01);
      else if (rc1 > epsilon4) {
        t0 = cornerTangents(x00, y00, x01, y01, r1, rc1, cw);
        t1 = cornerTangents(x11, y11, x10, y10, r1, rc1, cw);
        context.moveTo(t0.cx + t0.x01, t0.cy + t0.y01);
        if (rc1 < rc) context.arc(t0.cx, t0.cy, rc1, atan2(t0.y01, t0.x01), atan2(t1.y01, t1.x01), !cw);
        else {
          context.arc(t0.cx, t0.cy, rc1, atan2(t0.y01, t0.x01), atan2(t0.y11, t0.x11), !cw);
          context.arc(0, 0, r1, atan2(t0.cy + t0.y11, t0.cx + t0.x11), atan2(t1.cy + t1.y11, t1.cx + t1.x11), !cw);
          context.arc(t1.cx, t1.cy, rc1, atan2(t1.y11, t1.x11), atan2(t1.y01, t1.x01), !cw);
        }
      } else context.moveTo(x01, y01), context.arc(0, 0, r1, a01, a11, !cw);
      if (!(r0 > epsilon4) || !(da0 > epsilon4)) context.lineTo(x10, y10);
      else if (rc0 > epsilon4) {
        t0 = cornerTangents(x10, y10, x11, y11, r0, -rc0, cw);
        t1 = cornerTangents(x01, y01, x00, y00, r0, -rc0, cw);
        context.lineTo(t0.cx + t0.x01, t0.cy + t0.y01);
        if (rc0 < rc) context.arc(t0.cx, t0.cy, rc0, atan2(t0.y01, t0.x01), atan2(t1.y01, t1.x01), !cw);
        else {
          context.arc(t0.cx, t0.cy, rc0, atan2(t0.y01, t0.x01), atan2(t0.y11, t0.x11), !cw);
          context.arc(0, 0, r0, atan2(t0.cy + t0.y11, t0.cx + t0.x11), atan2(t1.cy + t1.y11, t1.cx + t1.x11), cw);
          context.arc(t1.cx, t1.cy, rc0, atan2(t1.y11, t1.x11), atan2(t1.y01, t1.x01), !cw);
        }
      } else context.arc(0, 0, r0, a10, a00, cw);
    }
    context.closePath();
    if (buffer) return context = null, buffer + "" || null;
  }
  arc.centroid = function() {
    var r = (+innerRadius.apply(this, arguments) + +outerRadius.apply(this, arguments)) / 2, a2 = (+startAngle.apply(this, arguments) + +endAngle.apply(this, arguments)) / 2 - pi2 / 2;
    return [cos(a2) * r, sin(a2) * r];
  };
  arc.innerRadius = function(_) {
    return arguments.length ? (innerRadius = typeof _ === "function" ? _ : constant_default6(+_), arc) : innerRadius;
  };
  arc.outerRadius = function(_) {
    return arguments.length ? (outerRadius = typeof _ === "function" ? _ : constant_default6(+_), arc) : outerRadius;
  };
  arc.cornerRadius = function(_) {
    return arguments.length ? (cornerRadius = typeof _ === "function" ? _ : constant_default6(+_), arc) : cornerRadius;
  };
  arc.padRadius = function(_) {
    return arguments.length ? (padRadius = _ == null ? null : typeof _ === "function" ? _ : constant_default6(+_), arc) : padRadius;
  };
  arc.startAngle = function(_) {
    return arguments.length ? (startAngle = typeof _ === "function" ? _ : constant_default6(+_), arc) : startAngle;
  };
  arc.endAngle = function(_) {
    return arguments.length ? (endAngle = typeof _ === "function" ? _ : constant_default6(+_), arc) : endAngle;
  };
  arc.padAngle = function(_) {
    return arguments.length ? (padAngle = typeof _ === "function" ? _ : constant_default6(+_), arc) : padAngle;
  };
  arc.context = function(_) {
    return arguments.length ? (context = _ == null ? null : _, arc) : context;
  };
  return arc;
}

// node_modules/d3-zoom/src/constant.js
var constant_default7 = (x3) => () => x3;

// node_modules/d3-zoom/src/event.js
function ZoomEvent(type2, {
  sourceEvent,
  target,
  transform: transform2,
  dispatch: dispatch2
}) {
  Object.defineProperties(this, {
    type: { value: type2, enumerable: true, configurable: true },
    sourceEvent: { value: sourceEvent, enumerable: true, configurable: true },
    target: { value: target, enumerable: true, configurable: true },
    transform: { value: transform2, enumerable: true, configurable: true },
    _: { value: dispatch2 }
  });
}

// node_modules/d3-zoom/src/transform.js
function Transform(k, x3, y3) {
  this.k = k;
  this.x = x3;
  this.y = y3;
}
Transform.prototype = {
  constructor: Transform,
  scale: function(k) {
    return k === 1 ? this : new Transform(this.k * k, this.x, this.y);
  },
  translate: function(x3, y3) {
    return x3 === 0 & y3 === 0 ? this : new Transform(this.k, this.x + this.k * x3, this.y + this.k * y3);
  },
  apply: function(point2) {
    return [point2[0] * this.k + this.x, point2[1] * this.k + this.y];
  },
  applyX: function(x3) {
    return x3 * this.k + this.x;
  },
  applyY: function(y3) {
    return y3 * this.k + this.y;
  },
  invert: function(location) {
    return [(location[0] - this.x) / this.k, (location[1] - this.y) / this.k];
  },
  invertX: function(x3) {
    return (x3 - this.x) / this.k;
  },
  invertY: function(y3) {
    return (y3 - this.y) / this.k;
  },
  rescaleX: function(x3) {
    return x3.copy().domain(x3.range().map(this.invertX, this).map(x3.invert, x3));
  },
  rescaleY: function(y3) {
    return y3.copy().domain(y3.range().map(this.invertY, this).map(y3.invert, y3));
  },
  toString: function() {
    return "translate(" + this.x + "," + this.y + ") scale(" + this.k + ")";
  }
};
var identity3 = new Transform(1, 0, 0);
transform.prototype = Transform.prototype;
function transform(node) {
  while (!node.__zoom) if (!(node = node.parentNode)) return identity3;
  return node.__zoom;
}

// node_modules/d3-zoom/src/noevent.js
function nopropagation3(event) {
  event.stopImmediatePropagation();
}
function noevent_default3(event) {
  event.preventDefault();
  event.stopImmediatePropagation();
}

// node_modules/d3-zoom/src/zoom.js
function defaultFilter2(event) {
  return (!event.ctrlKey || event.type === "wheel") && !event.button;
}
function defaultExtent() {
  var e = this;
  if (e instanceof SVGElement) {
    e = e.ownerSVGElement || e;
    if (e.hasAttribute("viewBox")) {
      e = e.viewBox.baseVal;
      return [[e.x, e.y], [e.x + e.width, e.y + e.height]];
    }
    return [[0, 0], [e.width.baseVal.value, e.height.baseVal.value]];
  }
  return [[0, 0], [e.clientWidth, e.clientHeight]];
}
function defaultTransform() {
  return this.__zoom || identity3;
}
function defaultWheelDelta(event) {
  return -event.deltaY * (event.deltaMode === 1 ? 0.05 : event.deltaMode ? 1 : 2e-3) * (event.ctrlKey ? 10 : 1);
}
function defaultTouchable2() {
  return navigator.maxTouchPoints || "ontouchstart" in this;
}
function defaultConstrain(transform2, extent, translateExtent) {
  var dx0 = transform2.invertX(extent[0][0]) - translateExtent[0][0], dx1 = transform2.invertX(extent[1][0]) - translateExtent[1][0], dy0 = transform2.invertY(extent[0][1]) - translateExtent[0][1], dy1 = transform2.invertY(extent[1][1]) - translateExtent[1][1];
  return transform2.translate(
    dx1 > dx0 ? (dx0 + dx1) / 2 : Math.min(0, dx0) || Math.max(0, dx1),
    dy1 > dy0 ? (dy0 + dy1) / 2 : Math.min(0, dy0) || Math.max(0, dy1)
  );
}
function zoom_default2() {
  var filter2 = defaultFilter2, extent = defaultExtent, constrain = defaultConstrain, wheelDelta = defaultWheelDelta, touchable = defaultTouchable2, scaleExtent = [0, Infinity], translateExtent = [[-Infinity, -Infinity], [Infinity, Infinity]], duration = 250, interpolate = zoom_default, listeners = dispatch_default("start", "zoom", "end"), touchstarting, touchfirst, touchending, touchDelay = 500, wheelDelay = 150, clickDistance2 = 0, tapDistance = 10;
  function zoom(selection2) {
    selection2.property("__zoom", defaultTransform).on("wheel.zoom", wheeled, { passive: false }).on("mousedown.zoom", mousedowned).on("dblclick.zoom", dblclicked).filter(touchable).on("touchstart.zoom", touchstarted).on("touchmove.zoom", touchmoved).on("touchend.zoom touchcancel.zoom", touchended).style("-webkit-tap-highlight-color", "rgba(0,0,0,0)");
  }
  zoom.transform = function(collection, transform2, point2, event) {
    var selection2 = collection.selection ? collection.selection() : collection;
    selection2.property("__zoom", defaultTransform);
    if (collection !== selection2) {
      schedule(collection, transform2, point2, event);
    } else {
      selection2.interrupt().each(function() {
        gesture(this, arguments).event(event).start().zoom(null, typeof transform2 === "function" ? transform2.apply(this, arguments) : transform2).end();
      });
    }
  };
  zoom.scaleBy = function(selection2, k, p, event) {
    zoom.scaleTo(selection2, function() {
      var k0 = this.__zoom.k, k1 = typeof k === "function" ? k.apply(this, arguments) : k;
      return k0 * k1;
    }, p, event);
  };
  zoom.scaleTo = function(selection2, k, p, event) {
    zoom.transform(selection2, function() {
      var e = extent.apply(this, arguments), t0 = this.__zoom, p0 = p == null ? centroid(e) : typeof p === "function" ? p.apply(this, arguments) : p, p1 = t0.invert(p0), k1 = typeof k === "function" ? k.apply(this, arguments) : k;
      return constrain(translate(scale(t0, k1), p0, p1), e, translateExtent);
    }, p, event);
  };
  zoom.translateBy = function(selection2, x3, y3, event) {
    zoom.transform(selection2, function() {
      return constrain(this.__zoom.translate(
        typeof x3 === "function" ? x3.apply(this, arguments) : x3,
        typeof y3 === "function" ? y3.apply(this, arguments) : y3
      ), extent.apply(this, arguments), translateExtent);
    }, null, event);
  };
  zoom.translateTo = function(selection2, x3, y3, p, event) {
    zoom.transform(selection2, function() {
      var e = extent.apply(this, arguments), t2 = this.__zoom, p0 = p == null ? centroid(e) : typeof p === "function" ? p.apply(this, arguments) : p;
      return constrain(identity3.translate(p0[0], p0[1]).scale(t2.k).translate(
        typeof x3 === "function" ? -x3.apply(this, arguments) : -x3,
        typeof y3 === "function" ? -y3.apply(this, arguments) : -y3
      ), e, translateExtent);
    }, p, event);
  };
  function scale(transform2, k) {
    k = Math.max(scaleExtent[0], Math.min(scaleExtent[1], k));
    return k === transform2.k ? transform2 : new Transform(k, transform2.x, transform2.y);
  }
  function translate(transform2, p0, p1) {
    var x3 = p0[0] - p1[0] * transform2.k, y3 = p0[1] - p1[1] * transform2.k;
    return x3 === transform2.x && y3 === transform2.y ? transform2 : new Transform(transform2.k, x3, y3);
  }
  function centroid(extent2) {
    return [(+extent2[0][0] + +extent2[1][0]) / 2, (+extent2[0][1] + +extent2[1][1]) / 2];
  }
  function schedule(transition2, transform2, point2, event) {
    transition2.on("start.zoom", function() {
      gesture(this, arguments).event(event).start();
    }).on("interrupt.zoom end.zoom", function() {
      gesture(this, arguments).event(event).end();
    }).tween("zoom", function() {
      var that = this, args = arguments, g2 = gesture(that, args).event(event), e = extent.apply(that, args), p = point2 == null ? centroid(e) : typeof point2 === "function" ? point2.apply(that, args) : point2, w = Math.max(e[1][0] - e[0][0], e[1][1] - e[0][1]), a2 = that.__zoom, b = typeof transform2 === "function" ? transform2.apply(that, args) : transform2, i = interpolate(a2.invert(p).concat(w / a2.k), b.invert(p).concat(w / b.k));
      return function(t2) {
        if (t2 === 1) t2 = b;
        else {
          var l = i(t2), k = w / l[2];
          t2 = new Transform(k, p[0] - l[0] * k, p[1] - l[1] * k);
        }
        g2.zoom(null, t2);
      };
    });
  }
  function gesture(that, args, clean) {
    return !clean && that.__zooming || new Gesture(that, args);
  }
  function Gesture(that, args) {
    this.that = that;
    this.args = args;
    this.active = 0;
    this.sourceEvent = null;
    this.extent = extent.apply(that, args);
    this.taps = 0;
  }
  Gesture.prototype = {
    event: function(event) {
      if (event) this.sourceEvent = event;
      return this;
    },
    start: function() {
      if (++this.active === 1) {
        this.that.__zooming = this;
        this.emit("start");
      }
      return this;
    },
    zoom: function(key, transform2) {
      if (this.mouse && key !== "mouse") this.mouse[1] = transform2.invert(this.mouse[0]);
      if (this.touch0 && key !== "touch") this.touch0[1] = transform2.invert(this.touch0[0]);
      if (this.touch1 && key !== "touch") this.touch1[1] = transform2.invert(this.touch1[0]);
      this.that.__zoom = transform2;
      this.emit("zoom");
      return this;
    },
    end: function() {
      if (--this.active === 0) {
        delete this.that.__zooming;
        this.emit("end");
      }
      return this;
    },
    emit: function(type2) {
      var d = select_default2(this.that).datum();
      listeners.call(
        type2,
        this.that,
        new ZoomEvent(type2, {
          sourceEvent: this.sourceEvent,
          target: zoom,
          type: type2,
          transform: this.that.__zoom,
          dispatch: listeners
        }),
        d
      );
    }
  };
  function wheeled(event, ...args) {
    if (!filter2.apply(this, arguments)) return;
    var g2 = gesture(this, args).event(event), t2 = this.__zoom, k = Math.max(scaleExtent[0], Math.min(scaleExtent[1], t2.k * Math.pow(2, wheelDelta.apply(this, arguments)))), p = pointer_default(event);
    if (g2.wheel) {
      if (g2.mouse[0][0] !== p[0] || g2.mouse[0][1] !== p[1]) {
        g2.mouse[1] = t2.invert(g2.mouse[0] = p);
      }
      clearTimeout(g2.wheel);
    } else if (t2.k === k) return;
    else {
      g2.mouse = [p, t2.invert(p)];
      interrupt_default(this);
      g2.start();
    }
    noevent_default3(event);
    g2.wheel = setTimeout(wheelidled, wheelDelay);
    g2.zoom("mouse", constrain(translate(scale(t2, k), g2.mouse[0], g2.mouse[1]), g2.extent, translateExtent));
    function wheelidled() {
      g2.wheel = null;
      g2.end();
    }
  }
  function mousedowned(event, ...args) {
    if (touchending || !filter2.apply(this, arguments)) return;
    var currentTarget = event.currentTarget, g2 = gesture(this, args, true).event(event), v = select_default2(event.view).on("mousemove.zoom", mousemoved, true).on("mouseup.zoom", mouseupped, true), p = pointer_default(event, currentTarget), x0 = event.clientX, y0 = event.clientY;
    nodrag_default(event.view);
    nopropagation3(event);
    g2.mouse = [p, this.__zoom.invert(p)];
    interrupt_default(this);
    g2.start();
    function mousemoved(event2) {
      noevent_default3(event2);
      if (!g2.moved) {
        var dx = event2.clientX - x0, dy = event2.clientY - y0;
        g2.moved = dx * dx + dy * dy > clickDistance2;
      }
      g2.event(event2).zoom("mouse", constrain(translate(g2.that.__zoom, g2.mouse[0] = pointer_default(event2, currentTarget), g2.mouse[1]), g2.extent, translateExtent));
    }
    function mouseupped(event2) {
      v.on("mousemove.zoom mouseup.zoom", null);
      yesdrag(event2.view, g2.moved);
      noevent_default3(event2);
      g2.event(event2).end();
    }
  }
  function dblclicked(event, ...args) {
    if (!filter2.apply(this, arguments)) return;
    var t0 = this.__zoom, p0 = pointer_default(event.changedTouches ? event.changedTouches[0] : event, this), p1 = t0.invert(p0), k1 = t0.k * (event.shiftKey ? 0.5 : 2), t1 = constrain(translate(scale(t0, k1), p0, p1), extent.apply(this, args), translateExtent);
    noevent_default3(event);
    if (duration > 0) select_default2(this).transition().duration(duration).call(schedule, t1, p0, event);
    else select_default2(this).call(zoom.transform, t1, p0, event);
  }
  function touchstarted(event, ...args) {
    if (!filter2.apply(this, arguments)) return;
    var touches = event.touches, n = touches.length, g2 = gesture(this, args, event.changedTouches.length === n).event(event), started, i, t2, p;
    nopropagation3(event);
    for (i = 0; i < n; ++i) {
      t2 = touches[i], p = pointer_default(t2, this);
      p = [p, this.__zoom.invert(p), t2.identifier];
      if (!g2.touch0) g2.touch0 = p, started = true, g2.taps = 1 + !!touchstarting;
      else if (!g2.touch1 && g2.touch0[2] !== p[2]) g2.touch1 = p, g2.taps = 0;
    }
    if (touchstarting) touchstarting = clearTimeout(touchstarting);
    if (started) {
      if (g2.taps < 2) touchfirst = p[0], touchstarting = setTimeout(function() {
        touchstarting = null;
      }, touchDelay);
      interrupt_default(this);
      g2.start();
    }
  }
  function touchmoved(event, ...args) {
    if (!this.__zooming) return;
    var g2 = gesture(this, args).event(event), touches = event.changedTouches, n = touches.length, i, t2, p, l;
    noevent_default3(event);
    for (i = 0; i < n; ++i) {
      t2 = touches[i], p = pointer_default(t2, this);
      if (g2.touch0 && g2.touch0[2] === t2.identifier) g2.touch0[0] = p;
      else if (g2.touch1 && g2.touch1[2] === t2.identifier) g2.touch1[0] = p;
    }
    t2 = g2.that.__zoom;
    if (g2.touch1) {
      var p0 = g2.touch0[0], l0 = g2.touch0[1], p1 = g2.touch1[0], l1 = g2.touch1[1], dp = (dp = p1[0] - p0[0]) * dp + (dp = p1[1] - p0[1]) * dp, dl = (dl = l1[0] - l0[0]) * dl + (dl = l1[1] - l0[1]) * dl;
      t2 = scale(t2, Math.sqrt(dp / dl));
      p = [(p0[0] + p1[0]) / 2, (p0[1] + p1[1]) / 2];
      l = [(l0[0] + l1[0]) / 2, (l0[1] + l1[1]) / 2];
    } else if (g2.touch0) p = g2.touch0[0], l = g2.touch0[1];
    else return;
    g2.zoom("touch", constrain(translate(t2, p, l), g2.extent, translateExtent));
  }
  function touchended(event, ...args) {
    if (!this.__zooming) return;
    var g2 = gesture(this, args).event(event), touches = event.changedTouches, n = touches.length, i, t2;
    nopropagation3(event);
    if (touchending) clearTimeout(touchending);
    touchending = setTimeout(function() {
      touchending = null;
    }, touchDelay);
    for (i = 0; i < n; ++i) {
      t2 = touches[i];
      if (g2.touch0 && g2.touch0[2] === t2.identifier) delete g2.touch0;
      else if (g2.touch1 && g2.touch1[2] === t2.identifier) delete g2.touch1;
    }
    if (g2.touch1 && !g2.touch0) g2.touch0 = g2.touch1, delete g2.touch1;
    if (g2.touch0) g2.touch0[1] = this.__zoom.invert(g2.touch0[0]);
    else {
      g2.end();
      if (g2.taps === 2) {
        t2 = pointer_default(t2, this);
        if (Math.hypot(touchfirst[0] - t2[0], touchfirst[1] - t2[1]) < tapDistance) {
          var p = select_default2(this).on("dblclick.zoom");
          if (p) p.apply(this, arguments);
        }
      }
    }
  }
  zoom.wheelDelta = function(_) {
    return arguments.length ? (wheelDelta = typeof _ === "function" ? _ : constant_default7(+_), zoom) : wheelDelta;
  };
  zoom.filter = function(_) {
    return arguments.length ? (filter2 = typeof _ === "function" ? _ : constant_default7(!!_), zoom) : filter2;
  };
  zoom.touchable = function(_) {
    return arguments.length ? (touchable = typeof _ === "function" ? _ : constant_default7(!!_), zoom) : touchable;
  };
  zoom.extent = function(_) {
    return arguments.length ? (extent = typeof _ === "function" ? _ : constant_default7([[+_[0][0], +_[0][1]], [+_[1][0], +_[1][1]]]), zoom) : extent;
  };
  zoom.scaleExtent = function(_) {
    return arguments.length ? (scaleExtent[0] = +_[0], scaleExtent[1] = +_[1], zoom) : [scaleExtent[0], scaleExtent[1]];
  };
  zoom.translateExtent = function(_) {
    return arguments.length ? (translateExtent[0][0] = +_[0][0], translateExtent[1][0] = +_[1][0], translateExtent[0][1] = +_[0][1], translateExtent[1][1] = +_[1][1], zoom) : [[translateExtent[0][0], translateExtent[0][1]], [translateExtent[1][0], translateExtent[1][1]]];
  };
  zoom.constrain = function(_) {
    return arguments.length ? (constrain = _, zoom) : constrain;
  };
  zoom.duration = function(_) {
    return arguments.length ? (duration = +_, zoom) : duration;
  };
  zoom.interpolate = function(_) {
    return arguments.length ? (interpolate = _, zoom) : interpolate;
  };
  zoom.on = function() {
    var value = listeners.on.apply(listeners, arguments);
    return value === listeners ? zoom : value;
  };
  zoom.clickDistance = function(_) {
    return arguments.length ? (clickDistance2 = (_ = +_) * _, zoom) : Math.sqrt(clickDistance2);
  };
  zoom.tapDistance = function(_) {
    return arguments.length ? (tapDistance = +_, zoom) : tapDistance;
  };
  return zoom;
}

// node_modules/simple-statistics/dist/simple-statistics.mjs
function sum(x3) {
  if (x3.length === 0) {
    return 0;
  }
  var sum2 = x3[0];
  var correction = 0;
  var transition2;
  if (typeof sum2 !== "number") {
    return Number.NaN;
  }
  for (var i = 1; i < x3.length; i++) {
    if (typeof x3[i] !== "number") {
      return Number.NaN;
    }
    transition2 = sum2 + x3[i];
    if (Math.abs(sum2) >= Math.abs(x3[i])) {
      correction += sum2 - transition2 + x3[i];
    } else {
      correction += x3[i] - transition2 + sum2;
    }
    sum2 = transition2;
  }
  return sum2 + correction;
}
function mean(x3) {
  if (x3.length === 0) {
    throw new Error("mean requires at least one data point");
  }
  return sum(x3) / x3.length;
}
function sumNthPowerDeviations(x3, n) {
  var meanValue = mean(x3);
  var sum2 = 0;
  var tempValue;
  var i;
  if (n === 2) {
    for (i = 0; i < x3.length; i++) {
      tempValue = x3[i] - meanValue;
      sum2 += tempValue * tempValue;
    }
  } else {
    for (i = 0; i < x3.length; i++) {
      sum2 += Math.pow(x3[i] - meanValue, n);
    }
  }
  return sum2;
}
function variance(x3) {
  if (x3.length === 0) {
    throw new Error("variance requires at least one data point");
  }
  return sumNthPowerDeviations(x3, 2) / x3.length;
}
function standardDeviation(x3) {
  if (x3.length === 1) {
    return 0;
  }
  var v = variance(x3);
  return Math.sqrt(v);
}
function quantileSorted(x3, p) {
  var idx = x3.length * p;
  if (x3.length === 0) {
    throw new Error("quantile requires at least one data point.");
  } else if (p < 0 || p > 1) {
    throw new Error("quantiles must be between 0 and 1");
  } else if (p === 1) {
    return x3[x3.length - 1];
  } else if (p === 0) {
    return x3[0];
  } else if (idx % 1 !== 0) {
    return x3[Math.ceil(idx) - 1];
  } else if (x3.length % 2 === 0) {
    return (x3[idx - 1] + x3[idx]) / 2;
  } else {
    return x3[idx];
  }
}
function quickselect(arr, k, left2, right2) {
  left2 = left2 || 0;
  right2 = right2 || arr.length - 1;
  while (right2 > left2) {
    if (right2 - left2 > 600) {
      var n = right2 - left2 + 1;
      var m2 = k - left2 + 1;
      var z = Math.log(n);
      var s = 0.5 * Math.exp(2 * z / 3);
      var sd = 0.5 * Math.sqrt(z * s * (n - s) / n);
      if (m2 - n / 2 < 0) {
        sd *= -1;
      }
      var newLeft = Math.max(left2, Math.floor(k - m2 * s / n + sd));
      var newRight = Math.min(
        right2,
        Math.floor(k + (n - m2) * s / n + sd)
      );
      quickselect(arr, k, newLeft, newRight);
    }
    var t2 = arr[k];
    var i = left2;
    var j = right2;
    swap(arr, left2, k);
    if (arr[right2] > t2) {
      swap(arr, left2, right2);
    }
    while (i < j) {
      swap(arr, i, j);
      i++;
      j--;
      while (arr[i] < t2) {
        i++;
      }
      while (arr[j] > t2) {
        j--;
      }
    }
    if (arr[left2] === t2) {
      swap(arr, left2, j);
    } else {
      j++;
      swap(arr, j, right2);
    }
    if (j <= k) {
      left2 = j + 1;
    }
    if (k <= j) {
      right2 = j - 1;
    }
  }
}
function swap(arr, i, j) {
  var tmp = arr[i];
  arr[i] = arr[j];
  arr[j] = tmp;
}
function quantile(x3, p) {
  var copy2 = x3.slice();
  if (Array.isArray(p)) {
    multiQuantileSelect(copy2, p);
    var results = [];
    for (var i = 0; i < p.length; i++) {
      results[i] = quantileSorted(copy2, p[i]);
    }
    return results;
  } else {
    var idx = quantileIndex(copy2.length, p);
    quantileSelect(copy2, idx, 0, copy2.length - 1);
    return quantileSorted(copy2, p);
  }
}
function quantileSelect(arr, k, left2, right2) {
  if (k % 1 === 0) {
    quickselect(arr, k, left2, right2);
  } else {
    k = Math.floor(k);
    quickselect(arr, k, left2, right2);
    quickselect(arr, k + 1, k + 1, right2);
  }
}
function multiQuantileSelect(arr, p) {
  var indices = [0];
  for (var i = 0; i < p.length; i++) {
    indices.push(quantileIndex(arr.length, p[i]));
  }
  indices.push(arr.length - 1);
  indices.sort(compare);
  var stack = [0, indices.length - 1];
  while (stack.length) {
    var r = Math.ceil(stack.pop());
    var l = Math.floor(stack.pop());
    if (r - l <= 1) {
      continue;
    }
    var m2 = Math.floor((l + r) / 2);
    quantileSelect(
      arr,
      indices[m2],
      Math.floor(indices[l]),
      Math.ceil(indices[r])
    );
    stack.push(l, m2, m2, r);
  }
}
function compare(a2, b) {
  return a2 - b;
}
function quantileIndex(len, p) {
  var idx = len * p;
  if (p === 1) {
    return len - 1;
  } else if (p === 0) {
    return 0;
  } else if (idx % 1 !== 0) {
    return Math.ceil(idx) - 1;
  } else if (len % 2 === 0) {
    return idx - 0.5;
  } else {
    return idx;
  }
}
function interquartileRange(x3) {
  var q1 = quantile(x3, 0.75);
  var q2 = quantile(x3, 0.25);
  if (typeof q1 === "number" && typeof q2 === "number") {
    return q1 - q2;
  }
}
function median(x3) {
  return +quantile(x3, 0.5);
}
function jenksBreaks(data, lowerClassLimits, nClasses) {
  var k = data.length;
  var kclass = [];
  var countNum = nClasses;
  kclass[nClasses] = data[data.length - 1];
  while (countNum > 0) {
    kclass[countNum - 1] = data[lowerClassLimits[k][countNum] - 1];
    k = lowerClassLimits[k][countNum] - 1;
    countNum--;
  }
  return kclass;
}
function jenksMatrices(data, nClasses) {
  var lowerClassLimits = [];
  var varianceCombinations = [];
  var i;
  var j;
  var variance2 = 0;
  for (i = 0; i < data.length + 1; i++) {
    var tmp1 = [];
    var tmp2 = [];
    for (j = 0; j < nClasses + 1; j++) {
      tmp1.push(0);
      tmp2.push(0);
    }
    lowerClassLimits.push(tmp1);
    varianceCombinations.push(tmp2);
  }
  for (i = 1; i < nClasses + 1; i++) {
    lowerClassLimits[1][i] = 1;
    varianceCombinations[1][i] = 0;
    for (j = 2; j < data.length + 1; j++) {
      varianceCombinations[j][i] = Number.POSITIVE_INFINITY;
    }
  }
  for (var l = 2; l < data.length + 1; l++) {
    var sum2 = 0;
    var sumSquares = 0;
    var w = 0;
    var i4 = 0;
    for (var m2 = 1; m2 < l + 1; m2++) {
      var lowerClassLimit = l - m2 + 1;
      var val = data[lowerClassLimit - 1];
      w++;
      sum2 += val;
      sumSquares += val * val;
      variance2 = sumSquares - sum2 * sum2 / w;
      i4 = lowerClassLimit - 1;
      if (i4 !== 0) {
        for (j = 2; j < nClasses + 1; j++) {
          if (varianceCombinations[l][j] >= variance2 + varianceCombinations[i4][j - 1]) {
            lowerClassLimits[l][j] = lowerClassLimit;
            varianceCombinations[l][j] = variance2 + varianceCombinations[i4][j - 1];
          }
        }
      }
    }
    lowerClassLimits[l][1] = 1;
    varianceCombinations[l][1] = variance2;
  }
  return {
    lowerClassLimits,
    varianceCombinations
  };
}
function jenks(data, nClasses) {
  if (nClasses > data.length) {
    return null;
  }
  data = data.slice().sort(function(a2, b) {
    return a2 - b;
  });
  var matrices = jenksMatrices(data, nClasses);
  var lowerClassLimits = matrices.lowerClassLimits;
  return jenksBreaks(data, lowerClassLimits, nClasses);
}
function sampleVariance(x3) {
  if (x3.length < 2) {
    throw new Error("sampleVariance requires at least two data points");
  }
  var sumSquaredDeviationsValue = sumNthPowerDeviations(x3, 2);
  var besselsCorrection = x3.length - 1;
  return sumSquaredDeviationsValue / besselsCorrection;
}
function sampleStandardDeviation(x3) {
  var sampleVarianceX = sampleVariance(x3);
  return Math.sqrt(sampleVarianceX);
}
function sampleSkewness(x3) {
  if (x3.length < 3) {
    throw new Error("sampleSkewness requires at least three data points");
  }
  var meanValue = mean(x3);
  var tempValue;
  var sumSquaredDeviations = 0;
  var sumCubedDeviations = 0;
  for (var i = 0; i < x3.length; i++) {
    tempValue = x3[i] - meanValue;
    sumSquaredDeviations += tempValue * tempValue;
    sumCubedDeviations += tempValue * tempValue * tempValue;
  }
  var besselsCorrection = x3.length - 1;
  var theSampleStandardDeviation = Math.sqrt(
    sumSquaredDeviations / besselsCorrection
  );
  var n = x3.length;
  var cubedS = Math.pow(theSampleStandardDeviation, 3);
  return n * sumCubedDeviations / ((n - 1) * (n - 2) * cubedS);
}
function sampleKurtosis(x3) {
  var n = x3.length;
  if (n < 4) {
    throw new Error("sampleKurtosis requires at least four data points");
  }
  var meanValue = mean(x3);
  var tempValue;
  var secondCentralMoment = 0;
  var fourthCentralMoment = 0;
  for (var i = 0; i < n; i++) {
    tempValue = x3[i] - meanValue;
    secondCentralMoment += tempValue * tempValue;
    fourthCentralMoment += tempValue * tempValue * tempValue * tempValue;
  }
  return (n - 1) / ((n - 2) * (n - 3)) * (n * (n + 1) * fourthCentralMoment / (secondCentralMoment * secondCentralMoment) - 3 * (n - 1));
}
var BayesianClassifier = function BayesianClassifier2() {
  this.totalCount = 0;
  this.data = {};
};
BayesianClassifier.prototype.train = function train(item, category) {
  if (!this.data[category]) {
    this.data[category] = {};
  }
  for (var k in item) {
    var v = item[k];
    if (this.data[category][k] === void 0) {
      this.data[category][k] = {};
    }
    if (this.data[category][k][v] === void 0) {
      this.data[category][k][v] = 0;
    }
    this.data[category][k][v]++;
  }
  this.totalCount++;
};
BayesianClassifier.prototype.score = function score(item) {
  var odds = {};
  var category;
  for (var k in item) {
    var v = item[k];
    for (category in this.data) {
      odds[category] = {};
      if (this.data[category][k]) {
        odds[category][k + "_" + v] = (this.data[category][k][v] || 0) / this.totalCount;
      } else {
        odds[category][k + "_" + v] = 0;
      }
    }
  }
  var oddsSums = {};
  for (category in odds) {
    oddsSums[category] = 0;
    for (var combination in odds[category]) {
      oddsSums[category] += odds[category][combination];
    }
  }
  return oddsSums;
};
var PerceptronModel = function PerceptronModel2() {
  this.weights = [];
  this.bias = 0;
};
PerceptronModel.prototype.predict = function predict(features) {
  if (features.length !== this.weights.length) {
    return null;
  }
  var score2 = 0;
  for (var i = 0; i < this.weights.length; i++) {
    score2 += this.weights[i] * features[i];
  }
  score2 += this.bias;
  if (score2 > 0) {
    return 1;
  } else {
    return 0;
  }
};
PerceptronModel.prototype.train = function train2(features, label) {
  if (label !== 0 && label !== 1) {
    return null;
  }
  if (features.length !== this.weights.length) {
    this.weights = features;
    this.bias = 1;
  }
  var prediction = this.predict(features);
  if (typeof prediction === "number" && prediction !== label) {
    var gradient = label - prediction;
    for (var i = 0; i < this.weights.length; i++) {
      this.weights[i] += gradient * features[i];
    }
    this.bias += gradient;
  }
  return this;
};
var g = 607 / 128;
var LOGSQRT2PI = Math.log(Math.sqrt(2 * Math.PI));
var SQRT_2PI$1 = Math.sqrt(2 * Math.PI);
var kernels = {
  /**
   * The gaussian kernel.
   * @private
   */
  gaussian: function(u) {
    return Math.exp(-0.5 * u * u) / SQRT_2PI$1;
  }
};
var bandwidthMethods = {
  /**
   * The ["normal reference distribution"
   * rule-of-thumb](https://stat.ethz.ch/R-manual/R-devel/library/MASS/html/bandwidth.nrd.html),
   * a commonly used version of [Silverman's
   * rule-of-thumb](https://en.wikipedia.org/wiki/Kernel_density_estimation#A_rule-of-thumb_bandwidth_estimator).
   * @private
   */
  nrd: function(x3) {
    var s = sampleStandardDeviation(x3);
    var iqr = interquartileRange(x3);
    if (typeof iqr === "number") {
      s = Math.min(s, iqr / 1.34);
    }
    return 1.06 * s * Math.pow(x3.length, -0.2);
  }
};
function kernelDensityEstimation(X2, kernel, bandwidthMethod) {
  var kernelFn;
  if (kernel === void 0) {
    kernelFn = kernels.gaussian;
  } else if (typeof kernel === "string") {
    if (!kernels[kernel]) {
      throw new Error('Unknown kernel "' + kernel + '"');
    }
    kernelFn = kernels[kernel];
  } else {
    kernelFn = kernel;
  }
  var bandwidth;
  if (typeof bandwidthMethod === "undefined") {
    bandwidth = bandwidthMethods.nrd(X2);
  } else if (typeof bandwidthMethod === "string") {
    if (!bandwidthMethods[bandwidthMethod]) {
      throw new Error(
        'Unknown bandwidth method "' + bandwidthMethod + '"'
      );
    }
    bandwidth = bandwidthMethods[bandwidthMethod](X2);
  } else {
    bandwidth = bandwidthMethod;
  }
  return function(x3) {
    var i = 0;
    var sum2 = 0;
    for (i = 0; i < X2.length; i++) {
      sum2 += kernelFn((x3 - X2[i]) / bandwidth);
    }
    return sum2 / bandwidth / X2.length;
  };
}
var SQRT_2PI = Math.sqrt(2 * Math.PI);
function cumulativeDistribution(z) {
  var sum2 = z;
  var tmp = z;
  for (var i = 1; i < 15; i++) {
    tmp *= z * z / (2 * i + 1);
    sum2 += tmp;
  }
  return Math.round((0.5 + sum2 / SQRT_2PI * Math.exp(-z * z / 2)) * 1e4) / 1e4;
}
var standardNormalTable = [];
for (z = 0; z <= 3.09; z += 0.01) {
  standardNormalTable.push(cumulativeDistribution(z));
}
var z;

// src/services/PluginService.ts
var PluginService = class {
  constructor(app) {
    const extendedApp = app;
    this.plugin = extendedApp.plugins.plugins["knowledge-graph-analysis"];
    if (!this.plugin) {
      throw new Error("Graph Analysis plugin not found");
    }
  }
  getPlugin() {
    return this.plugin;
  }
  async ensureWasmLoaded() {
    return this.plugin.ensureWasmLoaded();
  }
  async buildGraphFromVault() {
    await this.ensureWasmLoaded();
    return this.plugin.buildGraphFromVault();
  }
  /**
   * Initialize the graph with provided graph data.
   * This method aligns with the Rust side's VaultData structure.
   */
  async initializeGraph(graphData) {
    await this.ensureWasmLoaded();
    await this.plugin.initializeGraphWithData(graphData);
  }
  calculateDegreeCentrality() {
    return this.plugin.calculateDegreeCentralityCached();
  }
  calculateEigenvectorCentrality() {
    return this.plugin.calculateEigenvectorCentralityCached();
  }
  calculateBetweennessCentrality() {
    return this.plugin.calculateBetweennessCentralityCached();
  }
  calculateClosenessCentrality() {
    return this.plugin.calculateClosenessCentralityCached();
  }
  getNodeNeighbors(nodeId) {
    return this.plugin.getNodeNeighborsCached(nodeId);
  }
  clearGraphCache() {
    this.plugin.clearGraphCache();
  }
  getGraphMetadata() {
    return this.plugin.getGraphMetadata();
  }
};

// src/components/graph-view/data/graph-builder.ts
var GraphDataBuilder = class {
  constructor(app) {
    this.pluginService = new PluginService(app);
    this.app = app;
  }
  getLinksFromFile(file) {
    const links = /* @__PURE__ */ new Set();
    const cache = this.app.metadataCache.getFileCache(file);
    if (!cache) return links;
    const allLinks = [
      ...cache.links || [],
      ...cache.embeds || [],
      ...cache.frontmatterLinks || []
    ];
    for (const link of allLinks) {
      const resolvedFile = this.app.metadataCache.getFirstLinkpathDest(link.link, file.path);
      if (resolvedFile) {
        links.add(resolvedFile.path);
      }
    }
    return links;
  }
  async buildGraphData() {
    const plugin = this.pluginService.getPlugin();
    const files = plugin.getIncludedMarkdownFiles();
    const nodes = [];
    const pathToIndex = /* @__PURE__ */ new Map();
    const edges = /* @__PURE__ */ new Set();
    for (const file of files) {
      const index2 = nodes.length;
      nodes.push(file.path);
      pathToIndex.set(file.path, index2);
    }
    const linkCache = /* @__PURE__ */ new Map();
    for (const file of files) {
      const sourceIndex = pathToIndex.get(file.path);
      if (sourceIndex === void 0) continue;
      let linkedPaths;
      if (linkCache.has(file.path)) {
        linkedPaths = linkCache.get(file.path);
      } else {
        linkedPaths = this.getLinksFromFile(file);
        linkCache.set(file.path, linkedPaths);
      }
      for (const linkedPath of linkedPaths) {
        const targetIndex = pathToIndex.get(linkedPath);
        if (targetIndex === void 0) continue;
        const minIndex = Math.min(sourceIndex, targetIndex);
        const maxIndex = Math.max(sourceIndex, targetIndex);
        edges.add(`${minIndex},${maxIndex}`);
      }
    }
    const edgesArray = [];
    for (const edge of edges) {
      const parts = edge.split(",");
      const source = Number(parts[0] ?? 0);
      const target = Number(parts[1] ?? 0);
      edgesArray.push([source, target]);
    }
    const graphData = {
      nodes,
      edges: edgesArray
    };
    await this.pluginService.initializeGraph(graphData);
    const metadata = this.pluginService.getGraphMetadata();
    const degreeCentrality = this.pluginService.calculateDegreeCentrality();
    return {
      graphData,
      degreeCentrality,
      metadata
    };
  }
};

// src/ai/VaultSemanticAnalysisManager.ts
var import_obsidian11 = require("obsidian");

// src/views/VaultAnalysisModals.ts
var import_obsidian10 = require("obsidian");

// src/utils/PluginAccess.ts
function getIncludedMarkdownFiles(app) {
  const plugin = app.plugins?.plugins?.["knowledge-graph-analysis"];
  if (plugin?.getIncludedMarkdownFiles) {
    return plugin.getIncludedMarkdownFiles();
  }
  return app.vault.getMarkdownFiles();
}

// src/components/calendar-chart/KnowledgeCalendarChart.ts
var _KnowledgeCalendarChart = class _KnowledgeCalendarChart {
  constructor(app, container, options = {}) {
    this.data = [];
    this.app = app;
    this.container = container;
    this.options = {
      cellSize: 11,
      yearRange: 1,
      ...options
    };
  }
  static getCachedCalendar(sourceAnalysisId) {
    return _KnowledgeCalendarChart.calendarCacheBySourceId.get(sourceAnalysisId);
  }
  static setCachedCalendar(sourceAnalysisId, data) {
    _KnowledgeCalendarChart.calendarCacheBySourceId.set(sourceAnalysisId, data);
  }
  async renderWithData(data, summaryContext) {
    this.data = data;
    this.summaryContext = summaryContext;
    await this.render();
  }
  async generateCalendarData(sourceAnalysisId) {
    if (sourceAnalysisId) {
      const cached = _KnowledgeCalendarChart.calendarCacheBySourceId.get(sourceAnalysisId);
      if (cached) {
        this.data = cached;
        return this.data;
      }
    }
    const files = getIncludedMarkdownFiles(this.app);
    const dailyActivity = /* @__PURE__ */ new Map();
    const BATCH_SIZE = 10;
    const batches = [];
    for (let i = 0; i < files.length; i += BATCH_SIZE) {
      batches.push(files.slice(i, i + BATCH_SIZE));
    }
    await Promise.all(batches.map(async (batch) => {
      await Promise.all(batch.map(async (file) => {
        try {
          const content = await this.app.vault.read(file);
          const wordCount = this.calculateWordCount(content);
          const modifiedDate = new Date(file.stat.mtime);
          const dateKey = modifiedDate.toISOString().split("T")[0];
          let dayData = dailyActivity.get(dateKey);
          if (!dayData) {
            dayData = {
              date: new Date(dateKey),
              value: 0,
              wordCount: 0,
              fileCount: 0
            };
            dailyActivity.set(dateKey, dayData);
          }
          dayData.wordCount += wordCount;
          dayData.fileCount++;
          dayData.value = dayData.wordCount;
        } catch {
        }
      }));
    }));
    const dailyActivities = Array.from(dailyActivity.values());
    dailyActivities.sort((a2, b) => a2.date.getTime() - b.date.getTime());
    this.data = dailyActivities;
    if (sourceAnalysisId) {
      _KnowledgeCalendarChart.calendarCacheBySourceId.set(sourceAnalysisId, this.data);
    }
    return this.data;
  }
  calculateWordCount(content) {
    const contentWithoutFrontmatter = content.replace(/^---[\s\S]*?---\n/m, "");
    const cleanContent = contentWithoutFrontmatter.replace(/!\[\[.*?\]\]/g, "").replace(/\[\[.*?\]\]/g, "").replace(/\[.*?\]\(.*?\)/g, "").replace(/```[\s\S]*?```/g, "").replace(/`.*?`/g, "").replace(/#{1,6}\s/g, "").replace(/[*_~`]/g, "").replace(/\n+/g, " ").trim();
    const words = cleanContent.split(/\s+/).filter((word) => word.length > 0);
    return words.length;
  }
  async render() {
    this.container.empty();
    if (this.data.length === 0) {
      await this.generateCalendarData();
    }
    this.createSummarySection();
    const chartContainer = this.container.createEl("div", { cls: "calendar-chart-container" });
    this.createCalendarChart(chartContainer);
  }
  createSummarySection() {
    const summaryContainer = this.container.createEl("div", { cls: "calendar-summary" });
    let totalNotes;
    let totalWords;
    let vaultDuration;
    if (this.summaryContext) {
      totalNotes = this.summaryContext.totalNotes;
      totalWords = this.summaryContext.totalWords;
      vaultDuration = `${this.summaryContext.vaultDurationDays.toLocaleString()} days`;
    } else {
      const allFiles = getIncludedMarkdownFiles(this.app);
      totalNotes = allFiles.length;
      totalWords = this.data.reduce((sum2, day) => sum2 + day.wordCount, 0);
      vaultDuration = "Unknown";
      if (allFiles.length > 0) {
        const creationDates = allFiles.map((file) => file.stat.ctime);
        const firstNoteDate = new Date(Math.min(...creationDates));
        const today = /* @__PURE__ */ new Date();
        const timeDiff = today.getTime() - firstNoteDate.getTime();
        const daysDiff = Math.ceil(timeDiff / (1e3 * 3600 * 24));
        vaultDuration = `${daysDiff.toLocaleString()} days`;
      }
    }
    const stats = summaryContainer.createEl("div", { cls: "calendar-summary-stats" });
    [
      { label: "Vault Duration", value: vaultDuration },
      { label: "Total Notes", value: totalNotes.toLocaleString() },
      { label: "Total Words", value: totalWords.toLocaleString() }
    ].forEach(({ label, value }) => {
      const stat = stats.createEl("div", { cls: "summary-stat" });
      stat.createEl("span", { cls: "stat-label", text: label });
      stat.createEl("span", { cls: "stat-value", text: value });
    });
  }
  createCalendarChart(container) {
    const cellSize = this.options.cellSize;
    const containerWidth = container.clientWidth || 800;
    const margin = {
      top: 30,
      right: 20,
      bottom: 0,
      left: 50
    };
    const contentWidth = containerWidth - margin.left - margin.right;
    const nonZeroValues = this.data.filter((d) => d.value > 0).map((d) => d.value);
    const minValue = nonZeroValues.length > 0 ? Math.min(...nonZeroValues) : 0;
    const maxValue = nonZeroValues.length > 0 ? Math.max(...nonZeroValues) : 1;
    const dataWithDates = this.data.filter((d) => d.value > 0);
    let startDate;
    let endDate;
    if (dataWithDates.length === 0) {
      const now2 = /* @__PURE__ */ new Date();
      startDate = new Date(now2.getFullYear(), 0, 1);
      endDate = new Date(now2.getFullYear(), 11, 31);
    } else {
      const allDates = dataWithDates.map((d) => d.date);
      const minDate = new Date(Math.min(...allDates.map((d) => d.getTime())));
      const maxDate = new Date(Math.max(...allDates.map((d) => d.getTime())));
      startDate = new Date(minDate.getFullYear(), 0, 1);
      endDate = new Date(maxDate.getFullYear(), 11, 31);
    }
    const startYear = startDate.getFullYear();
    const endYear = endDate.getFullYear();
    const years = [];
    for (let year = startYear; year <= endYear; year++) {
      years.push(year);
    }
    const maxWeeksInYear = 53;
    const optimalWeekWidth = cellSize + 2;
    const calendarWidth = Math.min(contentWidth, maxWeeksInYear * optimalWeekWidth);
    const calendarOffsetX = (contentWidth - calendarWidth) / 2;
    const yearHeight = cellSize * 7 + 40;
    const height = yearHeight * years.length + margin.top + margin.bottom;
    const dataMap = /* @__PURE__ */ new Map();
    this.data.forEach((d) => {
      const dateKey = d.date.toISOString().split("T")[0];
      dataMap.set(dateKey, d);
    });
    const svg = select_default2(container).append("svg").attr("width", containerWidth).attr("height", height).attr("class", "calendar-chart").style("font", "10px sans-serif");
    const g2 = svg.append("g").attr("transform", `translate(${margin.left + calendarOffsetX}, ${margin.top})`);
    years.forEach((year, yearIndex) => {
      const yearStartDate = new Date(year, 0, 1);
      const yearEndDate = new Date(year, 11, 31);
      const yearGroup = g2.append("g").attr("transform", `translate(0, ${yearIndex * yearHeight})`);
      const totalDays = Math.ceil((yearEndDate.getTime() - yearStartDate.getTime()) / (24 * 60 * 60 * 1e3));
      const totalWeeks = Math.ceil(totalDays / 7);
      const weekWidth = Math.min(optimalWeekWidth, calendarWidth / totalWeeks);
      yearGroup.append("text").attr("x", -5).attr("y", -10).attr("font-weight", "bold").attr("text-anchor", "end").style("fill", "var(--text-normal)").style("font-size", "14px").text(year);
      if (yearIndex === 0) {
        const dayLabels = ["M", "T", "W", "T", "F", "S", "S"];
        yearGroup.selectAll(".day-label").data(dayLabels).enter().append("text").attr("class", "day-label").attr("x", -5).attr("y", (_d, i) => (i + 0.5) * (cellSize + 1)).attr("dy", "0.31em").attr("text-anchor", "end").style("fill", "var(--text-muted)").style("font-size", "9px").text((d) => d);
      }
      const yearDates = [];
      for (let d = new Date(yearStartDate); d <= yearEndDate; d.setDate(d.getDate() + 1)) {
        yearDates.push(new Date(d));
      }
      const getWeekNumber = (date) => {
        const yearStart = new Date(date.getFullYear(), 0, 1);
        const firstMonday = new Date(yearStart);
        const yearStartDay = getMondayFirstDay(yearStart);
        if (yearStartDay !== 0) {
          firstMonday.setDate(yearStart.getDate() - yearStartDay);
        }
        const daysDiff = Math.floor((date.getTime() - firstMonday.getTime()) / (24 * 60 * 60 * 1e3));
        return Math.floor(daysDiff / 7);
      };
      const getMondayFirstDay = (date) => {
        const jsDay = date.getDay();
        return jsDay === 0 ? 6 : jsDay - 1;
      };
      yearGroup.selectAll(".day-cell").data(yearDates).enter().append("rect").attr("class", "day-cell").attr("width", cellSize).attr("height", cellSize).attr("x", (d) => getWeekNumber(d) * weekWidth).attr("y", (d) => getMondayFirstDay(d) * (cellSize + 1)).attr("fill", (d) => {
        const dateKey = d.toISOString().split("T")[0];
        const dayData = dataMap.get(dateKey);
        return dayData ? this.getObsidianAccentColor(dayData.value, minValue, maxValue) : "var(--background-modifier-border)";
      }).attr("rx", 2).attr("ry", 2).style("cursor", "pointer").on("mouseover", (event, d) => {
        const dateKey = d.toISOString().split("T")[0];
        const dayData = dataMap.get(dateKey);
        this.showTooltip(event, d, dayData);
      }).on("mouseout", () => {
        this.hideTooltip();
      });
      const currentDate = /* @__PURE__ */ new Date();
      if (currentDate.getFullYear() === year) {
        const currentWeekNum = getWeekNumber(currentDate);
        const lineX = currentWeekNum * weekWidth + weekWidth / 2;
        yearGroup.append("line").attr("class", "current-week-indicator").attr("x1", lineX).attr("y1", -15).attr("x2", lineX).attr("y2", cellSize * 7 + 15).attr("stroke", "var(--text-accent)").attr("stroke-width", 2).attr("stroke-dasharray", "4,3").attr("opacity", 0.7).style("pointer-events", "none");
      }
      const months = [
        "Jan",
        "Feb",
        "Mar",
        "Apr",
        "May",
        "Jun",
        "Jul",
        "Aug",
        "Sep",
        "Oct",
        "Nov",
        "Dec"
      ];
      months.forEach((month, i) => {
        const monthDate = new Date(year, i, 1);
        const weekNum = getWeekNumber(monthDate);
        if (weekNum * weekWidth < calendarWidth - 30) {
          yearGroup.append("text").attr("x", weekNum * weekWidth + 2).attr("y", -5).style("fill", "var(--text-muted)").style("font-size", "10px").text(month);
        }
      });
    });
  }
  getObsidianAccentColor(value, minValue, maxValue) {
    if (value === 0) {
      return "var(--background-modifier-border)";
    }
    const baseColor = "var(--background-secondary-alt)";
    if (maxValue === minValue) {
      return "var(--text-accent)";
    }
    const normalizedValue = (value - minValue) / (maxValue - minValue);
    const accentPercentage = 30 + normalizedValue * 70;
    return `color-mix(in srgb, var(--text-accent) ${Math.round(accentPercentage)}%, ${baseColor})`;
  }
  showTooltip(event, date, dayData) {
    this.hideTooltip();
    const doc = this.container.ownerDocument;
    const tooltip = doc.createElement("div");
    tooltip.className = "calendar-tooltip";
    const dateStr = date.toLocaleDateString("en-US", {
      weekday: "short",
      year: "numeric",
      month: "short",
      day: "numeric"
    });
    const wordCount = dayData?.wordCount || 0;
    const fileCount = dayData?.fileCount || 0;
    tooltip.createEl("div", { cls: "tooltip-date", text: dateStr });
    const stats = tooltip.createEl("div", { cls: "tooltip-stats" });
    stats.createEl("div", { text: `${wordCount.toLocaleString()} words written` });
    stats.createEl("div", { text: fileCount > 0 ? `${fileCount} file${fileCount !== 1 ? "s" : ""} modified` : "No activity" });
    doc.body.appendChild(tooltip);
    const rect = tooltip.getBoundingClientRect();
    tooltip.style.left = event.pageX - rect.width / 2 + "px";
    tooltip.style.top = event.pageY - rect.height - 10 + "px";
  }
  hideTooltip() {
    const tooltip = this.container.ownerDocument.querySelector(".calendar-tooltip");
    if (tooltip) {
      tooltip.remove();
    }
  }
  async refresh() {
    _KnowledgeCalendarChart.calendarCacheBySourceId.clear();
    this.data = [];
    this.summaryContext = void 0;
    await this.render();
  }
};
_KnowledgeCalendarChart.calendarCacheBySourceId = /* @__PURE__ */ new Map();
var KnowledgeCalendarChart = _KnowledgeCalendarChart;

// src/components/scatter-chart/ConnectivityScatterChart.ts
var import_obsidian = require("obsidian");
var ConnectivityScatterChart = class {
  constructor(app, container, options = {}) {
    this.svg = null;
    this.tooltip = null;
    this.data = [];
    this.app = app;
    this.container = container;
    this.options = {
      width: 600,
      height: 400,
      margin: { top: 40, right: 40, bottom: 120, left: 60 },
      // Increased bottom margin for explanation text with spacing
      mode: "links",
      ...options
    };
    this.currentMode = this.options.mode || "links";
  }
  render() {
    this.container.empty();
    if (this.currentMode === "links") {
      this.computeLinkData();
    } else {
      this.computeCentralityData();
    }
    if (this.data.length === 0) {
      const isCentralityMode2 = this.currentMode === "centrality";
      const message = isCentralityMode2 ? "No centrality data available. Please generate vault analysis first to view centrality metrics." : "No connectivity data available for scatter plot analysis.";
      this.container.createEl("p", {
        text: message,
        cls: "scatter-chart-no-data"
      });
      return Promise.resolve();
    }
    const { width, height, margin } = this.options;
    const innerWidth = width - margin.left - margin.right;
    const innerHeight = height - margin.top - margin.bottom;
    const svgSelection = select_default2(this.container).append("svg");
    this.svg = svgSelection.attr("width", width).attr("height", height).attr("viewBox", `0 0 ${width} ${height}`).attr("style", "max-width: 100%; height: auto; display: block; margin: 0 auto;");
    const g2 = this.svg.append("g").attr("transform", `translate(${margin.left},${margin.top})`);
    const xValues = this.data.map((d) => d.xValue);
    const yValues = this.data.map((d) => d.yValue);
    const maxX = Math.max(...xValues, 0);
    const maxY = Math.max(...yValues, 0);
    const xDomainMax = maxX === 0 ? 1 : maxX * 1.1;
    const yDomainMax = maxY === 0 ? 1 : maxY * 1.1;
    const xScale = linear2().domain([0, xDomainMax]).nice().range([0, innerWidth]);
    const yScale = linear2().domain([0, yDomainMax]).nice().range([innerHeight, 0]);
    const dotColor = "var(--text-accent)";
    const dots = g2.append("g").attr("class", "scatter-dots");
    dots.selectAll(".scatter-dot").data(this.data).enter().append("circle").attr("class", "scatter-dot").attr("cx", (d) => xScale(d.xValue)).attr("cy", (d) => yScale(d.yValue)).attr("r", 4).attr("fill", dotColor).attr("stroke", "var(--background-primary)").attr("stroke-width", 1).style("opacity", 0.7).on("mouseover", (event, d) => {
      select_default2(event.currentTarget).attr("r", 6).style("opacity", 1);
      this.showTooltip(event, d);
    }).on("mousemove", (event) => {
      this.updateTooltipPosition(event);
    }).on("mouseout", (event) => {
      select_default2(event.currentTarget).attr("r", 4).style("opacity", 0.7);
      this.hideTooltip();
    });
    const isCentralityMode = this.currentMode === "centrality";
    const xAxisLabel = isCentralityMode ? "Betweenness" : "Outbound Links";
    const yAxisLabel = isCentralityMode ? "Eigenvector" : "Inbound Links";
    const tickFormat2 = (d, index2) => {
      const value = typeof d === "number" ? d : d.valueOf();
      if (isCentralityMode && value < 0.01 && value > 0) {
        return value.toExponential(1);
      }
      if (value < 1 && value > 0) {
        return value.toFixed(3);
      }
      if (value >= 1) {
        return Math.round(value).toString();
      }
      return value.toString();
    };
    const xAxis = axisBottom(xScale).ticks(isCentralityMode ? 8 : 10).tickFormat(tickFormat2);
    const xAxisGroup = g2.append("g").attr("transform", `translate(0,${innerHeight})`);
    xAxisGroup.call(xAxis);
    xAxisGroup.selectAll(".tick text").attr("fill", "var(--text-muted)").style("font-size", "11px");
    xAxisGroup.append("text").attr("x", innerWidth / 2).attr("y", 45).attr("fill", "var(--text-normal)").style("text-anchor", "middle").style("font-size", "12px").text(xAxisLabel);
    const explanationGroup = xAxisGroup.append("g").attr("transform", `translate(${innerWidth / 2}, 80)`);
    let lineY = 0;
    const lineHeight = 14;
    const fontSize = "11px";
    if (isCentralityMode) {
      explanationGroup.append("text").attr("x", 0).attr("y", lineY).attr("fill", "var(--text-muted)").style("text-anchor", "middle").style("font-size", fontSize).style("font-weight", "500").text("Purpose: Compare bridge role vs influence to identify note structural types.");
      lineY += lineHeight;
      explanationGroup.append("text").attr("x", 0).attr("y", lineY).attr("fill", "var(--text-muted)").style("text-anchor", "middle").style("font-size", fontSize).text("High Betweenness + Low Eigenvector = Bridges; Low Betweenness + High Eigenvector = Influential;");
      lineY += lineHeight;
      explanationGroup.append("text").attr("x", 0).attr("y", lineY).attr("fill", "var(--text-muted)").style("text-anchor", "middle").style("font-size", fontSize).text("High Both = Critical Hubs; Low Both = Peripheral Notes.");
    } else {
      explanationGroup.append("text").attr("x", 0).attr("y", lineY).attr("fill", "var(--text-muted)").style("text-anchor", "middle").style("font-size", fontSize).style("font-weight", "500").text("Purpose: Reveal connectivity imbalances to identify integration opportunities.");
      lineY += lineHeight;
      explanationGroup.append("text").attr("x", 0).attr("y", lineY).attr("fill", "var(--text-muted)").style("text-anchor", "middle").style("font-size", fontSize).text("High Outbound + Low Inbound = Silos; Low Outbound + High Inbound = Hub Candidates;");
      lineY += lineHeight;
      explanationGroup.append("text").attr("x", 0).attr("y", lineY).attr("fill", "var(--text-muted)").style("text-anchor", "middle").style("font-size", fontSize).text("High Both = Well Connected; Low Both = Orphan Notes.");
    }
    const yAxis = axisLeft(yScale).ticks(isCentralityMode ? 8 : 10).tickFormat(tickFormat2);
    const yAxisGroup = g2.append("g");
    yAxisGroup.call(yAxis);
    yAxisGroup.selectAll(".tick text").attr("fill", "var(--text-muted)").style("font-size", "11px");
    yAxisGroup.append("text").attr("transform", "rotate(-90)").attr("y", -45).attr("x", -innerHeight / 2).attr("fill", "var(--text-normal)").style("text-anchor", "middle").style("font-size", "12px").text(yAxisLabel);
    g2.selectAll(".domain, .tick line").attr("stroke", "var(--background-modifier-border)");
    return Promise.resolve();
  }
  computeLinkData() {
    const allFiles = getIncludedMarkdownFiles(this.app);
    const dataPoints = [];
    const inboundLinkCounts = /* @__PURE__ */ new Map();
    for (const file of allFiles) {
      try {
        const cache = this.app.metadataCache.getFileCache(file);
        if (!cache) continue;
        const allLinks = [
          ...cache.links || [],
          ...cache.embeds || [],
          ...cache.frontmatterLinks || []
        ];
        for (const link of allLinks) {
          const resolvedFile = this.app.metadataCache.getFirstLinkpathDest(link.link, file.path);
          if (resolvedFile) {
            const currentCount = inboundLinkCounts.get(resolvedFile.path) || 0;
            inboundLinkCounts.set(resolvedFile.path, currentCount + 1);
          }
        }
      } catch {
      }
    }
    for (const file of allFiles) {
      try {
        const cache = this.app.metadataCache.getFileCache(file);
        const outboundLinks = (cache?.links?.length || 0) + (cache?.embeds?.length || 0) + (cache?.frontmatterLinks?.length || 0);
        const inboundLinks = inboundLinkCounts.get(file.path) || 0;
        if (outboundLinks > 0 || inboundLinks > 0) {
          const title = file.basename || file.name.replace(".md", "");
          dataPoints.push({
            path: file.path,
            title,
            xValue: outboundLinks,
            yValue: inboundLinks,
            outboundLinks,
            inboundLinks
          });
        }
      } catch {
      }
    }
    this.data = dataPoints;
  }
  computeCentralityData() {
    const dataPoints = [];
    if (!this.options.analysisData || !this.options.analysisData.results) {
      this.data = [];
      return;
    }
    for (const result of this.options.analysisData.results) {
      const betweenness = result.graphMetrics?.betweennessCentrality ?? 0;
      const eigenvector = result.graphMetrics?.eigenvectorCentrality ?? 0;
      if (betweenness > 0 || eigenvector > 0) {
        dataPoints.push({
          path: result.path,
          title: result.title,
          xValue: betweenness,
          yValue: eigenvector,
          betweennessCentrality: betweenness,
          eigenvectorCentrality: eigenvector
        });
      }
    }
    this.data = dataPoints;
  }
  showTooltip(event, data) {
    this.hideTooltip();
    const tooltip = this.container.createEl("div", { cls: "scatter-tooltip" });
    tooltip.remove();
    this.container.ownerDocument.body.appendChild(tooltip);
    tooltip.createEl("div", { text: data.title, cls: "scatter-tooltip-title" });
    const isCentralityMode = this.currentMode === "centrality";
    if (isCentralityMode) {
      const betweenness = data.betweennessCentrality ?? 0;
      const eigenvector = data.eigenvectorCentrality ?? 0;
      const formatValue = (val) => {
        if (val < 0.01 && val > 0) return val.toExponential(3);
        return val.toFixed(4);
      };
      tooltip.createEl("div", { text: `Betweenness: ${formatValue(betweenness)}`, cls: "scatter-tooltip-muted" });
      tooltip.createEl("div", { text: `Eigenvector: ${formatValue(eigenvector)}`, cls: "scatter-tooltip-muted" });
    } else {
      const outbound = data.outboundLinks ?? 0;
      const inbound = data.inboundLinks ?? 0;
      tooltip.createEl("div", { text: `Outbound: ${outbound} link${outbound !== 1 ? "s" : ""}`, cls: "scatter-tooltip-muted" });
      tooltip.createEl("div", { text: `Inbound: ${inbound} link${inbound !== 1 ? "s" : ""}`, cls: "scatter-tooltip-muted" });
    }
    this.tooltip = tooltip;
    this.updateTooltipPosition(event);
  }
  updateTooltipPosition(event) {
    if (!this.tooltip) return;
    const rect = this.tooltip.getBoundingClientRect();
    const x3 = event.pageX - rect.width / 2;
    const y3 = event.pageY - rect.height - 10;
    this.tooltip.style.left = `${x3}px`;
    this.tooltip.style.top = `${y3}px`;
  }
  hideTooltip() {
    if (this.tooltip) {
      this.tooltip.remove();
      this.tooltip = null;
    }
  }
  openNote(path2) {
    try {
      const file = this.app.vault.getAbstractFileByPath(path2);
      if (file instanceof import_obsidian.TFile) {
        if (this.options.modal) {
          this.options.modal.close();
        }
        this.container.ownerDocument.defaultView.setTimeout(() => {
          void this.app.workspace.openLinkText(path2, "", false);
        }, 100);
      }
    } catch {
    }
  }
  async setMode(mode) {
    this.currentMode = mode;
    await this.render();
  }
  destroy() {
    this.hideTooltip();
    if (this.svg) {
      this.svg.remove();
      this.svg = null;
    }
    this.container.empty();
  }
};

// src/components/connection-subgraph/ConnectionSubGraph.ts
var import_obsidian4 = require("obsidian");

// src/utils/NoteResolver.ts
var import_obsidian2 = require("obsidian");
var NoteResolver = class {
  /**
   * Resolve any raw note identifier to a valid vault file path.
   * Tries: exact path -> path + .md -> basename match.
   * Returns empty string if no match found.
   */
  static resolveToPath(app, rawId) {
    const file = this.resolveToFile(app, rawId);
    return file ? file.path : "";
  }
  /**
   * Resolve any raw note identifier to a TFile instance.
   * Returns null if no match found.
   */
  static resolveToFile(app, rawId, searchFiles) {
    if (!rawId?.trim()) return null;
    const exact = app.vault.getAbstractFileByPath(rawId);
    if (exact instanceof import_obsidian2.TFile) return exact;
    const withExt = rawId.endsWith(".md") ? rawId : rawId + ".md";
    const withExtFile = app.vault.getAbstractFileByPath(withExt);
    if (withExtFile instanceof import_obsidian2.TFile) return withExtFile;
    const cleanedId = rawId.split("/").pop()?.replace(/\.md$/i, "") || rawId;
    const candidates = searchFiles ?? app.vault.getMarkdownFiles();
    const match = candidates.find(
      (f) => f.basename.toLowerCase() === cleanedId.toLowerCase()
    );
    return match ?? null;
  }
  /**
   * Resolve any raw note identifier to a display title (basename without .md).
   * Always returns a string (falls back to cleaned-up rawId).
   */
  static resolveToTitle(app, rawId) {
    const file = this.resolveToFile(app, rawId);
    if (file) return file.basename;
    const fallback = rawId.split("/").pop()?.replace(/\.md$/i, "") || rawId;
    return fallback;
  }
};

// src/ai/visualization/KnowledgeActionsManager.ts
var KnowledgeActionsManager = class _KnowledgeActionsManager {
  /**
   * Compute hybrid urgency-scored review candidates by combining:
   * - Rule-based signals: centrality (hub/bridge/authority importance) + staleness (time since modified)
   * - AI signals: maintenance priority, reason, and action from AI analysis
   */
  static computeReviewCandidates(maintenance, analysisResults, limit = 9) {
    const CENTRALITY_WEIGHT = 0.4;
    const STALENESS_WEIGHT = 0.3;
    const AI_PRIORITY_WEIGHT = 0.3;
    const resultsByPath = /* @__PURE__ */ new Map();
    for (const r of analysisResults) {
      resultsByPath.set(r.path, r);
      resultsByPath.set(r.id, r);
    }
    const aiByNoteId = /* @__PURE__ */ new Map();
    for (const m2 of maintenance) {
      aiByNoteId.set(m2.noteId, m2);
    }
    const candidatePaths = /* @__PURE__ */ new Set();
    for (const m2 of maintenance) {
      candidatePaths.add(m2.noteId);
    }
    const centralityScored = analysisResults.filter((r) => r.graphMetrics).map((r) => ({
      path: r.path,
      maxCentrality: Math.max(
        r.graphMetrics?.betweennessCentrality ?? 0,
        r.graphMetrics?.eigenvectorCentrality ?? 0,
        r.graphMetrics?.degreeCentrality ?? 0
      )
    })).sort((a2, b) => b.maxCentrality - a2.maxCentrality);
    for (const item of centralityScored.slice(0, 20)) {
      candidatePaths.add(item.path);
    }
    const now2 = Date.now();
    let maxCentrality = 0;
    let maxStalenessMs = 1;
    for (const path2 of candidatePaths) {
      const result = resultsByPath.get(path2);
      if (result?.graphMetrics) {
        const mc = Math.max(
          result.graphMetrics.betweennessCentrality ?? 0,
          result.graphMetrics.eigenvectorCentrality ?? 0,
          result.graphMetrics.degreeCentrality ?? 0
        );
        if (mc > maxCentrality) maxCentrality = mc;
      }
      if (result?.modified) {
        const age = now2 - new Date(result.modified).getTime();
        if (age > maxStalenessMs) maxStalenessMs = age;
      }
    }
    if (maxCentrality === 0) maxCentrality = 1;
    const candidates = [];
    for (const path2 of candidatePaths) {
      const result = resultsByPath.get(path2);
      const aiAction = aiByNoteId.get(path2);
      const betweenness = result?.graphMetrics?.betweennessCentrality ?? 0;
      const eigenvector = result?.graphMetrics?.eigenvectorCentrality ?? 0;
      const degree = result?.graphMetrics?.degreeCentrality ?? 0;
      const rawCentrality = Math.max(betweenness, eigenvector, degree);
      const normalizedCentrality = rawCentrality / maxCentrality;
      let centralityRole = "normal";
      if (betweenness > 0 && betweenness >= eigenvector && betweenness >= degree) {
        centralityRole = "bridge";
      } else if (eigenvector > 0 && eigenvector >= betweenness && eigenvector >= degree) {
        centralityRole = "authority";
      } else if (degree > 0) {
        centralityRole = "hub";
      }
      const modified = result?.modified ? new Date(result.modified).getTime() : now2;
      const stalenessMs = now2 - modified;
      const normalizedStaleness = stalenessMs / maxStalenessMs;
      let aiPriorityScore = 0;
      if (aiAction) {
        aiPriorityScore = aiAction.priority === "high" ? 1 : aiAction.priority === "medium" ? 0.6 : 0.3;
      }
      const urgencyScore = CENTRALITY_WEIGHT * normalizedCentrality + STALENESS_WEIGHT * normalizedStaleness + AI_PRIORITY_WEIGHT * aiPriorityScore;
      const title = aiAction?.title || result?.title || path2.split("/").pop()?.replace(".md", "") || path2;
      const reason = aiAction?.reason || _KnowledgeActionsManager.generateRuleBasedReason(
        centralityRole,
        stalenessMs,
        normalizedCentrality
      );
      const priority = aiAction?.priority || (urgencyScore > 0.65 ? "high" : urgencyScore > 0.35 ? "medium" : "low");
      const action = aiAction?.action || "";
      candidates.push({
        noteId: path2,
        title,
        path: result?.path || path2,
        reason,
        priority,
        action,
        lastModified: result?.modified || "",
        urgencyScore,
        centralityRole,
        centralityScore: rawCentrality,
        fromAI: !!aiAction
      });
    }
    candidates.sort((a2, b) => b.urgencyScore - a2.urgencyScore);
    return candidates.slice(0, limit);
  }
  static generateRuleBasedReason(role, stalenessMs, normalizedCentrality) {
    const days = Math.floor(stalenessMs / (1e3 * 60 * 60 * 24));
    const roleLabel = role === "bridge" ? "a key bridge between topics" : role === "authority" ? "a highly-referenced authority note" : role === "hub" ? "a well-connected hub note" : "a note in your vault";
    if (days > 180 && normalizedCentrality > 0.5) {
      return `This is ${roleLabel} that hasn't been updated in ${days} days. Its high importance makes it a priority for review.`;
    }
    if (days > 180) {
      return `This note hasn't been modified in ${days} days and may need a review to stay current.`;
    }
    if (normalizedCentrality > 0.5) {
      return `This is ${roleLabel} with high centrality. Consider reviewing to ensure it remains accurate.`;
    }
    return `This is ${roleLabel} that could benefit from a review.`;
  }
  /**
   * Write [[link]] connections into source notes for the given connection suggestions.
   * Appends a "Related Notes" section at the end of the source file (or after frontmatter).
   */
  static async writeConnectionsToNotes(app, connections) {
    let written = 0;
    let failed = 0;
    const bySource = /* @__PURE__ */ new Map();
    for (const conn of connections) {
      const list = bySource.get(conn.sourceId) || [];
      list.push(conn);
      bySource.set(conn.sourceId, list);
    }
    for (const [sourceId, conns] of bySource) {
      try {
        const file = NoteResolver.resolveToFile(app, sourceId);
        if (!file) {
          failed += conns.length;
          continue;
        }
        const linkLines = conns.map((c4) => {
          const targetName = NoteResolver.resolveToTitle(app, c4.targetId);
          return `- [[${targetName}]]`;
        });
        const newSection = `

## Related Notes
${linkLines.join("\n")}
`;
        await app.vault.process(file, (content) => {
          const relatedNotesRegex = /\n## Related Notes\n/;
          if (relatedNotesRegex.test(content)) {
            const insertPos = content.search(/\n## Related Notes\n/);
            const afterSection = content.indexOf("\n## ", insertPos + 1);
            if (afterSection > insertPos + 20) {
              const existingSection = content.slice(insertPos, afterSection);
              return content.slice(0, insertPos) + existingSection + linkLines.join("\n") + "\n" + content.slice(afterSection);
            }
            return content + "\n" + linkLines.join("\n") + "\n";
          }
          return content + newSection;
        });
        written += conns.length;
      } catch {
        failed += conns.length;
      }
    }
    return { written, failed };
  }
};

// src/i18n/index.ts
var import_obsidian3 = require("obsidian");

// src/i18n/locales/en.json
var en_default = {
  settings: {
    excludeHeading: "Exclude notes from analysis",
    excludeFolders: {
      name: "Exclude folders",
      desc: 'Use folder paths like "archive", "templates", "private/personal"',
      placeholder: "Archive,templates,private/personal"
    },
    excludeTags: {
      name: "Exclude tags",
      desc: 'Use tag names without # like "private", "draft", "archive"',
      placeholder: "Private,draft,archive"
    },
    llmHeading: "LLM model configuration",
    geminiApiKey: {
      name: "Gemini API key",
      descPrefix: "Your Google Gemini API key. ",
      getKeyLink: "Get an API key",
      placeholder: "Enter your Gemini API key",
      showTooltip: "Show API key",
      hideTooltip: "Hide API key"
    },
    networkDisclosure: {
      name: "Network use (AI analysis)",
      desc: "When you run Vault Analysis or generate tab insights, the plugin sends note text and analysis prompts to Google's Gemini API (generativelanguage.googleapis.com) using your API key. Nothing is sent on plugin load. Graph metrics and caches stay on your device. See the README Privacy & network section."
    },
    languageHeading: "Language",
    uiLanguage: {
      name: "UI language",
      desc: "Language for plugin menus, settings, and labels.",
      obsidian: "Same as Obsidian",
      en: "English",
      zhHans: "\u7B80\u4F53\u4E2D\u6587"
    },
    aiResponseLanguage: {
      name: "AI response language",
      desc: "Language for all AI-generated text (note summaries, structure, evolution, and actions). Auto picks English or \u7B80\u4F53\u4E2D\u6587 from your vault or Obsidian language.",
      auto: "Auto detect",
      en: "English",
      zhHans: "\u7B80\u4F53\u4E2D\u6587"
    },
    stats: {
      excludedTotal: "Excluded notes: {{total}}{{breakdown}}",
      excludedByFolder: "{{count}} by folder",
      excludedByTag: "{{count}} by tag",
      includedTotal: "Notes included in analysis: {{included}}/{{total}}",
      showExcluded: "Show excluded files",
      error: "Error calculating exclusion statistics"
    },
    excludedModal: {
      title: "Excluded files",
      empty: "No files are currently excluded."
    }
  },
  commands: {
    showExclusionStats: "Show exclusion statistics",
    generateVaultAnalysis: "Generate AI analysis for entire vault",
    viewVaultAnalysis: "View vault analysis results"
  },
  ribbon: {
    graphView: "Graph analysis view"
  },
  errors: {
    quotaExhausted: "Free-tier daily limit reached. Retry tomorrow.",
    rateLimit: "API rate limit exceeded. Please try again later."
  },
  notices: {
    vaultAnalysisNotInitialized: "Vault analysis manager not initialized",
    wasmInitializing: "Initializing graph analysis...",
    wasmInitFailed: "Failed to initialize Graph Analysis WASM module: {{message}}",
    exclusionUtilsNotInitialized: "Exclusion utils not initialized",
    exclusionStatsConsole: "Check console for detailed exclusion statistics. {{count}} files excluded.",
    exclusionStatsError: "Error getting exclusion statistics",
    analyzeCentralityFailed: "Failed to analyze {{algorithm}} centrality: {{message}}",
    graphLoadError: "Error loading graph data: {{message}}",
    graphReloadError: "Error reloading graph data: {{message}}",
    centralityFailed: "Failed to calculate {{type}} centrality: {{message}}",
    configureApiKey: "Please configure your Gemini API key in settings to use vault analysis.",
    noFilesAfterExclusion: "No files found for analysis after applying exclusion rules.",
    allFilesUpToDate: "All files are up to date. No changes detected. ({{count}} files unchanged)",
    vaultAnalysisProgress: "Analyzing vault: {{current}}/{{total}} files...",
    calculatingGraphMetrics: "Calculating graph metrics...",
    enhancingWithMetrics: "Enhancing vault analysis with graph metrics...",
    enhancedWithMetrics: "Vault analysis enhanced with graph metrics!",
    noAnalysisForEnhance: "No existing vault analysis found. Generate analysis first.",
    enhanceFailed: "Failed to enhance: {{message}}",
    vaultAnalysisComplete: "Vault analysis complete! {{generated}} generated, {{updated}} updated.",
    vaultAnalysisFailed: "Failed to generate vault analysis: {{message}}",
    enhanceMetricsPrompt: "Your vault analysis exists but lacks graph metrics. Click to enhance it with centrality scores.",
    enhanceMetricsButton: "Enhance with graph metrics",
    loadVaultAnalysisFailed: "Failed to load vault analysis results",
    vaultAnalysisInProgress: "Advanced analysis is still running. Results will open automatically when finished.",
    tabAnalysisComplete: "{{tab}} Analysis completed successfully!",
    reopenModalFailed: "Failed to reopen analysis modal",
    updatingTabAnalysis: "Updating {{tab}} Analysis... (est. 1\u20132 min)",
    generatingTabAnalysis: "Generating {{tab}} Analysis... (est. 1\u20132 min)",
    tabAnalysisSuccess: "{{tab}} analysis generated successfully!",
    tabAnalysisFailed: "Failed to generate AI analysis: {{message}}",
    noConnectionsRemaining: "No connections remaining to add.",
    connectionsWritten: "Successfully added {{count}} connection to your notes.",
    connectionsWritten_other: "Successfully added {{count}} connections to your notes.",
    connectionsWriteFailed: "Failed to write {{count}} connection.",
    connectionsWriteFailed_other: "Failed to write {{count}} connections.",
    connectionsWriteError: "Failed to write connections. Check console for details.",
    preparingFiles: "Preparing files for analysis...",
    vaultAnalysisStarting: "Starting vault analysis for {{count}} files. Est. ~{{minutes}} min",
    vaultAnalysisUpdating: "Updating analysis: {{changed}} changed, {{new}} new, {{unchanged}} unchanged (processing {{processing}} files). Est. ~{{minutes}} min",
    vaultCompleteQuota: "Saved partial results ({{success}}/{{total}} files). Free tier limit: ~500 notes per day. Continue the remaining {{remaining}} notes after {{retryTime}} by running analysis again.",
    vaultCompleteIncrementalOk: "Analysis updated successfully! Processed {{success}} changed/new files ({{changed}} changed, {{new}} new), kept {{unchanged}} unchanged, removed {{deleted}} deleted.",
    vaultCompleteIncrementalWarn: "Analysis update completed with some issues. Processed {{success}} files successfully, {{failed}} failed, kept {{unchanged}} unchanged, removed {{deleted}} deleted.",
    vaultCompleteFullOk: "Vault analysis with graph metrics completed successfully! Processed {{success}} files. Results saved to plugin data folder",
    vaultCompleteFullWarn: "Vault analysis with graph metrics completed with some issues. Processed {{success}} files successfully, {{failed}} failed. Results saved to plugin data folder",
    enhanceAnalysisFailed: "Failed to enhance analysis: {{message}}"
  },
  graph: {
    loading: "Loading graph data...",
    display: "Display",
    labels: "Labels",
    arrows: "Arrows",
    type: "Type",
    scale: "Scale",
    steps: "Steps",
    reverse: "Reverse",
    on: "on",
    off: "off",
    centralityTitle: "{{type}} Centrality",
    betweennessDesc: "Measures how often a node acts as a bridge along the shortest path between two other nodes. Higher values indicate more important bridge nodes.",
    closenessDesc: "Measures how close a node is to all other nodes in the network. Higher values indicate nodes that can quickly reach or communicate with other nodes.",
    eigenvectorDesc: "Measures node importance based on the importance of its neighbors. Higher values indicate nodes connected to other important nodes.",
    tooltip: {
      created: "Created: ",
      modified: "Modified: ",
      size: "Size: ",
      tags: "Tags: ",
      openNote: "Open note",
      notePreview: "Note preview",
      previewFailed: "Unable to load note preview.",
      noteNotFound: "Note not found in vault. It may have been renamed or deleted.",
      noFilePath: "No file path associated with this node."
    }
  },
  vaultAnalysis: {
    buttonTitle: "Vault Analysis",
    buttonDesc: "AI-powered analysis of your entire vault to extract summaries, keywords, knowledge domains, and graph centrality metrics. Shift+click to force refresh graph metrics.",
    summary: "Analysis summary",
    searchFilter: "Search & filter",
    results: "Analysis results",
    noSearchResults: "No results found matching your search.",
    previous: "Previous",
    next: "Next",
    noAnalysisYet: "No vault analysis has been generated yet",
    generatePrompt: "Click the button below to analyze your entire vault and extract summaries, keywords, and knowledge domains from all notes.",
    domainDistribution: "Knowledge domain distribution",
    networkAnalysis: "Knowledge network analysis",
    knowledgeGaps: "Knowledge gaps",
    identifiedGaps: "Identified knowledge gaps",
    structureEmptyTitle: "Knowledge structure analysis",
    structureEmptyDesc: "Generate AI-powered analysis to unlock advanced knowledge structure insights.",
    structureFeatureSunburst: "Interactive sunburst chart \u2014 explore hierarchical knowledge domains",
    structureFeatureNetwork: "Knowledge network analysis \u2014 identify bridge notes, foundations, and authorities",
    structureFeatureGaps: "Knowledge gaps discovery \u2014 find underexplored areas in your vault",
    structureFeatureDistribution: "Domain distribution \u2014 see how your knowledge is organized across fields",
    actions: "Actions",
    processing: "Analysis is processing...",
    updateAnalysis: "Update analysis",
    generateAnalysis: "Generate analysis",
    privacyNote1: "This analysis uses Google Gemini AI to extract insights from your vault. We only send note summaries and metadata (keywords, domains, graph metrics) to the AI\u2014never full note content. This protects your privacy and significantly reduces token usage.",
    privacyNote2: "Before AI analysis, we use deterministic methods (graph theory, statistical analysis, kde distributions) to preprocess your vault data, ensuring accurate and efficient insights.",
    loadingTitle: "Generating AI analysis",
    estimatedTime: "Estimated time: ",
    cachedNote: "Results will be cached for future use.",
    errorTitle: "Error generating AI analysis",
    conclusion: "Conclusion",
    generateVaultFirst: "Please generate vault analysis first to access this feature.",
    networkMetrics: "Network metrics analysis",
    inboundOutbound: "Inbound vs outbound links",
    betweennessEigenvector: "Betweenness vs eigenvector",
    notesNeedingReview: "Notes needing review",
    suggestedConnections: "Suggested connections",
    evolutionEmptyTitle: "Knowledge evolution analysis",
    evolutionEmptyDesc: "Knowledge evolution analysis requires AI-powered vault analysis to be completed first.",
    developmentTimeline: "Knowledge development timeline",
    tabSemantic: "Semantic analysis",
    tabStructure: "Knowledge structure",
    tabEvolution: "Knowledge evolution",
    tabActions: "Recommended actions",
    tabDisabledTitle: "Run semantic analysis first",
    sectionTopicPatterns: "Topic introduction patterns",
    sectionFocusShifts: "Focus shift analysis",
    placeholderTimeline: "Generate analysis to summarize key phases and milestones in how your vault developed over time.",
    placeholderTopic: "Generate analysis to highlight when new topics and knowledge domains first appeared in your vault.",
    placeholderFocus: "Generate analysis to compare recent focus areas with earlier periods and identify notable shifts.",
    evolutionFeatureTimeline: "Knowledge development timeline \u2014 track how your understanding evolved",
    evolutionFeatureTopic: "Topic introduction patterns \u2014 see when different subjects entered your system",
    evolutionFeatureFocus: "Focus shift analysis \u2014 compare current interests vs historical patterns",
    focusShiftStats: "{{newCount}} new areas, {{reducedCount}} reduced",
    loadingIncludesTab: "This includes {{description}}.",
    loadingIncludesAll: "This includes knowledge structure, evolution, and recommendations.",
    tabDisplayStructure: "Knowledge structure",
    tabDisplayEvolution: "Knowledge evolution",
    tabDisplayActions: "Recommended actions",
    tabDisplayDefault: "Knowledge",
    tabDescStructure: "domain classification, hierarchical structure, and network analysis",
    tabDescEvolution: "timeline analysis, topic patterns, and focus shifts",
    tabDescActions: "maintenance tasks, connection opportunities, and learning paths",
    tabDescDefault: "comprehensive knowledge analysis",
    errorFailed: "Failed to generate analysis: {{message}}",
    aboutTitle: "About vault analysis",
    aboutIntro: "Vault analysis uses AI to analyze your entire Obsidian vault and provides:",
    requirements: "Requirements",
    requirementsApiKey: "Google Gemini API key (configured in plugin settings)",
    requirementsInternet: "Internet connection for AI processing",
    exclusions: "Exclusions",
    exclusionsDesc: "The analysis respects your exclusion settings for folders and tags, ensuring only relevant notes are processed.",
    rateLimiting: "Rate limiting",
    rateLimitingDesc: "Processing is done in batches with delays to respect API rate limits. Large vaults may take several minutes to complete.",
    close: "Close",
    loadingUpdatingTab: "Updating {{tab}} Analysis...",
    loadingGeneratingTab: "Generating {{tab}} Analysis...",
    loadingGeneratingAll: "Generating All Analyses",
    allAnalysesSuccess: "AI Knowledge Analysis completed successfully! Results cached for future use."
  },
  structure: {
    domainDistribution: "Knowledge domain distribution",
    networkAnalysis: "Knowledge network analysis",
    centralityDistributions: "Centrality score distributions",
    gapAnalysis: "Knowledge gap analysis",
    identifiedGaps: "Identified knowledge gaps"
  },
  evolution: {
    title: "Knowledge evolution analysis",
    emptyDesc: "Generate vault analysis to see your knowledge evolution insights.",
    activityCalendar: "Activity Calendar",
    learningTrends: "Learning Trends",
    focusEvolution: "Focus Evolution",
    calendarHeading: "Knowledge activity calendar",
    insightsHeading: "Knowledge evolution insights",
    timelineHeading: "Knowledge activity timeline",
    phasesHeading: "Knowledge development phases",
    velocityHeading: "Learning velocity trends",
    learningStrategy: "Learning strategy",
    topicIntroTimeline: "Topic introduction timeline",
    tabFocusShifts: "Focus shifts",
    tabTopicPatterns: "Topic patterns",
    newAreasLabel: "New: {{areas}}",
    increasedFocusLabel: "Increased focus: {{areas}}",
    decreasedFocusLabel: "Decreased focus: {{areas}}",
    emptyStateMessage: "Generate AI analysis to see your knowledge evolution insights and patterns over time.",
    trendProductivity: "Productivity",
    trendDiversity: "Diversity",
    trendDepth: "Depth",
    phaseMetrics: "{{count}} notes \xB7 {{words}} words",
    strategyStyle: "Style: {{value}}",
    strategyConsistency: "Consistency: {{value}}",
    velocity_increasing: "Increasing",
    velocity_decreasing: "Decreasing",
    velocity_stable: "Stable",
    velocity_expanding: "Expanding",
    velocity_narrowing: "Narrowing",
    shiftType_major: "Major shift",
    shiftType_minor: "Minor shift",
    shiftType_gradual: "Gradual shift",
    "strategyStyle_depth-first": "Depth-first",
    "strategyStyle_breadth-first": "Breadth-first",
    strategyStyle_balanced: "Balanced",
    strategyConsistency_focused: "Focused",
    strategyConsistency_exploratory: "Exploratory",
    strategyConsistency_mixed: "Mixed",
    acquisition_burst: "Burst",
    acquisition_gradual: "Gradual",
    "acquisition_project-based": "Project-based"
  },
  actions: {
    recommendedTitle: "Recommended actions",
    emptyDesc: "Generate vault analysis to see personalized action recommendations.",
    emptyStateMessage: "Generate AI analysis to get personalized action recommendations for your vault.",
    orgTabTags: "Tags",
    orgTabFolders: "Folders",
    orgTabStructure: "Structure",
    maintenance: "Knowledge Maintenance",
    connections: "Connection Opportunities",
    learningPaths: "Learning Paths",
    organization: "Organization Tips",
    summaryHeading: "Action summary",
    maintenanceHeading: "Knowledge maintenance",
    maintenanceDesc: "Notes that need review, updates, or improvements",
    openNote: "Open note",
    markDone: "Mark done",
    connectionsHeading: "Connection opportunities",
    connectionsDesc: "Suggested links between your notes",
    createLink: "Create link",
    preview: "Preview",
    dismiss: "Dismiss",
    learningPathsHeading: "Learning paths",
    learningPathsDesc: "Recommended sequences for learning and exploration",
    startPath: "Start path",
    bookmark: "Bookmark",
    organizationHeading: "Organization suggestions",
    organizationDesc: "Improvements for your knowledge structure",
    apply: "Apply"
  },
  domainChart: {
    noHierarchy: "No domain hierarchy available",
    generateFirst: "Please generate vault analysis with knowledge domain classification to see domain distribution.",
    knowledgeDomains: "Knowledge domains",
    subdivisions: "subdivisions",
    layers: "{{count}} layers",
    hoverExplore: "hover to explore",
    notes: "notes",
    centrality: "Centrality: {{value}}"
  },
  centralityView: {
    title: "{{algorithm}} Analysis"
  }
};

// src/i18n/locales/zh-Hans.json
var zh_Hans_default = {
  settings: {
    excludeHeading: "\u4ECE\u5206\u6790\u4E2D\u6392\u9664\u7B14\u8BB0",
    excludeFolders: {
      name: "\u6392\u9664\u6587\u4EF6\u5939",
      desc: '\u4F7F\u7528\u6587\u4EF6\u5939\u8DEF\u5F84\uFF0C\u4F8B\u5982 "archive"\u3001"templates"\u3001"private/personal"',
      placeholder: "Archive,templates,private/personal"
    },
    excludeTags: {
      name: "\u6392\u9664\u6807\u7B7E",
      desc: '\u4F7F\u7528\u4E0D\u5E26 # \u7684\u6807\u7B7E\u540D\uFF0C\u4F8B\u5982 "private"\u3001"draft"\u3001"archive"',
      placeholder: "Private,draft,archive"
    },
    llmHeading: "\u5927\u8BED\u8A00\u6A21\u578B\u914D\u7F6E",
    geminiApiKey: {
      name: "Gemini API \u5BC6\u94A5",
      descPrefix: "\u60A8\u7684 Google Gemini API \u5BC6\u94A5\u3002",
      getKeyLink: "\u83B7\u53D6 API \u5BC6\u94A5",
      placeholder: "\u8F93\u5165\u60A8\u7684 Gemini API \u5BC6\u94A5",
      showTooltip: "\u663E\u793A API \u5BC6\u94A5",
      hideTooltip: "\u9690\u85CF API \u5BC6\u94A5"
    },
    networkDisclosure: {
      name: "\u7F51\u7EDC\u4F7F\u7528\uFF08AI \u5206\u6790\uFF09",
      desc: "\u5F53\u60A8\u8FD0\u884C\u5E93\u5206\u6790\u6216\u751F\u6210\u6807\u7B7E\u9875\u6D1E\u5BDF\u65F6\uFF0C\u63D2\u4EF6\u4F1A\u4F7F\u7528\u60A8\u7684 API \u5BC6\u94A5\u5C06\u7B14\u8BB0\u5185\u5BB9\u4E0E\u5206\u6790\u63D0\u793A\u53D1\u9001\u81F3 Google Gemini API\uFF08generativelanguage.googleapis.com\uFF09\u3002\u63D2\u4EF6\u52A0\u8F7D\u65F6\u4E0D\u4F1A\u53D1\u9001\u4EFB\u4F55\u6570\u636E\u3002\u56FE\u6307\u6807\u4E0E\u7F13\u5B58\u5747\u4FDD\u5B58\u5728\u672C\u673A\u3002\u8BE6\u89C1 README \u4E2D\u7684\u300C\u9690\u79C1\u4E0E\u7F51\u7EDC\u300D\u4E00\u8282\u3002"
    },
    languageHeading: "\u8BED\u8A00",
    uiLanguage: {
      name: "\u754C\u9762\u8BED\u8A00",
      desc: "\u63D2\u4EF6\u83DC\u5355\u3001\u8BBE\u7F6E\u4E0E\u6807\u7B7E\u7684\u663E\u793A\u8BED\u8A00\u3002",
      obsidian: "\u4E0E Obsidian \u4E00\u81F4",
      en: "English",
      zhHans: "\u7B80\u4F53\u4E2D\u6587"
    },
    aiResponseLanguage: {
      name: "AI \u56DE\u590D\u8BED\u8A00",
      desc: "\u6240\u6709 AI \u751F\u6210\u5185\u5BB9\u7684\u8BED\u8A00\uFF08\u7B14\u8BB0\u6458\u8981\u3001\u7ED3\u6784\u3001\u6F14\u5316\u4E0E\u884C\u52A8\uFF09\u3002\u81EA\u52A8\u6A21\u5F0F\u6839\u636E\u5E93\u5185\u5BB9\u6216 Obsidian \u8BED\u8A00\u9009\u62E9\u82F1\u6587\u6216\u7B80\u4F53\u4E2D\u6587\u3002",
      auto: "\u81EA\u52A8\u68C0\u6D4B",
      en: "English",
      zhHans: "\u7B80\u4F53\u4E2D\u6587"
    },
    stats: {
      excludedTotal: "\u5DF2\u6392\u9664\u7B14\u8BB0\uFF1A{{total}}{{breakdown}}",
      excludedByFolder: "{{count}} \u4E2A\u6309\u6587\u4EF6\u5939",
      excludedByTag: "{{count}} \u4E2A\u6309\u6807\u7B7E",
      includedTotal: "\u7EB3\u5165\u5206\u6790\u7684\u7B14\u8BB0\uFF1A{{included}}/{{total}}",
      showExcluded: "\u663E\u793A\u5DF2\u6392\u9664\u7684\u6587\u4EF6",
      error: "\u8BA1\u7B97\u6392\u9664\u7EDF\u8BA1\u65F6\u51FA\u9519"
    },
    excludedModal: {
      title: "\u5DF2\u6392\u9664\u7684\u6587\u4EF6",
      empty: "\u5F53\u524D\u6CA1\u6709\u6392\u9664\u4EFB\u4F55\u6587\u4EF6\u3002"
    }
  },
  commands: {
    showExclusionStats: "\u663E\u793A\u6392\u9664\u7EDF\u8BA1",
    generateVaultAnalysis: "\u4E3A\u6574\u4E2A\u5E93\u751F\u6210 AI \u5206\u6790",
    viewVaultAnalysis: "\u67E5\u770B\u77E5\u8BC6\u5E93\u5206\u6790\u7ED3\u679C"
  },
  ribbon: {
    graphView: "\u56FE\u8C31\u5206\u6790\u89C6\u56FE"
  },
  errors: {
    quotaExhausted: "\u5DF2\u8FBE\u514D\u8D39\u7248\u6BCF\u65E5\u9650\u989D\uFF0C\u8BF7\u660E\u5929\u518D\u8BD5\u3002",
    rateLimit: "API \u8BF7\u6C42\u9891\u7387\u8D85\u9650\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002"
  },
  notices: {
    vaultAnalysisNotInitialized: "\u77E5\u8BC6\u5E93\u5206\u6790\u7BA1\u7406\u5668\u672A\u521D\u59CB\u5316",
    wasmInitializing: "\u6B63\u5728\u521D\u59CB\u5316\u56FE\u8C31\u5206\u6790\u2026",
    wasmInitFailed: "\u56FE\u8C31\u5206\u6790 WASM \u6A21\u5757\u521D\u59CB\u5316\u5931\u8D25\uFF1A{{message}}",
    exclusionUtilsNotInitialized: "\u6392\u9664\u5DE5\u5177\u672A\u521D\u59CB\u5316",
    exclusionStatsConsole: "\u8BF7\u5728\u63A7\u5236\u53F0\u67E5\u770B\u8BE6\u7EC6\u6392\u9664\u7EDF\u8BA1\u3002\u5DF2\u6392\u9664 {{count}} \u4E2A\u6587\u4EF6\u3002",
    exclusionStatsError: "\u83B7\u53D6\u6392\u9664\u7EDF\u8BA1\u65F6\u51FA\u9519",
    analyzeCentralityFailed: "\u5206\u6790 {{algorithm}} \u4E2D\u5FC3\u6027\u5931\u8D25\uFF1A{{message}}",
    graphLoadError: "\u52A0\u8F7D\u56FE\u8C31\u6570\u636E\u51FA\u9519\uFF1A{{message}}",
    graphReloadError: "\u91CD\u65B0\u52A0\u8F7D\u56FE\u8C31\u6570\u636E\u51FA\u9519\uFF1A{{message}}",
    centralityFailed: "\u8BA1\u7B97 {{type}} \u4E2D\u5FC3\u6027\u5931\u8D25\uFF1A{{message}}",
    configureApiKey: "\u8BF7\u5728\u8BBE\u7F6E\u4E2D\u914D\u7F6E Gemini API \u5BC6\u94A5\u4EE5\u4F7F\u7528\u77E5\u8BC6\u5E93\u5206\u6790\u3002",
    noFilesAfterExclusion: "\u5E94\u7528\u6392\u9664\u89C4\u5219\u540E\u672A\u627E\u5230\u53EF\u5206\u6790\u7684\u6587\u4EF6\u3002",
    allFilesUpToDate: "\u6240\u6709\u6587\u4EF6\u5747\u4E3A\u6700\u65B0\uFF0C\u672A\u68C0\u6D4B\u5230\u53D8\u66F4\u3002\uFF08{{count}} \u4E2A\u6587\u4EF6\u672A\u53D8\uFF09",
    vaultAnalysisProgress: "\u6B63\u5728\u5206\u6790\u5E93\uFF1A{{current}}/{{total}} \u4E2A\u6587\u4EF6\u2026",
    calculatingGraphMetrics: "\u6B63\u5728\u8BA1\u7B97\u56FE\u8C31\u6307\u6807\u2026",
    enhancingWithMetrics: "\u6B63\u5728\u7528\u56FE\u8C31\u6307\u6807\u589E\u5F3A\u77E5\u8BC6\u5E93\u5206\u6790\u2026",
    enhancedWithMetrics: "\u77E5\u8BC6\u5E93\u5206\u6790\u5DF2\u7528\u56FE\u8C31\u6307\u6807\u589E\u5F3A\u5B8C\u6210\uFF01",
    noAnalysisForEnhance: "\u672A\u627E\u5230\u73B0\u6709\u77E5\u8BC6\u5E93\u5206\u6790\uFF0C\u8BF7\u5148\u751F\u6210\u5206\u6790\u3002",
    enhanceFailed: "\u589E\u5F3A\u5931\u8D25\uFF1A{{message}}",
    vaultAnalysisComplete: "\u77E5\u8BC6\u5E93\u5206\u6790\u5B8C\u6210\uFF01\u751F\u6210 {{generated}} \u4E2A\uFF0C\u66F4\u65B0 {{updated}} \u4E2A\u3002",
    vaultAnalysisFailed: "\u751F\u6210\u77E5\u8BC6\u5E93\u5206\u6790\u5931\u8D25\uFF1A{{message}}",
    enhanceMetricsPrompt: "\u60A8\u7684\u77E5\u8BC6\u5E93\u5206\u6790\u7F3A\u5C11\u56FE\u8C31\u6307\u6807\u3002\u70B9\u51FB\u4EE5\u6DFB\u52A0\u4E2D\u5FC3\u6027\u5206\u6570\u3002",
    enhanceMetricsButton: "\u7528\u56FE\u8C31\u6307\u6807\u589E\u5F3A",
    loadVaultAnalysisFailed: "\u52A0\u8F7D\u77E5\u8BC6\u5E93\u5206\u6790\u7ED3\u679C\u5931\u8D25",
    vaultAnalysisInProgress: "\u9AD8\u7EA7\u5206\u6790\u4ECD\u5728\u8FDB\u884C\u4E2D\uFF0C\u5B8C\u6210\u540E\u5C06\u81EA\u52A8\u6253\u5F00\u7ED3\u679C\u3002",
    tabAnalysisComplete: "{{tab}} \u5206\u6790\u5DF2\u6210\u529F\u5B8C\u6210\uFF01",
    reopenModalFailed: "\u91CD\u65B0\u6253\u5F00\u5206\u6790\u7A97\u53E3\u5931\u8D25",
    updatingTabAnalysis: "\u6B63\u5728\u66F4\u65B0 {{tab}} \u5206\u6790\u2026\uFF08\u7EA6 1\u20132 \u5206\u949F\uFF09",
    generatingTabAnalysis: "\u6B63\u5728\u751F\u6210 {{tab}} \u5206\u6790\u2026\uFF08\u7EA6 1\u20132 \u5206\u949F\uFF09",
    tabAnalysisSuccess: "{{tab}} \u5206\u6790\u5DF2\u6210\u529F\u751F\u6210\uFF01",
    tabAnalysisFailed: "\u751F\u6210 AI \u5206\u6790\u5931\u8D25\uFF1A{{message}}",
    noConnectionsRemaining: "\u6CA1\u6709\u53EF\u6DFB\u52A0\u7684\u8FDE\u63A5\u3002",
    connectionsWritten: "\u5DF2\u6210\u529F\u5411\u7B14\u8BB0\u6DFB\u52A0 {{count}} \u6761\u8FDE\u63A5\u3002",
    connectionsWritten_other: "\u5DF2\u6210\u529F\u5411\u7B14\u8BB0\u6DFB\u52A0 {{count}} \u6761\u8FDE\u63A5\u3002",
    connectionsWriteFailed: "{{count}} \u6761\u8FDE\u63A5\u5199\u5165\u5931\u8D25\u3002",
    connectionsWriteFailed_other: "{{count}} \u6761\u8FDE\u63A5\u5199\u5165\u5931\u8D25\u3002",
    connectionsWriteError: "\u5199\u5165\u8FDE\u63A5\u5931\u8D25\uFF0C\u8BF7\u67E5\u770B\u63A7\u5236\u53F0\u4E86\u89E3\u8BE6\u60C5\u3002",
    preparingFiles: "\u6B63\u5728\u51C6\u5907\u5F85\u5206\u6790\u6587\u4EF6\u2026",
    vaultAnalysisStarting: "\u5F00\u59CB\u77E5\u8BC6\u5E93\u5206\u6790\uFF0C\u5171 {{count}} \u4E2A\u6587\u4EF6\uFF0C\u9884\u8BA1\u7EA6 {{minutes}} \u5206\u949F",
    vaultAnalysisUpdating: "\u66F4\u65B0\u5206\u6790\uFF1A{{changed}} \u4E2A\u5DF2\u6539\u3001{{new}} \u4E2A\u65B0\u589E\u3001{{unchanged}} \u4E2A\u672A\u53D8\uFF08\u6B63\u5728\u5904\u7406 {{processing}} \u4E2A\u6587\u4EF6\uFF09\uFF0C\u9884\u8BA1\u7EA6 {{minutes}} \u5206\u949F",
    vaultCompleteQuota: "\u5DF2\u4FDD\u5B58\u90E8\u5206\u7ED3\u679C\uFF08{{success}}/{{total}} \u4E2A\u6587\u4EF6\uFF09\u3002\u514D\u8D39\u7248\u6BCF\u65E5\u7EA6 500 \u7BC7\u7B14\u8BB0\u4E0A\u9650\u3002\u53EF\u5728 {{retryTime}} \u540E\u518D\u6B21\u8FD0\u884C\u4EE5\u7EE7\u7EED\u5269\u4F59 {{remaining}} \u7BC7\u3002",
    vaultCompleteIncrementalOk: "\u5206\u6790\u66F4\u65B0\u6210\u529F\uFF01\u5DF2\u5904\u7406 {{success}} \u4E2A\u53D8\u66F4/\u65B0\u589E\u6587\u4EF6\uFF08{{changed}} \u6539\u3001{{new}} \u65B0\uFF09\uFF0C\u4FDD\u7559 {{unchanged}} \u4E2A\u672A\u53D8\uFF0C\u79FB\u9664 {{deleted}} \u4E2A\u5DF2\u5220\u3002",
    vaultCompleteIncrementalWarn: "\u5206\u6790\u66F4\u65B0\u5B8C\u6210\u4F46\u90E8\u5206\u6709\u95EE\u9898\u3002\u6210\u529F {{success}} \u4E2A\uFF0C\u5931\u8D25 {{failed}} \u4E2A\uFF0C\u4FDD\u7559 {{unchanged}} \u4E2A\u672A\u53D8\uFF0C\u79FB\u9664 {{deleted}} \u4E2A\u5DF2\u5220\u3002",
    vaultCompleteFullOk: "\u5E26\u56FE\u8C31\u6307\u6807\u7684\u77E5\u8BC6\u5E93\u5206\u6790\u5DF2\u5B8C\u6210\uFF01\u5DF2\u5904\u7406 {{success}} \u4E2A\u6587\u4EF6\uFF0C\u7ED3\u679C\u5DF2\u4FDD\u5B58\u5230\u63D2\u4EF6\u6570\u636E\u76EE\u5F55",
    vaultCompleteFullWarn: "\u5E26\u56FE\u8C31\u6307\u6807\u7684\u77E5\u8BC6\u5E93\u5206\u6790\u5DF2\u5B8C\u6210\u4F46\u90E8\u5206\u6709\u95EE\u9898\u3002\u6210\u529F {{success}} \u4E2A\uFF0C\u5931\u8D25 {{failed}} \u4E2A\uFF0C\u7ED3\u679C\u5DF2\u4FDD\u5B58\u5230\u63D2\u4EF6\u6570\u636E\u76EE\u5F55",
    enhanceAnalysisFailed: "\u589E\u5F3A\u5206\u6790\u5931\u8D25\uFF1A{{message}}"
  },
  graph: {
    loading: "\u6B63\u5728\u52A0\u8F7D\u56FE\u8C31\u6570\u636E\u2026",
    display: "\u663E\u793A",
    labels: "\u6807\u7B7E",
    arrows: "\u7BAD\u5934",
    type: "\u7C7B\u578B",
    scale: "\u523B\u5EA6",
    steps: "\u6B65\u6570",
    reverse: "\u53CD\u8F6C",
    on: "\u5F00",
    off: "\u5173",
    centralityTitle: "{{type}} \u4E2D\u5FC3\u6027",
    betweennessDesc: "\u8861\u91CF\u8282\u70B9\u5728\u6700\u77ED\u8DEF\u5F84\u4E0A\u4F5C\u4E3A\u6865\u6881\u7684\u9891\u7387\uFF0C\u503C\u8D8A\u9AD8\u8868\u793A\u8D8A\u91CD\u8981\u7684\u8FDE\u63A5\u8282\u70B9\u3002",
    closenessDesc: "\u8861\u91CF\u8282\u70B9\u4E0E\u7F51\u7EDC\u4E2D\u5176\u4ED6\u8282\u70B9\u7684\u63A5\u8FD1\u7A0B\u5EA6\uFF0C\u503C\u8D8A\u9AD8\u8868\u793A\u80FD\u66F4\u5FEB\u89E6\u8FBE\u5176\u4ED6\u8282\u70B9\u3002",
    eigenvectorDesc: "\u6839\u636E\u90BB\u5C45\u8282\u70B9\u7684\u91CD\u8981\u6027\u8861\u91CF\u8282\u70B9\u91CD\u8981\u6027\uFF0C\u503C\u8D8A\u9AD8\u8868\u793A\u4E0E\u91CD\u8981\u6982\u5FF5\u8FDE\u63A5\u66F4\u7D27\u5BC6\u3002",
    tooltip: {
      created: "\u521B\u5EFA\uFF1A",
      modified: "\u4FEE\u6539\uFF1A",
      size: "\u5927\u5C0F\uFF1A",
      tags: "\u6807\u7B7E\uFF1A",
      openNote: "\u6253\u5F00\u7B14\u8BB0",
      notePreview: "\u7B14\u8BB0\u9884\u89C8",
      previewFailed: "\u65E0\u6CD5\u52A0\u8F7D\u7B14\u8BB0\u9884\u89C8\u3002",
      noteNotFound: "\u5728\u5E93\u4E2D\u672A\u627E\u5230\u8BE5\u7B14\u8BB0\uFF0C\u53EF\u80FD\u5DF2\u91CD\u547D\u540D\u6216\u5220\u9664\u3002",
      noFilePath: "\u8BE5\u8282\u70B9\u6CA1\u6709\u5173\u8054\u7684\u6587\u4EF6\u8DEF\u5F84\u3002"
    }
  },
  vaultAnalysis: {
    buttonTitle: "\u77E5\u8BC6\u5E93\u5206\u6790",
    buttonDesc: "\u4F7F\u7528 AI \u5206\u6790\u6574\u4E2A\u5E93\uFF0C\u63D0\u53D6\u6458\u8981\u3001\u5173\u952E\u8BCD\u3001\u77E5\u8BC6\u9886\u57DF\u548C\u56FE\u8C31\u4E2D\u5FC3\u6027\u6307\u6807\u3002Shift+\u70B9\u51FB\u53EF\u5F3A\u5236\u5237\u65B0\u56FE\u8C31\u6307\u6807\u3002",
    summary: "\u5206\u6790\u6458\u8981",
    searchFilter: "\u641C\u7D22\u4E0E\u7B5B\u9009",
    results: "\u5206\u6790\u7ED3\u679C",
    noSearchResults: "\u6CA1\u6709\u7B26\u5408\u641C\u7D22\u6761\u4EF6\u7684\u7ED3\u679C\u3002",
    previous: "\u4E0A\u4E00\u9875",
    next: "\u4E0B\u4E00\u9875",
    noAnalysisYet: "\u5C1A\u672A\u751F\u6210\u77E5\u8BC6\u5E93\u5206\u6790",
    generatePrompt: "\u70B9\u51FB\u4E0B\u65B9\u6309\u94AE\u5206\u6790\u6574\u4E2A\u5E93\uFF0C\u4ECE\u6240\u6709\u7B14\u8BB0\u4E2D\u63D0\u53D6\u6458\u8981\u3001\u5173\u952E\u8BCD\u548C\u77E5\u8BC6\u9886\u57DF\u3002",
    domainDistribution: "\u77E5\u8BC6\u9886\u57DF\u5206\u5E03",
    networkAnalysis: "\u77E5\u8BC6\u7F51\u7EDC\u5206\u6790",
    knowledgeGaps: "\u77E5\u8BC6\u7F3A\u53E3",
    identifiedGaps: "\u5DF2\u8BC6\u522B\u7684\u77E5\u8BC6\u7F3A\u53E3",
    structureEmptyTitle: "\u77E5\u8BC6\u7ED3\u6784\u5206\u6790",
    structureEmptyDesc: "\u751F\u6210 AI \u5206\u6790\u4EE5\u89E3\u9501\u9AD8\u7EA7\u77E5\u8BC6\u7ED3\u6784\u6D1E\u5BDF\u3002",
    structureFeatureSunburst: "\u4EA4\u4E92\u5F0F\u65ED\u65E5\u56FE \u2014 \u63A2\u7D22\u5C42\u7EA7\u5316\u77E5\u8BC6\u9886\u57DF",
    structureFeatureNetwork: "\u77E5\u8BC6\u7F51\u7EDC\u5206\u6790 \u2014 \u8BC6\u522B\u6865\u6881\u7B14\u8BB0\u3001\u57FA\u7840\u8282\u70B9\u4E0E\u6743\u5A01\u8282\u70B9",
    structureFeatureGaps: "\u77E5\u8BC6\u7F3A\u53E3\u53D1\u73B0 \u2014 \u627E\u51FA\u5E93\u4E2D\u63A2\u7D22\u4E0D\u8DB3\u7684\u533A\u57DF",
    structureFeatureDistribution: "\u9886\u57DF\u5206\u5E03 \u2014 \u4E86\u89E3\u77E5\u8BC6\u5728\u5404\u9886\u57DF\u7684\u7EC4\u7EC7\u65B9\u5F0F",
    actions: "\u64CD\u4F5C",
    processing: "\u5206\u6790\u8FDB\u884C\u4E2D\u2026",
    updateAnalysis: "\u66F4\u65B0\u5206\u6790",
    generateAnalysis: "\u751F\u6210\u5206\u6790",
    privacyNote1: "\u672C\u5206\u6790\u4F7F\u7528 Google Gemini AI \u4ECE\u60A8\u7684\u5E93\u4E2D\u63D0\u53D6\u6D1E\u5BDF\u3002\u6211\u4EEC\u4EC5\u5411 AI \u53D1\u9001\u7B14\u8BB0\u6458\u8981\u548C\u5143\u6570\u636E\uFF08\u5173\u952E\u8BCD\u3001\u9886\u57DF\u3001\u56FE\u8C31\u6307\u6807\uFF09\uFF0C\u4ECE\u4E0D\u53D1\u9001\u5B8C\u6574\u7B14\u8BB0\u5185\u5BB9\uFF0C\u4EE5\u4FDD\u62A4\u9690\u79C1\u5E76\u663E\u8457\u51CF\u5C11 token \u7528\u91CF\u3002",
    privacyNote2: "\u5728 AI \u5206\u6790\u4E4B\u524D\uFF0C\u6211\u4EEC\u4F7F\u7528\u786E\u5B9A\u6027\u65B9\u6CD5\uFF08\u56FE\u8BBA\u3001\u7EDF\u8BA1\u5206\u6790\u3001KDE \u5206\u5E03\uFF09\u9884\u5904\u7406\u5E93\u6570\u636E\uFF0C\u4EE5\u786E\u4FDD\u51C6\u786E\u9AD8\u6548\u7684\u6D1E\u5BDF\u3002",
    loadingTitle: "\u6B63\u5728\u751F\u6210 AI \u5206\u6790",
    estimatedTime: "\u9884\u8BA1\u65F6\u95F4\uFF1A",
    cachedNote: "\u7ED3\u679C\u5C06\u7F13\u5B58\u4F9B\u65E5\u540E\u4F7F\u7528\u3002",
    errorTitle: "\u751F\u6210 AI \u5206\u6790\u65F6\u51FA\u9519",
    conclusion: "\u7ED3\u8BBA",
    generateVaultFirst: "\u8BF7\u5148\u751F\u6210\u77E5\u8BC6\u5E93\u5206\u6790\u4EE5\u4F7F\u7528\u6B64\u529F\u80FD\u3002",
    networkMetrics: "\u7F51\u7EDC\u6307\u6807\u5206\u6790",
    inboundOutbound: "\u5165\u94FE vs \u51FA\u94FE",
    betweennessEigenvector: "\u4ECB\u6570 vs \u7279\u5F81\u5411\u91CF",
    notesNeedingReview: "\u9700\u8981\u5BA1\u9605\u7684\u7B14\u8BB0",
    suggestedConnections: "\u5EFA\u8BAE\u7684\u8FDE\u63A5",
    evolutionEmptyTitle: "\u77E5\u8BC6\u6F14\u5316\u5206\u6790",
    evolutionEmptyDesc: "\u77E5\u8BC6\u6F14\u5316\u5206\u6790\u9700\u8981\u5148\u5B8C\u6210 AI \u77E5\u8BC6\u5E93\u5206\u6790\u3002",
    developmentTimeline: "\u77E5\u8BC6\u53D1\u5C55\u65F6\u95F4\u7EBF",
    tabSemantic: "\u8BED\u4E49\u5206\u6790",
    tabStructure: "\u77E5\u8BC6\u7ED3\u6784",
    tabEvolution: "\u77E5\u8BC6\u6F14\u5316",
    tabActions: "\u63A8\u8350\u64CD\u4F5C",
    tabDisabledTitle: "\u8BF7\u5148\u8FD0\u884C\u8BED\u4E49\u5206\u6790",
    sectionTopicPatterns: "\u4E3B\u9898\u5F15\u5165\u6A21\u5F0F",
    sectionFocusShifts: "\u7126\u70B9\u8F6C\u79FB\u5206\u6790",
    placeholderTimeline: "\u751F\u6210\u5206\u6790\u4EE5\u603B\u7ED3\u5E93\u5728\u53D1\u5C55\u8FC7\u7A0B\u4E2D\u7684\u5173\u952E\u9636\u6BB5\u4E0E\u91CC\u7A0B\u7891\u3002",
    placeholderTopic: "\u751F\u6210\u5206\u6790\u4EE5\u6807\u51FA\u65B0\u4E3B\u9898\u4E0E\u77E5\u8BC6\u9886\u57DF\u9996\u6B21\u51FA\u73B0\u7684\u65F6\u95F4\u3002",
    placeholderFocus: "\u751F\u6210\u5206\u6790\u4EE5\u5BF9\u6BD4\u8FD1\u671F\u4E0E\u65E9\u671F\u7684\u5173\u6CE8\u9886\u57DF\uFF0C\u5E76\u8BC6\u522B\u663E\u8457\u53D8\u5316\u3002",
    evolutionFeatureTimeline: "\u77E5\u8BC6\u53D1\u5C55\u65F6\u95F4\u7EBF \u2014 \u8FFD\u8E2A\u7406\u89E3\u5982\u4F55\u6F14\u5316",
    evolutionFeatureTopic: "\u4E3B\u9898\u5F15\u5165\u6A21\u5F0F \u2014 \u67E5\u770B\u4E0D\u540C\u4E3B\u9898\u4F55\u65F6\u8FDB\u5165\u4F53\u7CFB",
    evolutionFeatureFocus: "\u7126\u70B9\u8F6C\u79FB\u5206\u6790 \u2014 \u5BF9\u6BD4\u5F53\u524D\u5174\u8DA3\u4E0E\u5386\u53F2\u6A21\u5F0F",
    focusShiftStats: "\u65B0\u589E {{newCount}} \u4E2A\u9886\u57DF\uFF0C\u51CF\u5C11 {{reducedCount}} \u4E2A",
    loadingIncludesTab: "\u5185\u5BB9\u5305\u62EC\uFF1A{{description}}\u3002",
    loadingIncludesAll: "\u5185\u5BB9\u5305\u62EC\u77E5\u8BC6\u7ED3\u6784\u3001\u6F14\u5316\u5206\u6790\u4E0E\u63A8\u8350\u64CD\u4F5C\u3002",
    tabDisplayStructure: "\u77E5\u8BC6\u7ED3\u6784",
    tabDisplayEvolution: "\u77E5\u8BC6\u6F14\u5316",
    tabDisplayActions: "\u63A8\u8350\u64CD\u4F5C",
    tabDisplayDefault: "\u77E5\u8BC6",
    tabDescStructure: "\u9886\u57DF\u5206\u7C7B\u3001\u5C42\u7EA7\u7ED3\u6784\u4E0E\u7F51\u7EDC\u5206\u6790",
    tabDescEvolution: "\u65F6\u95F4\u7EBF\u5206\u6790\u3001\u4E3B\u9898\u6A21\u5F0F\u4E0E\u7126\u70B9\u8F6C\u79FB",
    tabDescActions: "\u7EF4\u62A4\u4EFB\u52A1\u3001\u8FDE\u63A5\u673A\u4F1A\u4E0E\u5B66\u4E60\u8DEF\u5F84",
    tabDescDefault: "\u5168\u9762\u7684\u77E5\u8BC6\u5206\u6790",
    errorFailed: "\u751F\u6210\u5206\u6790\u5931\u8D25\uFF1A{{message}}",
    aboutTitle: "\u5173\u4E8E\u77E5\u8BC6\u5E93\u5206\u6790",
    aboutIntro: "\u77E5\u8BC6\u5E93\u5206\u6790\u4F7F\u7528 AI \u5206\u6790\u6574\u4E2A Obsidian \u5E93\u5E76\u63D0\u4F9B\uFF1A",
    requirements: "\u8981\u6C42",
    requirementsApiKey: "Google Gemini API \u5BC6\u94A5\uFF08\u5728\u63D2\u4EF6\u8BBE\u7F6E\u4E2D\u914D\u7F6E\uFF09",
    requirementsInternet: "\u8FDB\u884C AI \u5904\u7406\u9700\u8981\u7F51\u7EDC\u8FDE\u63A5",
    exclusions: "\u6392\u9664\u89C4\u5219",
    exclusionsDesc: "\u5206\u6790\u4F1A\u9075\u5FAA\u60A8\u5BF9\u6587\u4EF6\u5939\u548C\u6807\u7B7E\u7684\u6392\u9664\u8BBE\u7F6E\uFF0C\u4EC5\u5904\u7406\u76F8\u5173\u7B14\u8BB0\u3002",
    rateLimiting: "\u901F\u7387\u9650\u5236",
    rateLimitingDesc: "\u5904\u7406\u5206\u6279\u8FDB\u884C\u5E76\u5E26\u6709\u5EF6\u8FDF\u4EE5\u9075\u5B88 API \u9650\u5236\uFF0C\u5927\u578B\u5E93\u53EF\u80FD\u9700\u8981\u6570\u5206\u949F\u3002",
    close: "\u5173\u95ED",
    loadingUpdatingTab: "\u6B63\u5728\u66F4\u65B0 {{tab}} \u5206\u6790\u2026",
    loadingGeneratingTab: "\u6B63\u5728\u751F\u6210 {{tab}} \u5206\u6790\u2026",
    loadingGeneratingAll: "\u6B63\u5728\u751F\u6210\u5168\u90E8\u5206\u6790",
    allAnalysesSuccess: "AI \u77E5\u8BC6\u5206\u6790\u5DF2\u6210\u529F\u5B8C\u6210\uFF01\u7ED3\u679C\u5DF2\u7F13\u5B58\u4F9B\u65E5\u540E\u4F7F\u7528\u3002"
  },
  structure: {
    domainDistribution: "\u77E5\u8BC6\u9886\u57DF\u5206\u5E03",
    networkAnalysis: "\u77E5\u8BC6\u7F51\u7EDC\u5206\u6790",
    centralityDistributions: "\u4E2D\u5FC3\u6027\u5206\u6570\u5206\u5E03",
    gapAnalysis: "\u77E5\u8BC6\u7F3A\u53E3\u5206\u6790",
    identifiedGaps: "\u5DF2\u8BC6\u522B\u7684\u77E5\u8BC6\u7F3A\u53E3"
  },
  evolution: {
    title: "\u77E5\u8BC6\u6F14\u5316\u5206\u6790",
    emptyDesc: "\u751F\u6210\u77E5\u8BC6\u5E93\u5206\u6790\u4EE5\u67E5\u770B\u77E5\u8BC6\u6F14\u5316\u6D1E\u5BDF\u3002",
    activityCalendar: "\u6D3B\u52A8\u65E5\u5386",
    learningTrends: "\u5B66\u4E60\u8D8B\u52BF",
    focusEvolution: "\u7126\u70B9\u6F14\u5316",
    calendarHeading: "\u77E5\u8BC6\u6D3B\u52A8\u65E5\u5386",
    insightsHeading: "\u77E5\u8BC6\u6F14\u5316\u6D1E\u5BDF",
    timelineHeading: "\u77E5\u8BC6\u6D3B\u52A8\u65F6\u95F4\u7EBF",
    phasesHeading: "\u77E5\u8BC6\u53D1\u5C55\u9636\u6BB5",
    velocityHeading: "\u5B66\u4E60\u901F\u5EA6\u8D8B\u52BF",
    learningStrategy: "\u5B66\u4E60\u7B56\u7565",
    topicIntroTimeline: "\u4E3B\u9898\u5F15\u5165\u65F6\u95F4\u7EBF",
    tabFocusShifts: "\u7126\u70B9\u8F6C\u79FB",
    tabTopicPatterns: "\u4E3B\u9898\u6A21\u5F0F",
    newAreasLabel: "\u65B0\u589E\uFF1A{{areas}}",
    increasedFocusLabel: "\u5173\u6CE8\u589E\u52A0\uFF1A{{areas}}",
    decreasedFocusLabel: "\u5173\u6CE8\u51CF\u5C11\uFF1A{{areas}}",
    emptyStateMessage: "\u751F\u6210 AI \u5206\u6790\u4EE5\u67E5\u770B\u77E5\u8BC6\u6F14\u5316\u6D1E\u5BDF\u4E0E\u957F\u671F\u6A21\u5F0F\u3002",
    trendProductivity: "\u4EA7\u51FA",
    trendDiversity: "\u591A\u6837\u6027",
    trendDepth: "\u6DF1\u5EA6",
    phaseMetrics: "{{count}} \u7BC7\u7B14\u8BB0 \xB7 {{words}} \u5B57",
    strategyStyle: "\u98CE\u683C\uFF1A{{value}}",
    strategyConsistency: "\u4E00\u81F4\u6027\uFF1A{{value}}",
    velocity_increasing: "\u4E0A\u5347",
    velocity_decreasing: "\u4E0B\u964D",
    velocity_stable: "\u7A33\u5B9A",
    velocity_expanding: "\u6269\u5C55",
    velocity_narrowing: "\u6536\u7A84",
    shiftType_major: "\u91CD\u5927\u8F6C\u79FB",
    shiftType_minor: "\u6B21\u8981\u8F6C\u79FB",
    shiftType_gradual: "\u6E10\u8FDB\u8F6C\u79FB",
    "strategyStyle_depth-first": "\u6DF1\u5EA6\u4F18\u5148",
    "strategyStyle_breadth-first": "\u5E7F\u5EA6\u4F18\u5148",
    strategyStyle_balanced: "\u5747\u8861",
    strategyConsistency_focused: "\u4E13\u6CE8",
    strategyConsistency_exploratory: "\u63A2\u7D22\u578B",
    strategyConsistency_mixed: "\u6DF7\u5408",
    acquisition_burst: "\u96C6\u4E2D\u7206\u53D1",
    acquisition_gradual: "\u6E10\u8FDB",
    "acquisition_project-based": "\u9879\u76EE\u9A71\u52A8"
  },
  actions: {
    recommendedTitle: "\u63A8\u8350\u64CD\u4F5C",
    emptyDesc: "\u751F\u6210\u77E5\u8BC6\u5E93\u5206\u6790\u4EE5\u67E5\u770B\u4E2A\u6027\u5316\u884C\u52A8\u5EFA\u8BAE\u3002",
    emptyStateMessage: "\u751F\u6210 AI \u5206\u6790\u4EE5\u83B7\u53D6\u9488\u5BF9\u6574\u4E2A\u5E93\u7684\u4E2A\u6027\u5316\u884C\u52A8\u5EFA\u8BAE\u3002",
    orgTabTags: "\u6807\u7B7E",
    orgTabFolders: "\u6587\u4EF6\u5939",
    orgTabStructure: "\u7ED3\u6784",
    maintenance: "\u77E5\u8BC6\u7EF4\u62A4",
    connections: "\u8FDE\u63A5\u673A\u4F1A",
    learningPaths: "\u5B66\u4E60\u8DEF\u5F84",
    organization: "\u6574\u7406\u5EFA\u8BAE",
    summaryHeading: "\u884C\u52A8\u6458\u8981",
    maintenanceHeading: "\u77E5\u8BC6\u7EF4\u62A4",
    maintenanceDesc: "\u9700\u8981\u5BA1\u9605\u3001\u66F4\u65B0\u6216\u6539\u8FDB\u7684\u7B14\u8BB0",
    openNote: "\u6253\u5F00\u7B14\u8BB0",
    markDone: "\u6807\u8BB0\u5B8C\u6210",
    connectionsHeading: "\u8FDE\u63A5\u673A\u4F1A",
    connectionsDesc: "\u7B14\u8BB0\u4E4B\u95F4\u7684\u5EFA\u8BAE\u94FE\u63A5",
    createLink: "\u521B\u5EFA\u94FE\u63A5",
    preview: "\u9884\u89C8",
    dismiss: "\u5FFD\u7565",
    learningPathsHeading: "\u5B66\u4E60\u8DEF\u5F84",
    learningPathsDesc: "\u63A8\u8350\u7684\u5B66\u4E60\u4E0E\u63A2\u7D22\u987A\u5E8F",
    startPath: "\u5F00\u59CB\u8DEF\u5F84",
    bookmark: "\u6536\u85CF",
    organizationHeading: "\u6574\u7406\u5EFA\u8BAE",
    organizationDesc: "\u6539\u8FDB\u77E5\u8BC6\u7ED3\u6784\u7684\u5EFA\u8BAE",
    apply: "\u5E94\u7528"
  },
  domainChart: {
    noHierarchy: "\u65E0\u53EF\u7528\u9886\u57DF\u5C42\u7EA7",
    generateFirst: "\u8BF7\u5148\u751F\u6210\u5E26\u77E5\u8BC6\u9886\u57DF\u5206\u7C7B\u7684\u77E5\u8BC6\u5E93\u5206\u6790\u4EE5\u67E5\u770B\u9886\u57DF\u5206\u5E03\u3002",
    knowledgeDomains: "\u77E5\u8BC6\u9886\u57DF",
    subdivisions: "\u4E2A\u5B50\u7C7B",
    layers: "{{count}} \u5C42",
    hoverExplore: "\u60AC\u505C\u63A2\u7D22",
    notes: "\u7BC7\u7B14\u8BB0",
    centrality: "\u4E2D\u5FC3\u6027\uFF1A{{value}}"
  },
  centralityView: {
    title: "{{algorithm}} \u5206\u6790"
  }
};

// src/i18n/index.ts
var LOCALES = {
  en: en_default,
  "zh-Hans": zh_Hans_default
};
var uiLanguageSetting = "auto";
function configureI18n(uiLanguage) {
  uiLanguageSetting = uiLanguage;
}
function isChineseLocaleTag(loc) {
  return loc === "zh-cn" || loc === "zh-hans" || loc.startsWith("zh");
}
function getObsidianLocale() {
  const momentLoc = import_obsidian3.moment.locale().toLowerCase();
  if (isChineseLocaleTag(momentLoc)) {
    return "zh-Hans";
  }
  if (typeof navigator !== "undefined") {
    const navLang = navigator.language?.toLowerCase() ?? "";
    if (isChineseLocaleTag(navLang)) {
      return "zh-Hans";
    }
  }
  return "en";
}
function getPluginLocale() {
  if (uiLanguageSetting === "en") return "en";
  if (uiLanguageSetting === "zh-Hans") return "zh-Hans";
  return getObsidianLocale();
}
function lookupString(locale2, key) {
  let value = LOCALES[locale2];
  for (const part of key.split(".")) {
    if (value == null || typeof value !== "object") {
      return void 0;
    }
    value = value[part];
  }
  return typeof value === "string" ? value : void 0;
}
function t(key, params) {
  const locale2 = getPluginLocale();
  let s = lookupString(locale2, key) ?? lookupString("en", key) ?? key;
  if (params) {
    for (const [k, v] of Object.entries(params)) {
      s = s.replaceAll(`{{${k}}}`, String(v));
    }
  }
  return s;
}
function tp(count2, oneKey, otherKey, params) {
  return t(count2 === 1 ? oneKey : otherKey, { ...params, count: count2 });
}

// src/components/connection-subgraph/ConnectionSubGraph.ts
var _ConnectionSubGraph = class _ConnectionSubGraph {
  constructor(app, container, connections, options = {}) {
    this.nodes = [];
    this.links = [];
    this.markerId = "";
    this.app = app;
    this.container = container;
    this.connections = connections;
    this.options = options;
    this.width = options.width || 700;
    this.height = options.height || 450;
  }
  /**
   * Build the node/link data from ConnectionSuggestion[], then render
   * the D3 force graph and the "Add to Main Graph" button.
   */
  render() {
    this.buildGraphData();
    this.createSVG();
    this.createTooltip();
    this.initSimulation();
    this.drawLinks();
    this.drawNodes();
    this.createLegend();
    this.createAddToGraphButton();
  }
  // ─────────────────── Data Construction ───────────────────
  buildGraphData() {
    const nodeMap = /* @__PURE__ */ new Map();
    for (const conn of this.connections) {
      if (!nodeMap.has(conn.sourceId)) {
        nodeMap.set(conn.sourceId, {
          id: conn.sourceId,
          title: NoteResolver.resolveToTitle(this.app, conn.sourceId),
          path: conn.sourceId,
          degree: 0,
          removed: false
        });
      }
      if (!nodeMap.has(conn.targetId)) {
        nodeMap.set(conn.targetId, {
          id: conn.targetId,
          title: NoteResolver.resolveToTitle(this.app, conn.targetId),
          path: conn.targetId,
          degree: 0,
          removed: false
        });
      }
      nodeMap.get(conn.sourceId).degree++;
      nodeMap.get(conn.targetId).degree++;
    }
    this.nodes = Array.from(nodeMap.values());
    this.links = this.connections.map((c4) => ({
      source: c4.sourceId,
      target: c4.targetId,
      reason: c4.reason,
      confidence: c4.confidence,
      removed: false
    }));
  }
  // ─────────────────── SVG Setup ───────────────────
  createSVG() {
    const svgWrapper = this.container.createEl("div", { cls: "subgraph-svg-wrapper" });
    svgWrapper.style.setProperty("--subgraph-height", `${this.height}px`);
    this.svg = select_default2(svgWrapper).append("svg").attr("width", "100%").attr("height", "100%").attr("viewBox", [
      -this.width / 2,
      -this.height / 2,
      this.width,
      this.height
    ].join(" ")).attr("class", "connection-subgraph-svg");
    this.markerId = `subgraph-arrow-${Date.now()}-${Math.random().toString(36).slice(2)}`;
    this.svg.append("defs").append("marker").attr("id", this.markerId).attr("markerUnits", "userSpaceOnUse").attr("markerWidth", 10).attr("markerHeight", 10).attr("refX", 9).attr("refY", 0).attr("orient", "auto").attr("viewBox", "0 -4 10 8").append("path").attr("d", "M0,-4 L10,0 L0,4 Z").attr("fill", "var(--text-accent)");
    this.svgGroup = this.svg.append("g");
    const pad = 0.5;
    const scale = _ConnectionSubGraph.GRAPH_SCALE;
    this.zoomBehavior = zoom_default2().scaleExtent([scale, scale]).translateExtent([
      [-this.width * (0.5 + pad), -this.height * (0.5 + pad)],
      [this.width * (0.5 + pad), this.height * (0.5 + pad)]
    ]).on("zoom", (ev) => {
      this.svgGroup.attr("transform", ev.transform.toString());
    });
    this.svg.call(this.zoomBehavior);
    this.svg.call(this.zoomBehavior.transform.bind(this.zoomBehavior), identity3.scale(scale));
    const resetBtn = svgWrapper.createEl("div", { cls: "subgraph-reset-view-btn" });
    resetBtn.setAttribute("role", "button");
    resetBtn.setAttribute("tabindex", "0");
    (0, import_obsidian4.setIcon)(resetBtn, "refresh-cw");
    resetBtn.title = "Reset view";
    resetBtn.addEventListener("click", (e) => {
      e.stopPropagation();
      this.resetView();
    });
    resetBtn.addEventListener("keydown", (e) => {
      if (e.key === "Enter" || e.key === " ") {
        e.preventDefault();
        this.resetView();
      }
    });
  }
  createTooltip() {
    this.tooltip = this.container.createEl("div", { cls: "subgraph-tooltip subgraph-tooltip-hidden" });
  }
  // ─────────────────── Simulation ───────────────────
  initSimulation() {
    this.simulation = simulation_default(this.nodes).force("link", link_default(this.links).id((d) => d.id).distance(100)).force("charge", manyBody_default().strength(-400)).force("x", x_default2().strength(0.1)).force("y", y_default2().strength(0.1)).force("collision", collide_default().radius((d) => this.getNodeRadius(d) + 10).strength(0.8)).on("tick", () => this.tick());
  }
  getNodeRadius(node) {
    return Math.min(15, Math.max(10, 9 + node.degree * 1.5));
  }
  tick() {
    this.linksSelection.attr("x1", (d) => this.linkStartX(d)).attr("y1", (d) => this.linkStartY(d)).attr("x2", (d) => this.linkEndX(d)).attr("y2", (d) => this.linkEndY(d));
    this.nodesSelection.attr("transform", (d) => `translate(${d.x ?? 0},${d.y ?? 0})`);
  }
  /** Shorten link to node edge so arrow sits adjacent to circle, not hidden behind it */
  linkStartX(d) {
    const s = d.source;
    const t2 = d.target;
    const sx = s.x ?? 0, sy = s.y ?? 0, tx = t2.x ?? 0, ty = t2.y ?? 0;
    const dx = tx - sx, dy = ty - sy;
    const len = Math.hypot(dx, dy) || 1;
    const normX = dx / len;
    return sx + normX * this.getNodeRadius(s);
  }
  linkStartY(d) {
    const s = d.source;
    const t2 = d.target;
    const sx = s.x ?? 0, sy = s.y ?? 0, tx = t2.x ?? 0, ty = t2.y ?? 0;
    const dx = tx - sx, dy = ty - sy;
    const len = Math.hypot(dx, dy) || 1;
    const normY = dy / len;
    return sy + normY * this.getNodeRadius(s);
  }
  linkEndX(d) {
    const s = d.source;
    const t2 = d.target;
    const sx = s.x ?? 0, sy = s.y ?? 0, tx = t2.x ?? 0, ty = t2.y ?? 0;
    const dx = tx - sx, dy = ty - sy;
    const len = Math.hypot(dx, dy) || 1;
    const normX = dx / len;
    return tx - normX * this.getNodeRadius(t2);
  }
  linkEndY(d) {
    const s = d.source;
    const t2 = d.target;
    const sx = s.x ?? 0, sy = s.y ?? 0, tx = t2.x ?? 0, ty = t2.y ?? 0;
    const dx = tx - sx, dy = ty - sy;
    const len = Math.hypot(dx, dy) || 1;
    const normY = dy / len;
    return ty - normY * this.getNodeRadius(t2);
  }
  // ─────────────────── Drawing ───────────────────
  drawLinks() {
    const linksGroup = this.svgGroup.append("g").attr("class", "subgraph-links");
    const linksSel = linksGroup.selectAll("line").data(this.links.filter((l) => !l.removed)).join("line");
    linksSel.attr("class", "suggested-link").attr("stroke", "var(--text-accent)").attr("stroke-width", 2).attr("stroke-opacity", (d) => 0.3 + d.confidence * 0.5).attr("stroke-dasharray", "6,3").attr("marker-end", "url(#" + this.markerId + ")").on("mouseover", (event, d) => {
      this.showLinkTooltip(event, d);
      select_default2(event.currentTarget).attr("stroke-opacity", 1);
    }).on("mouseout", (event, d) => {
      this.hideTooltip();
      select_default2(event.currentTarget).attr("stroke-opacity", 0.3 + d.confidence * 0.5);
    });
    this.linksSelection = linksSel;
  }
  drawNodes() {
    const nodesGroup = this.svgGroup.append("g").attr("class", "subgraph-nodes");
    const nodeGroups = nodesGroup.selectAll("g").data(this.nodes.filter((n) => !n.removed)).join("g").attr("class", "subgraph-node-group").style("cursor", "pointer").call(
      drag_default().on("start", (ev, d) => {
        if (!ev.active) this.simulation.alphaTarget(0.3).restart();
        d.fx = d.x ?? null;
        d.fy = d.y ?? null;
      }).on("drag", (ev, d) => {
        d.fx = ev.x;
        d.fy = ev.y;
      }).on("end", (ev, d) => {
        if (!ev.active) this.simulation.alphaTarget(0);
        d.fx = null;
        d.fy = null;
      })
    );
    nodeGroups.append("circle").attr("r", (d) => this.getNodeRadius(d)).attr("fill", "var(--interactive-accent)").attr("stroke", "none").on("mouseover", (event, d) => {
      this.showTooltip(event, d.title);
      select_default2(event.currentTarget).transition().duration(150).attr("r", this.getNodeRadius(d) + 3);
    }).on("mouseout", (event, d) => {
      this.hideTooltip();
      select_default2(event.currentTarget).transition().duration(150).attr("r", this.getNodeRadius(d));
    });
    nodeGroups.append("text").attr("class", "subgraph-node-label").attr("dy", (d) => this.getNodeRadius(d) + 18).attr("text-anchor", "middle").text((d) => d.title.length > 20 ? d.title.slice(0, 18) + "..." : d.title).attr("fill", "var(--text-muted)").attr("font-size", "11px").style("pointer-events", "none");
    const deleteBtn = nodeGroups.append("g").attr("class", "subgraph-delete-btn").attr("transform", (d) => `translate(${this.getNodeRadius(d) + 2}, ${-this.getNodeRadius(d) - 2})`).style("opacity", 0).style("cursor", "pointer").on("click", (event, d) => {
      event.stopPropagation();
      this.removeNode(d);
    });
    deleteBtn.append("circle").attr("r", 7).attr("fill", "var(--background-modifier-error)").attr("stroke", "var(--background-primary)").attr("stroke-width", 1);
    deleteBtn.append("text").attr("text-anchor", "middle").attr("dy", "0.35em").attr("font-size", "10px").attr("fill", "var(--text-on-accent)").text("\xD7");
    nodeGroups.on("mouseenter", function() {
      select_default2(this).select(".subgraph-delete-btn").transition().duration(150).style("opacity", 1);
    }).on("mouseleave", function() {
      select_default2(this).select(".subgraph-delete-btn").transition().duration(150).style("opacity", 0);
    });
    nodeGroups.select("circle").on("click", (event, d) => {
      if (event.defaultPrevented) return;
      void this.openNoteInNewTab(d.path);
    });
    this.nodesSelection = nodeGroups;
  }
  // ─────────────────── Legend ───────────────────
  createLegend() {
    const legend = this.container.createEl("div", { cls: "subgraph-legend" });
    const items = [
      { label: "Suggested link (hover for details)", cls: "legend-link" },
      { label: "Note node (click to open, hover \xD7 to remove)", cls: "legend-node" }
    ];
    for (const item of items) {
      const row = legend.createEl("div", { cls: "subgraph-legend-item" });
      row.createEl("span", { cls: `legend-dot ${item.cls}` });
      row.createEl("span", { text: item.label, cls: "legend-text" });
    }
  }
  resetView() {
    const transform2 = this.zoomBehavior.transform.bind(this.zoomBehavior);
    this.svg.transition().duration(300).call(transform2, identity3.scale(_ConnectionSubGraph.GRAPH_SCALE));
  }
  // ─────────────────── Add to Graph Button ───────────────────
  createAddToGraphButton() {
    const buttonSection = this.container.createEl("div", { cls: "subgraph-button-section" });
    const counter = buttonSection.createEl("div", { cls: "subgraph-counter" });
    this.updateCounter(counter);
    const alreadyAdded = !!this.options.connectionsAddedAt;
    const button = buttonSection.createEl("button", {
      cls: alreadyAdded ? "mod-cta subgraph-add-btn subgraph-btn-done" : "mod-cta subgraph-add-btn",
      text: alreadyAdded ? "Connections Added" : "Add to Main Graph"
    });
    if (alreadyAdded) {
      button.disabled = true;
    } else {
      const iconSpan = button.createEl("span", { cls: "subgraph-btn-icon" });
      (0, import_obsidian4.setIcon)(iconSpan, "plus-circle");
    }
    button.addEventListener("click", () => {
      void (async () => {
        const remaining = this.getRemainingConnections();
        if (remaining.length === 0) {
          new import_obsidian4.Notice(t("notices.noConnectionsRemaining"));
          return;
        }
        button.disabled = true;
        button.textContent = "Writing links...";
        try {
          const result = await KnowledgeActionsManager.writeConnectionsToNotes(
            this.app,
            remaining
          );
          if (result.written > 0) {
            new import_obsidian4.Notice(tp(
              result.written,
              "notices.connectionsWritten",
              "notices.connectionsWritten_other",
              { count: result.written }
            ));
          }
          if (result.failed > 0) {
            new import_obsidian4.Notice(tp(
              result.failed,
              "notices.connectionsWriteFailed",
              "notices.connectionsWriteFailed_other",
              { count: result.failed }
            ));
          }
          button.textContent = "Connections added";
          button.disabled = true;
          button.classList.add("subgraph-btn-done");
          const { actionsAnalysisData, saveCacheFn } = this.options;
          if (actionsAnalysisData && saveCacheFn) {
            actionsAnalysisData.connectionsAddedAt = (/* @__PURE__ */ new Date()).toISOString();
            await saveCacheFn(actionsAnalysisData);
          }
        } catch {
          new import_obsidian4.Notice(t("notices.connectionsWriteError"));
          button.disabled = false;
          button.textContent = "Add to main graph";
        }
      })();
    });
  }
  // ─────────────────── Editing: Remove Node / Link ───────────────────
  removeNode(node) {
    node.removed = true;
    const neighborsToCheck = /* @__PURE__ */ new Set();
    for (const link of this.links) {
      const sourceId = typeof link.source === "string" ? link.source : link.source.id;
      const targetId = typeof link.target === "string" ? link.target : link.target.id;
      if (sourceId === node.id || targetId === node.id) {
        link.removed = true;
        const otherId = sourceId === node.id ? targetId : sourceId;
        neighborsToCheck.add(otherId);
      }
    }
    for (const neighborId of neighborsToCheck) {
      const hasOtherLinks = this.links.some((l) => {
        if (l.removed) return false;
        const sourceId = typeof l.source === "string" ? l.source : l.source.id;
        const targetId = typeof l.target === "string" ? l.target : l.target.id;
        return sourceId === neighborId || targetId === neighborId;
      });
      if (!hasOtherLinks) {
        const neighbor = this.nodes.find((n) => n.id === neighborId);
        if (neighbor) neighbor.removed = true;
      }
    }
    this.refreshGraph();
  }
  removeLink(link) {
    link.removed = true;
    for (const node of this.nodes) {
      if (node.removed) continue;
      const hasLinks = this.links.some((l) => {
        if (l.removed) return false;
        const sourceId = typeof l.source === "string" ? l.source : l.source.id;
        const targetId = typeof l.target === "string" ? l.target : l.target.id;
        return sourceId === node.id || targetId === node.id;
      });
      if (!hasLinks) {
        node.removed = true;
      }
    }
    this.refreshGraph();
  }
  refreshGraph() {
    const activeNodes = this.nodes.filter((n) => !n.removed);
    const activeLinks = this.links.filter((l) => !l.removed);
    for (const n of activeNodes) {
      n.degree = 0;
    }
    for (const l of activeLinks) {
      const sourceId = typeof l.source === "string" ? l.source : l.source.id;
      const targetId = typeof l.target === "string" ? l.target : l.target.id;
      const sn = activeNodes.find((n) => n.id === sourceId);
      const tn = activeNodes.find((n) => n.id === targetId);
      if (sn) sn.degree++;
      if (tn) tn.degree++;
    }
    this.simulation.nodes(activeNodes);
    this.simulation.force("link").links(activeLinks);
    const linksGroup = this.svgGroup.select(".subgraph-links");
    const linkKey = (d) => {
      const sid = typeof d.source === "string" ? d.source : d.source.id;
      const tid = typeof d.target === "string" ? d.target : d.target.id;
      return `${sid}-${tid}`;
    };
    const linksData = linksGroup.selectAll("line").data(activeLinks, linkKey);
    this.linksSelection = linksData.join(
      (enter) => enter.append("line").attr("class", "suggested-link").attr("stroke", "var(--text-accent)").attr("stroke-width", 2).attr("stroke-opacity", (d) => 0.3 + d.confidence * 0.5).attr("stroke-dasharray", "6,3").attr("marker-end", "url(#" + this.markerId + ")").on("mouseover", (event, d) => {
        this.showLinkTooltip(event, d);
        select_default2(event.currentTarget).attr("stroke-opacity", 1);
      }).on("mouseout", (event, d) => {
        this.hideTooltip();
        select_default2(event.currentTarget).attr("stroke-opacity", 0.3 + d.confidence * 0.5);
      }),
      (update) => update,
      (exit) => exit.remove()
    );
    const nodesGroup = this.svgGroup.select(".subgraph-nodes");
    const nodeKey = (d) => d.id;
    const existingNodeGroups = nodesGroup.selectAll("g.subgraph-node-group").data(activeNodes, nodeKey);
    existingNodeGroups.exit().remove();
    existingNodeGroups.select("circle").attr("r", (d) => this.getNodeRadius(d));
    this.nodesSelection = existingNodeGroups;
    this.simulation.alpha(0.5).restart();
    const counter = this.container.querySelector(".subgraph-counter");
    if (counter) this.updateCounter(counter);
  }
  // ─────────────────── Helpers ───────────────────
  resolveNodeTitle(nodeRef) {
    if (typeof nodeRef === "string") {
      const node = this.nodes.find((n) => n.id === nodeRef);
      return node?.title || nodeRef;
    }
    return nodeRef.title;
  }
  /**
   * Show structured tooltip for a link: Direction, Rationale, Confidence
   */
  showLinkTooltip(event, link) {
    const direction = `${this.resolveNodeTitle(link.source)} \u2192 ${this.resolveNodeTitle(link.target)}`;
    const rationale = link.reason;
    const confidence = `${Math.round(link.confidence * 100)}%`;
    const text = `Direction:
${direction}
Rationale:
${rationale}
Confidence:
${confidence}`;
    this.showTooltip(event, text);
  }
  showTooltip(event, text) {
    this.tooltip.classList.remove("subgraph-tooltip-hidden");
    this.tooltip.textContent = "";
    const lines = text.split("\n");
    for (let i = 0; i < lines.length; i++) {
      if (i > 0) this.tooltip.createEl("br");
      this.tooltip.appendText(lines[i]);
    }
    const rect = this.container.getBoundingClientRect();
    this.tooltip.style.setProperty("--tooltip-x", `${event.clientX - rect.left + 12}px`);
    this.tooltip.style.setProperty("--tooltip-y", `${event.clientY - rect.top - 10}px`);
  }
  hideTooltip() {
    this.tooltip.classList.add("subgraph-tooltip-hidden");
  }
  getRemainingConnections() {
    return this.links.filter((l) => !l.removed).map((l) => {
      const sourceId = typeof l.source === "string" ? l.source : l.source.id;
      const targetId = typeof l.target === "string" ? l.target : l.target.id;
      return {
        sourceId,
        targetId,
        reason: l.reason,
        confidence: l.confidence
      };
    });
  }
  updateCounter(counter) {
    const remaining = this.links.filter((l) => !l.removed).length;
    const total = this.connections.length;
    counter.textContent = `${remaining} of ${total} connections remaining`;
  }
  async openNoteInNewTab(path2) {
    if (this.options.modal) {
      this.options.modal.close();
    }
    await this.app.workspace.openLinkText(path2, "", "tab");
  }
  /**
   * Clean up the simulation when the component is destroyed
   */
  destroy() {
    if (this.simulation) {
      this.simulation.stop();
    }
  }
};
_ConnectionSubGraph.GRAPH_SCALE = 0.8;
var ConnectionSubGraph = _ConnectionSubGraph;

// src/ai/MasterAnalysisManager.ts
var import_obsidian7 = require("obsidian");

// src/services/GeminiRestClient.ts
var import_obsidian5 = require("obsidian");
var GEMINI_API_BASE = "https://generativelanguage.googleapis.com/v1beta";
function responseTextFromParts(response) {
  const parts = response.candidates?.[0]?.content?.parts;
  if (parts && parts.length > 0) {
    const textParts = parts.filter((p) => !!p.text && p.thought !== true).map((p) => p.text);
    if (textParts.length > 0) {
      return textParts.join("").trim();
    }
  }
  return "";
}
function parseErrorBody(status, body, json) {
  const err = json;
  const msg = err?.error?.message ?? body?.slice(0, 500) ?? "Unknown error";
  return `${status} ${err?.error?.status ?? ""} ${msg}`.trim();
}
async function geminiGenerateContent(params) {
  const url = `${GEMINI_API_BASE}/models/${encodeURIComponent(params.model)}:generateContent?key=${encodeURIComponent(params.apiKey)}`;
  const body = {
    contents: [{ role: "user", parts: [{ text: params.prompt }] }],
    generationConfig: params.generationConfig
  };
  const result = await (0, import_obsidian5.requestUrl)({
    url,
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify(body),
    throw: false
  });
  let json;
  try {
    json = result.json;
  } catch {
    json = void 0;
  }
  if (result.status < 200 || result.status >= 300) {
    throw new Error(parseErrorBody(result.status, result.text, json));
  }
  const response = json ?? {};
  return Object.assign(response, { text: responseTextFromParts(response) });
}

// src/ai/schemas/gemini-json-schema.ts
var Type = {
  OBJECT: "OBJECT",
  ARRAY: "ARRAY",
  STRING: "STRING",
  NUMBER: "NUMBER",
  INTEGER: "INTEGER",
  BOOLEAN: "BOOLEAN"
};

// src/ai/schemas/knowledge-network.schema.ts
function createKnowledgeNetworkSchema() {
  return {
    type: Type.OBJECT,
    properties: {
      knowledgeNetwork: {
        type: Type.OBJECT,
        description: "Knowledge network with bridges, foundations, and authorities",
        properties: {
          bridges: {
            type: Type.ARRAY,
            description: "Knowledge bridges - domains connecting disparate areas (betweenness centrality)",
            items: {
              type: Type.OBJECT,
              properties: {
                domain: { type: Type.STRING, description: "Domain name" },
                explanation: { type: Type.STRING, description: "Why this domain qualifies as a bridge" },
                topNotes: {
                  type: Type.ARRAY,
                  description: "Top 3 notes contributing to this domain",
                  items: {
                    type: Type.OBJECT,
                    properties: {
                      title: { type: Type.STRING, description: "Note title" },
                      path: { type: Type.STRING, description: "Note path" },
                      rank: { type: Type.NUMBER, description: "Centrality rank" }
                    },
                    propertyOrdering: ["title", "path", "rank"]
                  }
                },
                connections: {
                  type: Type.ARRAY,
                  items: { type: Type.STRING },
                  description: "Connected domains or concepts"
                },
                insights: { type: Type.STRING, description: "Key insights about this bridge" }
              },
              propertyOrdering: ["domain", "explanation", "topNotes", "connections", "insights"]
            }
          },
          foundations: {
            type: Type.ARRAY,
            description: "Knowledge foundations - core domains (closeness centrality)",
            items: {
              type: Type.OBJECT,
              properties: {
                domain: { type: Type.STRING, description: "Domain name" },
                explanation: { type: Type.STRING, description: "Why this domain qualifies as a foundation" },
                topNotes: {
                  type: Type.ARRAY,
                  description: "Top 3 notes contributing to this domain",
                  items: {
                    type: Type.OBJECT,
                    properties: {
                      title: { type: Type.STRING, description: "Note title" },
                      path: { type: Type.STRING, description: "Note path" },
                      rank: { type: Type.NUMBER, description: "Centrality rank" }
                    },
                    propertyOrdering: ["title", "path", "rank"]
                  }
                },
                coverage: {
                  type: Type.ARRAY,
                  items: { type: Type.STRING },
                  description: "Coverage areas"
                },
                insights: { type: Type.STRING, description: "Key insights about this foundation" }
              },
              propertyOrdering: ["domain", "explanation", "topNotes", "coverage", "insights"]
            }
          },
          authorities: {
            type: Type.ARRAY,
            description: "Knowledge authorities - influential domains (eigenvector centrality)",
            items: {
              type: Type.OBJECT,
              properties: {
                domain: { type: Type.STRING, description: "Domain name" },
                explanation: { type: Type.STRING, description: "Why this domain qualifies as an authority" },
                topNotes: {
                  type: Type.ARRAY,
                  description: "Top 3 notes contributing to this domain",
                  items: {
                    type: Type.OBJECT,
                    properties: {
                      title: { type: Type.STRING, description: "Note title" },
                      path: { type: Type.STRING, description: "Note path" },
                      rank: { type: Type.NUMBER, description: "Centrality rank" }
                    },
                    propertyOrdering: ["title", "path", "rank"]
                  }
                },
                influence: {
                  type: Type.ARRAY,
                  items: { type: Type.STRING },
                  description: "Areas of influence"
                },
                insights: { type: Type.STRING, description: "Key insights about this authority" }
              },
              propertyOrdering: ["domain", "explanation", "topNotes", "influence", "insights"]
            }
          }
        },
        propertyOrdering: ["bridges", "foundations", "authorities"]
      },
      knowledgeGaps: {
        type: Type.ARRAY,
        items: { type: Type.STRING },
        description: "Identified knowledge gaps or areas to develop"
      }
    },
    propertyOrdering: ["knowledgeNetwork", "knowledgeGaps"]
  };
}

// src/ai/schemas/vault-semantic-analysis.schema.ts
function createVaultSemanticAnalysisSchema(expectedResultCount) {
  return {
    type: Type.ARRAY,
    items: {
      type: Type.OBJECT,
      properties: {
        summary: {
          type: Type.STRING,
          description: "Two to three sentence summary of the main concept or purpose (be detailed)"
        },
        keywords: {
          type: Type.STRING,
          description: "3-6 key terms or phrases (comma-separated)"
        },
        knowledgeDomain: {
          type: Type.STRING,
          description: "DDC classification codes that best match the content (comma-separated, e.g., '0-0-4,1-5-1')"
        }
      },
      required: ["summary", "keywords", "knowledgeDomain"],
      propertyOrdering: ["summary", "keywords", "knowledgeDomain"]
    },
    minItems: expectedResultCount,
    maxItems: expectedResultCount
  };
}

// src/ai/schemas/knowledge-evolution.schema.ts
function createKnowledgeEvolutionSchema() {
  return {
    type: Type.OBJECT,
    properties: {
      timeline: {
        type: Type.OBJECT,
        description: "Timeline analysis of knowledge evolution",
        properties: {
          narrative: {
            type: Type.OBJECT,
            description: "Overall narrative of knowledge growth",
            properties: {
              title: { type: Type.STRING, description: "Narrative title" },
              content: { type: Type.STRING, description: "Narrative content" },
              keyPoints: {
                type: Type.ARRAY,
                items: { type: Type.STRING },
                description: "Key points"
              }
            },
            propertyOrdering: ["title", "content", "keyPoints"]
          },
          phases: {
            type: Type.ARRAY,
            description: "Evolution phases over time",
            items: {
              type: Type.OBJECT,
              properties: {
                period: { type: Type.STRING, description: "Time period" },
                description: { type: Type.STRING, description: "Phase description" },
                keyDomains: {
                  type: Type.ARRAY,
                  items: { type: Type.STRING },
                  description: "Key domains in this phase"
                },
                metrics: {
                  type: Type.OBJECT,
                  description: "Phase metrics",
                  properties: {
                    noteCount: { type: Type.NUMBER, description: "Note count" },
                    wordCount: { type: Type.NUMBER, description: "Word count" },
                    avgWordsPerNote: { type: Type.NUMBER, description: "Avg words per note" }
                  },
                  propertyOrdering: ["noteCount", "wordCount", "avgWordsPerNote"]
                }
              },
              propertyOrdering: ["period", "description", "keyDomains", "metrics"]
            }
          },
          trends: {
            type: Type.OBJECT,
            description: "Trend indicators",
            properties: {
              productivity: {
                type: Type.STRING,
                enum: ["increasing", "decreasing", "stable"],
                description: "Productivity trend"
              },
              diversity: {
                type: Type.STRING,
                enum: ["expanding", "narrowing", "stable"],
                description: "Diversity trend"
              },
              depth: {
                type: Type.STRING,
                enum: ["increasing", "decreasing", "stable"],
                description: "Depth trend"
              }
            },
            propertyOrdering: ["productivity", "diversity", "depth"]
          }
        },
        propertyOrdering: ["narrative", "phases", "trends"]
      },
      topicPatterns: {
        type: Type.OBJECT,
        description: "Topic exploration patterns",
        properties: {
          exploration: {
            type: Type.OBJECT,
            description: "Exploration narrative",
            properties: {
              title: { type: Type.STRING, description: "Title" },
              content: { type: Type.STRING, description: "Content" },
              keyPoints: {
                type: Type.ARRAY,
                items: { type: Type.STRING },
                description: "Key points"
              }
            },
            propertyOrdering: ["title", "content", "keyPoints"]
          },
          introductionTimeline: {
            type: Type.ARRAY,
            description: "When new domains were introduced",
            items: {
              type: Type.OBJECT,
              properties: {
                period: { type: Type.STRING, description: "Time period" },
                newDomains: {
                  type: Type.ARRAY,
                  items: { type: Type.STRING },
                  description: "New domains introduced"
                },
                acquisitionPattern: {
                  type: Type.STRING,
                  enum: ["burst", "gradual", "project-based"],
                  description: "How knowledge was acquired"
                }
              },
              propertyOrdering: ["period", "newDomains", "acquisitionPattern"]
            }
          },
          strategy: {
            type: Type.OBJECT,
            description: "Learning strategy",
            properties: {
              style: {
                type: Type.STRING,
                enum: ["depth-first", "breadth-first", "balanced"],
                description: "Exploration style"
              },
              consistency: {
                type: Type.STRING,
                enum: ["focused", "exploratory", "mixed"],
                description: "Consistency of focus"
              }
            },
            propertyOrdering: ["style", "consistency"]
          }
        },
        propertyOrdering: ["exploration", "introductionTimeline", "strategy"]
      },
      focusShift: {
        type: Type.OBJECT,
        description: "Focus shift analysis",
        properties: {
          narrative: {
            type: Type.OBJECT,
            description: "Narrative of focus changes",
            properties: {
              title: { type: Type.STRING, description: "Title" },
              content: { type: Type.STRING, description: "Content" },
              keyPoints: {
                type: Type.ARRAY,
                items: { type: Type.STRING },
                description: "Key points"
              }
            },
            propertyOrdering: ["title", "content", "keyPoints"]
          },
          shifts: {
            type: Type.ARRAY,
            description: "Focus shifts over time",
            items: {
              type: Type.OBJECT,
              properties: {
                period: { type: Type.STRING, description: "Time period" },
                type: {
                  type: Type.STRING,
                  enum: ["major", "minor", "gradual"],
                  description: "Shift magnitude"
                },
                newAreas: {
                  type: Type.ARRAY,
                  items: { type: Type.STRING },
                  description: "New focus areas"
                },
                increasedFocus: {
                  type: Type.ARRAY,
                  items: { type: Type.STRING },
                  description: "Areas of increased focus"
                },
                decreasedFocus: {
                  type: Type.ARRAY,
                  items: { type: Type.STRING },
                  description: "Areas of decreased focus"
                },
                consistentAreas: {
                  type: Type.ARRAY,
                  items: { type: Type.STRING },
                  description: "Consistently focused areas"
                },
                trigger: { type: Type.STRING, description: "What triggered the shift" }
              },
              propertyOrdering: ["period", "type", "newAreas", "increasedFocus", "decreasedFocus", "consistentAreas", "trigger"]
            }
          },
          patterns: {
            type: Type.OBJECT,
            description: "Shift patterns",
            properties: {
              frequency: {
                type: Type.STRING,
                enum: ["frequent", "occasional", "rare"],
                description: "How often focus shifts"
              },
              direction: {
                type: Type.STRING,
                enum: ["expanding", "pivoting", "deepening"],
                description: "Direction of shifts"
              }
            },
            propertyOrdering: ["frequency", "direction"]
          }
        },
        propertyOrdering: ["narrative", "shifts", "patterns"]
      },
      insights: {
        type: Type.ARRAY,
        description: "Key insights from evolution analysis",
        items: {
          type: Type.OBJECT,
          properties: {
            title: { type: Type.STRING, description: "Insight title" },
            content: { type: Type.STRING, description: "Insight content" },
            keyPoints: {
              type: Type.ARRAY,
              items: { type: Type.STRING },
              description: "Key points"
            }
          },
          propertyOrdering: ["title", "content", "keyPoints"]
        }
      }
    },
    propertyOrdering: ["timeline", "topicPatterns", "focusShift", "insights"]
  };
}

// src/ai/schemas/recommended-actions.schema.ts
function createRecommendedActionsSchema() {
  return {
    type: Type.OBJECT,
    properties: {
      maintenance: {
        type: Type.ARRAY,
        description: "Notes needing maintenance or updates",
        items: {
          type: Type.OBJECT,
          properties: {
            noteId: { type: Type.STRING, description: "Note identifier" },
            title: { type: Type.STRING, description: "Note title" },
            reason: { type: Type.STRING, description: "Why maintenance is needed" },
            priority: {
              type: Type.STRING,
              enum: ["high", "medium", "low"],
              description: "Priority level"
            },
            action: { type: Type.STRING, description: "Recommended action" }
          },
          propertyOrdering: ["noteId", "title", "reason", "priority", "action"]
        }
      },
      connections: {
        type: Type.ARRAY,
        description: "Suggested connections between notes",
        items: {
          type: Type.OBJECT,
          properties: {
            sourceId: { type: Type.STRING, description: "Source note ID" },
            targetId: { type: Type.STRING, description: "Target note ID" },
            reason: { type: Type.STRING, description: "Why these notes should be connected" },
            confidence: { type: Type.NUMBER, description: "Confidence score 0-1" }
          },
          propertyOrdering: ["sourceId", "targetId", "reason", "confidence"]
        }
      },
      learningPaths: {
        type: Type.ARRAY,
        description: "Suggested learning paths through notes",
        items: {
          type: Type.OBJECT,
          properties: {
            title: { type: Type.STRING, description: "Path title" },
            description: { type: Type.STRING, description: "Path description" },
            noteIds: {
              type: Type.ARRAY,
              items: { type: Type.STRING },
              description: "Ordered note IDs in the path"
            },
            rationale: { type: Type.STRING, description: "Why this path is recommended" }
          },
          propertyOrdering: ["title", "description", "noteIds", "rationale"]
        }
      },
      organization: {
        type: Type.ARRAY,
        description: "Organization suggestions",
        items: {
          type: Type.OBJECT,
          properties: {
            type: {
              type: Type.STRING,
              enum: ["tag", "folder", "structure"],
              description: "Type of organization"
            },
            suggestion: { type: Type.STRING, description: "Organization suggestion" },
            affectedNotes: {
              type: Type.ARRAY,
              items: { type: Type.STRING },
              description: "Note IDs affected"
            }
          },
          propertyOrdering: ["type", "suggestion", "affectedNotes"]
        }
      }
    },
    propertyOrdering: ["maintenance", "connections", "learningPaths", "organization"]
  };
}

// src/utils/GeminiErrorUtils.ts
var SemanticAnalysisError = class extends Error {
  constructor(message, errorType, model) {
    super(message);
    this.errorType = errorType;
    this.model = model;
    this.name = "SemanticAnalysisError";
  }
};
function classifyGeminiError(message) {
  const lower2 = message.toLowerCase();
  const is429 = message.includes("429") || lower2.includes("rate limit") || lower2.includes("resource exhausted");
  const isQuota = lower2.includes("per day") || lower2.includes("perday") || lower2.includes("rpd") || lower2.includes("daily") || lower2.includes("quota") || lower2.includes("generate_content_free_tier_requests") || lower2.includes("requestsperday");
  if (is429 && isQuota) return "quota_exhausted";
  if (is429) return "rate_limit";
  return "other";
}
function getUserFriendlyMessage(error) {
  if (error instanceof SemanticAnalysisError) {
    switch (error.errorType) {
      case "quota_exhausted":
        return t("errors.quotaExhausted");
      case "rate_limit":
        return t("errors.rateLimit");
      default:
        return error.message;
    }
  }
  return error.message;
}

// src/services/AIModelService.ts
var AIModelService = class {
  constructor(app, settings) {
    // Gemini 3 Flash: RPM 5 -> 12s between requests
    this.ADVANCED_RATE_LIMIT_DELAY = 12e3;
    this.MODEL_NAME = "gemini-3-flash-preview";
    this.SEMANTIC_MODEL_NAME = "gemini-3.1-flash-lite-preview";
    this.app = app;
    this.settings = settings;
  }
  /** Window from app workspace (avoids global for pop-out compatibility) */
  get win() {
    return this.app.workspace.containerEl.ownerDocument.defaultView;
  }
  // Default when no modelOverride
  getModelName() {
    return this.MODEL_NAME;
  }
  getSemanticModelName() {
    return this.SEMANTIC_MODEL_NAME;
  }
  /**
   * Update settings (useful when settings change)
   */
  updateSettings(settings) {
    this.settings = settings;
  }
  getApiKey() {
    const key = this.settings?.geminiApiKey?.trim();
    if (!key) {
      throw new Error("Gemini API key not configured. Please configure your API key in settings.");
    }
    return key;
  }
  /**
   * Structured output analysis using the configured model with response schema
   * This method ensures reliable JSON responses by using the structured output feature
   */
  async generateStructuredAnalysis(prompt, responseSchema, maxOutputTokens = 8192 * 2, temperature = 0.3, topP = 0.72) {
    const apiKey = this.getApiKey();
    try {
      const response = await geminiGenerateContent({
        apiKey,
        model: this.MODEL_NAME,
        prompt,
        generationConfig: {
          responseMimeType: "application/json",
          responseSchema,
          temperature,
          topP,
          maxOutputTokens,
          thinkingConfig: {
            thinkingBudget: -1
          }
        }
      });
      const tokenUsage = {
        promptTokens: response.usageMetadata?.promptTokenCount || 0,
        candidatesTokens: response.usageMetadata?.candidatesTokenCount || 0,
        totalTokens: response.usageMetadata?.totalTokenCount || 0
      };
      const result = response.text || "";
      if (!result) {
        throw new Error(
          "Empty response from Gemini API - check API key, request format, or content policy restrictions"
        );
      }
      let parsedResult;
      try {
        parsedResult = JSON.parse(result);
      } catch (parseError) {
        throw new Error(`Failed to parse structured response: ${parseError.message}`);
      }
      return {
        result: parsedResult,
        tokenUsage
      };
    } catch (error) {
      const errorMessage = error.message;
      const errorType = classifyGeminiError(errorMessage);
      if (errorType === "quota_exhausted") {
        throw new SemanticAnalysisError(errorMessage, "quota_exhausted", this.MODEL_NAME);
      }
      if (errorType === "rate_limit") {
        await new Promise((resolve) => this.win.setTimeout(resolve, this.ADVANCED_RATE_LIMIT_DELAY));
        return this.generateStructuredAnalysis(
          prompt,
          responseSchema,
          maxOutputTokens,
          temperature,
          topP
        );
      }
      throw error;
    }
  }
  /**
   * Semantic analysis using Gemini for vault batch processing.
   * Uses native structured output (responseMimeType + responseSchema).
   * @param modelOverride When set, use this model instead of SEMANTIC_MODEL_NAME
   */
  async generateSemanticAnalysis(prompt, responseSchema, maxOutputTokens = 8192, temperature = 0.3, topP = 0.72, modelOverride) {
    const apiKey = this.getApiKey();
    const model = modelOverride ?? this.SEMANTIC_MODEL_NAME;
    try {
      const response = await geminiGenerateContent({
        apiKey,
        model,
        prompt,
        generationConfig: {
          responseMimeType: "application/json",
          responseSchema,
          temperature,
          topP,
          maxOutputTokens,
          thinkingConfig: {
            thinkingBudget: 0
          }
        }
      });
      const tokenUsage = {
        promptTokens: response.usageMetadata?.promptTokenCount || 0,
        candidatesTokens: response.usageMetadata?.candidatesTokenCount || 0,
        totalTokens: response.usageMetadata?.totalTokenCount || 0
      };
      const result = response.text?.trim() || "";
      if (!result) {
        throw new Error(
          "Empty response from Gemini API - check API key, request format, or content policy restrictions"
        );
      }
      let parsedResult;
      try {
        parsedResult = JSON.parse(result);
      } catch (parseError) {
        const msg = `Failed to parse semantic response: ${parseError.message}`;
        throw new SemanticAnalysisError(msg, "json_parse", model);
      }
      return {
        result: parsedResult,
        tokenUsage
      };
    } catch (error) {
      if (error instanceof SemanticAnalysisError) throw error;
      const errorMessage = error.message;
      const errorType = classifyGeminiError(errorMessage);
      if (errorType === "quota_exhausted") {
        throw new SemanticAnalysisError(errorMessage, "quota_exhausted", model);
      }
      throw new SemanticAnalysisError(errorMessage, errorType, model);
    }
  }
  createKnowledgeNetworkSchema() {
    return createKnowledgeNetworkSchema();
  }
  createVaultSemanticAnalysisSchema(expectedResultCount) {
    return createVaultSemanticAnalysisSchema(expectedResultCount);
  }
  createKnowledgeEvolutionSchema() {
    return createKnowledgeEvolutionSchema();
  }
  createRecommendedActionsSchema() {
    return createRecommendedActionsSchema();
  }
  async waitForRateLimit() {
    await new Promise((resolve) => this.win.setTimeout(resolve, this.ADVANCED_RATE_LIMIT_DELAY));
  }
  calculateDelay(_requestCount) {
    return this.ADVANCED_RATE_LIMIT_DELAY;
  }
};

// src/ai/promptLanguage.ts
function buildContextSampleFromVaultRows(rows, maxRows = 80) {
  return rows.slice(0, maxRows).map((r) => `${r.summary ?? ""} ${r.keywords ?? ""}`).join(" ");
}
function buildContextSampleFromNoteContents(rows, maxChars = 12e3) {
  let sample = "";
  for (const row of rows) {
    if (sample.length >= maxChars) break;
    sample += `${row.content} `;
  }
  return sample.slice(0, maxChars);
}
var CJK_REGEX = /[\u4e00-\u9fff\u3400-\u4dbf\uf900-\ufaff]/g;
function cjkRatio(text) {
  if (!text.length) return 0;
  const matches = text.match(CJK_REGEX);
  return (matches?.length ?? 0) / text.length;
}
function resolveAiOutputLanguage(settings, contextSample) {
  const preference = settings.aiResponseLanguage;
  if (preference === "en") return "en";
  if (preference === "zh-Hans") return "zh-Hans";
  const sample = contextSample.trim();
  if (sample.length > 0) {
    return cjkRatio(sample) >= 0.15 ? "zh-Hans" : "en";
  }
  const obsidianLocale = getObsidianLocale();
  return obsidianLocale === "zh-Hans" ? "zh-Hans" : "en";
}
function buildLanguagePromptSection(settings, contextSample) {
  const lang = resolveAiOutputLanguage(settings, contextSample);
  if (lang === "zh-Hans") {
    return `## Output language
Write every user-visible string in the JSON response in Simplified Chinese (\u7B80\u4F53\u4E2D\u6587), including summaries, keywords, titles, descriptions, keyPoints, and recommendations. Use the same language for all notes in the batch. Keep JSON property names and schema enum tokens in English.`;
  }
  return `## Output language
Write every user-visible string in the JSON response in English, including summaries, keywords, titles, descriptions, keyPoints, and recommendations. Use the same language for all notes in the batch. Keep JSON property names and schema enum tokens in English.`;
}

// src/utils/KDECalculationService.ts
var KDECalculationService = class {
  /**
   * Calculate KDE distributions for all centrality types
   */
  calculateKDEDistributions(analysisData) {
    const betweennessValues = this.extractCentralityValues(analysisData, "betweennessCentrality");
    const closenessValues = this.extractCentralityValues(analysisData, "closenessCentrality");
    const eigenvectorValues = this.extractCentralityValues(analysisData, "eigenvectorCentrality");
    const betweennessKDE = this.calculateKDE(betweennessValues);
    const closenessKDE = this.calculateKDE(closenessValues);
    const eigenvectorKDE = this.calculateKDE(eigenvectorValues);
    return {
      betweenness: betweennessKDE,
      closeness: closenessKDE,
      eigenvector: eigenvectorKDE
    };
  }
  /**
   * Extract centrality values from vault analysis data
   * Filters out zero and null values for better KDE estimation
   */
  extractCentralityValues(analysisData, centralityType, includeZeros = false) {
    const values = [];
    for (const result of analysisData.results) {
      if (result.graphMetrics && result.graphMetrics[centralityType] !== void 0) {
        const value = result.graphMetrics[centralityType];
        if (value !== null && value !== void 0 && (includeZeros || value > 0)) {
          values.push(value);
        }
      }
    }
    return values;
  }
  /**
   * Count all notes that have a specific centrality metric defined (including zeros)
   */
  countNotesWithMetric(analysisData, centralityType) {
    let count2 = 0;
    for (const result of analysisData.results) {
      if (result.graphMetrics && result.graphMetrics[centralityType] !== void 0) {
        const value = result.graphMetrics[centralityType];
        if (value !== null && value !== void 0) {
          count2++;
        }
      }
    }
    return count2;
  }
  /**
   * Calculate KDE for a set of values
   */
  calculateKDE(values) {
    if (values.length === 0) {
      return { x: [], y: [] };
    }
    if (values.length === 1) {
      return { x: [values[0]], y: [1] };
    }
    const kde = kernelDensityEstimation(values);
    const min8 = Math.min(...values);
    const max8 = Math.max(...values);
    const range2 = max8 - min8;
    const padding = range2 * 0.1;
    const start2 = Math.max(0, min8 - padding);
    const end = max8 + padding;
    const numPoints = 100;
    const x3 = [];
    const y3 = [];
    for (let i = 0; i < numPoints; i++) {
      const point2 = start2 + (end - start2) * (i / (numPoints - 1));
      x3.push(point2);
      y3.push(kde(point2));
    }
    return { x: x3, y: y3 };
  }
  /**
   * Generate summary statistics from KDE results for AI context
   */
  getKDESummaryStats(kdeResult) {
    const summaries = [];
    summaries.push("=== Betweenness Centrality Distribution ===");
    summaries.push(this.analyzeKDEDistribution(kdeResult.betweenness, "betweenness"));
    summaries.push("\n=== Closeness Centrality Distribution ===");
    summaries.push(this.analyzeKDEDistribution(kdeResult.closeness, "closeness"));
    summaries.push("\n=== Eigenvector Centrality Distribution ===");
    summaries.push(this.analyzeKDEDistribution(kdeResult.eigenvector, "eigenvector"));
    return summaries.join("\n");
  }
  /**
   * Analyze a single KDE distribution and return descriptive statistics
   */
  analyzeKDEDistribution(kdeData, centralityType) {
    if (kdeData.x.length === 0 || kdeData.y.length === 0) {
      return `No ${centralityType} centrality data available.`;
    }
    const stats = [];
    const maxDensityIndex = kdeData.y.indexOf(Math.max(...kdeData.y));
    const peakLocation = kdeData.x[maxDensityIndex];
    const peakDensity = kdeData.y[maxDensityIndex];
    stats.push(`Peak density location: ${peakLocation.toFixed(4)} (density: ${peakDensity.toFixed(4)})`);
    const meanX = kdeData.x.reduce((a2, b) => a2 + b, 0) / kdeData.x.length;
    const variance2 = kdeData.x.reduce((sum2, x3) => sum2 + Math.pow(x3 - meanX, 2), 0) / kdeData.x.length;
    const stdDev = Math.sqrt(variance2);
    stats.push(`Mean: ${meanX.toFixed(4)}, Standard Deviation: ${stdDev.toFixed(4)}`);
    const peakCount = this.countPeaks(kdeData.y);
    if (peakCount === 1) {
      stats.push("Distribution shape: Unimodal (single peak)");
    } else if (peakCount === 2) {
      stats.push("Distribution shape: Bimodal (two peaks)");
    } else if (peakCount > 2) {
      stats.push(`Distribution shape: Multimodal (${peakCount} peaks)`);
    }
    const coefficientOfVariation = stdDev / meanX;
    if (coefficientOfVariation < 0.5) {
      stats.push("Concentration: High (low variance, concentrated distribution)");
    } else if (coefficientOfVariation < 1) {
      stats.push("Concentration: Moderate (moderate variance)");
    } else {
      stats.push("Concentration: Low (high variance, spread out distribution)");
    }
    return stats.join("\n");
  }
  /**
   * Count the number of peaks in a density distribution
   */
  countPeaks(y3) {
    if (y3.length < 3) return y3.length;
    let peakCount = 0;
    const threshold2 = Math.max(...y3) * 0.3;
    for (let i = 1; i < y3.length - 1; i++) {
      if (y3[i] > y3[i - 1] && y3[i] > y3[i + 1] && y3[i] > threshold2) {
        peakCount++;
      }
    }
    return Math.max(1, peakCount);
  }
  /**
   * Calculate histogram distributions with 0.05 interval bins
   * Dynamically adjusts x-axis range based on actual data maximum
   */
  calculateHistogramDistributions(analysisData) {
    const betweennessValues = this.extractCentralityValues(analysisData, "betweennessCentrality");
    const closenessValues = this.extractCentralityValues(analysisData, "closenessCentrality");
    const eigenvectorValues = this.extractCentralityValues(analysisData, "eigenvectorCentrality");
    const allValues = [...betweennessValues, ...closenessValues, ...eigenvectorValues];
    const maxValue = allValues.length > 0 ? Math.max(...allValues) : 0;
    const calculateUpperBound = (max8) => {
      if (max8 <= 0) return 0.1;
      if (max8 >= 1) return 1;
      const roundedTo05 = Math.ceil(max8 * 20) / 20;
      const roundedTo10 = Math.ceil(max8 * 10) / 10;
      if (roundedTo10 - max8 <= 0.05) {
        return roundedTo10;
      }
      return roundedTo05;
    };
    const upperBound = calculateUpperBound(maxValue);
    const binSize = 0.01;
    const numBins = Math.ceil(upperBound / binSize);
    const bins = [];
    for (let i = 0; i < numBins; i++) {
      const min8 = i * binSize;
      const max8 = Math.min((i + 1) * binSize, upperBound);
      bins.push({
        range: `${min8.toFixed(2)}-${max8.toFixed(2)}`,
        min: min8,
        max: max8,
        betweenness: 0,
        closeness: 0,
        eigenvector: 0
      });
    }
    const countInBin = (value) => {
      if (value < 0) return 0;
      if (value >= upperBound) return numBins - 1;
      return Math.min(Math.floor(value / binSize), numBins - 1);
    };
    betweennessValues.forEach((value) => {
      const binIndex = countInBin(value);
      bins[binIndex].betweenness++;
    });
    closenessValues.forEach((value) => {
      const binIndex = countInBin(value);
      bins[binIndex].closeness++;
    });
    eigenvectorValues.forEach((value) => {
      const binIndex = countInBin(value);
      bins[binIndex].eigenvector++;
    });
    return {
      bins,
      totals: {
        betweenness: betweennessValues.length,
        closeness: closenessValues.length,
        eigenvector: eigenvectorValues.length
      },
      maxValue,
      upperBound
    };
  }
  /**
   * Generate comprehensive statistics for AI context
   * Includes basic stats, percentiles, distribution shape, KDE insights, and interpretation
   */
  getComprehensiveStats(analysisData) {
    const summaries = [];
    const kdeResults = this.calculateKDEDistributions(analysisData);
    const centralityTypes = [
      { name: "Betweenness", key: "betweennessCentrality", kdeData: kdeResults.betweenness },
      { name: "Closeness", key: "closenessCentrality", kdeData: kdeResults.closeness },
      { name: "Eigenvector", key: "eigenvectorCentrality", kdeData: kdeResults.eigenvector }
    ];
    for (const { name, key, kdeData } of centralityTypes) {
      summaries.push(`
=== ${name} Centrality Analysis ===`);
      const values = this.extractCentralityValues(analysisData, key);
      if (values.length === 0) {
        summaries.push(`No ${name.toLowerCase()} centrality data available.`);
        continue;
      }
      const count2 = values.length;
      const min8 = Math.min(...values);
      const max8 = Math.max(...values);
      const mean2 = mean(values);
      const median2 = median(values);
      const stdDev = standardDeviation(values);
      summaries.push(`Basic Stats: N=${count2}, Mean=${mean2.toFixed(4)}, Median=${median2.toFixed(4)}, StdDev=${stdDev.toFixed(4)}`);
      summaries.push(`Range: Min=${min8.toFixed(4)}, Max=${max8.toFixed(4)}`);
      const percentiles = [10, 25, 50, 75, 90, 95];
      const sortedValues = values.slice().sort((a2, b) => a2 - b);
      const percentileValues = percentiles.map((p) => {
        try {
          return quantileSorted(sortedValues, p / 100);
        } catch {
          return quantile(values, p / 100);
        }
      });
      summaries.push(`Percentiles: P10=${percentileValues[0].toFixed(4)}, P25=${percentileValues[1].toFixed(4)}, P50=${percentileValues[2].toFixed(4)}, P75=${percentileValues[3].toFixed(4)}, P90=${percentileValues[4].toFixed(4)}, P95=${percentileValues[5].toFixed(4)}`);
      let skewness;
      let kurtosis;
      try {
        skewness = sampleSkewness(values);
        kurtosis = sampleKurtosis(values);
      } catch {
        skewness = this.calculateSkewness(values, mean2, stdDev);
        kurtosis = this.calculateKurtosis(values, mean2, stdDev);
      }
      const skewnessDesc = skewness > 0.5 ? "Right-skewed" : skewness < -0.5 ? "Left-skewed" : "Symmetric";
      const kurtosisDesc = kurtosis > 3 ? "Heavy-tailed" : kurtosis < 3 ? "Light-tailed" : "Normal-tailed";
      summaries.push(`Distribution: ${skewnessDesc} (skewness=${skewness.toFixed(2)}), ${kurtosisDesc} (kurtosis=${kurtosis.toFixed(2)})`);
      if (kdeData.x.length > 0 && kdeData.y.length > 0) {
        const maxDensityIndex = kdeData.y.indexOf(Math.max(...kdeData.y));
        const peakLocation = kdeData.x[maxDensityIndex];
        const peakCount = this.countPeaks(kdeData.y);
        const modality = peakCount === 1 ? "unimodal" : peakCount === 2 ? "bimodal" : `multimodal (${peakCount} peaks)`;
        summaries.push(`KDE Peak: ${peakLocation.toFixed(4)} (${modality})`);
      }
      const interpretation = this.generateInterpretation(name, mean2, median2, stdDev, skewness, percentileValues);
      summaries.push(`Interpretation: ${interpretation}`);
    }
    return summaries.join("\n");
  }
  /**
   * Calculate skewness manually
   */
  calculateSkewness(values, mean2, stdDev) {
    if (values.length < 3 || stdDev === 0) return 0;
    const n = values.length;
    const sum2 = values.reduce((acc, val) => {
      const diff = (val - mean2) / stdDev;
      return acc + diff * diff * diff;
    }, 0);
    return n / ((n - 1) * (n - 2)) * sum2;
  }
  /**
   * Calculate kurtosis manually
   */
  calculateKurtosis(values, mean2, stdDev) {
    if (values.length < 4 || stdDev === 0) return 0;
    const n = values.length;
    const sum2 = values.reduce((acc, val) => {
      const diff = (val - mean2) / stdDev;
      return acc + diff * diff * diff * diff;
    }, 0);
    return n * (n + 1) / ((n - 1) * (n - 2) * (n - 3)) * sum2 - 3 * (n - 1) * (n - 1) / ((n - 2) * (n - 3));
  }
  /**
   * Generate plain language interpretation of centrality distribution
   * Always generates exactly 3 sentences for consistent length
   */
  generateInterpretation(centralityName, mean2, median2, stdDev, skewness, percentiles) {
    const interpretations = [];
    const centralityContext = {
      "Betweenness": "bridges",
      "Closeness": "foundations",
      "Eigenvector": "authorities"
    };
    const context = centralityContext[centralityName] || "nodes";
    const coefficientOfVariation = stdDev / mean2;
    if (coefficientOfVariation < 0.3) {
      interpretations.push(`Most notes have similar ${centralityName.toLowerCase()} scores (highly concentrated)`);
    } else if (coefficientOfVariation < 0.7) {
      interpretations.push(`Moderate variation in ${centralityName.toLowerCase()} scores`);
    } else {
      interpretations.push(`Wide variation in ${centralityName.toLowerCase()} scores (highly dispersed)`);
    }
    if (skewness > 1) {
      interpretations.push(`Most notes have low ${centralityName.toLowerCase()} (few high-value ${context})`);
    } else if (skewness < -1) {
      interpretations.push(`Most notes have high ${centralityName.toLowerCase()} (few low-value ${context})`);
    } else {
      interpretations.push(`Distribution shows balanced spread across score ranges`);
    }
    const p75 = percentiles[3];
    const p25 = percentiles[1];
    const iqr = p75 - p25;
    if (iqr < mean2 * 0.2) {
      interpretations.push(`Scores are tightly clustered around the median`);
    } else if (iqr > mean2 * 0.8) {
      interpretations.push(`Significant spread in scores, indicating diverse network roles`);
    } else {
      interpretations.push(`Score distribution shows moderate variability`);
    }
    return interpretations.join(". ") + ".";
  }
  /**
   * Histogram + structured stats in one KDE pass (for derivation cache and UI).
   */
  computeCentralityInsights(analysisData) {
    const histogram = this.calculateHistogramDistributions(analysisData);
    const kdeResults = this.calculateKDEDistributions(analysisData);
    const stats = this.getStructuredStatsFromKDE(analysisData, kdeResults);
    return { histogram, stats };
  }
  /**
   * Generate structured statistics for UI display
   * Returns structured data instead of text string
   */
  getStructuredStats(analysisData, precomputedKde) {
    const kdeResults = precomputedKde ?? this.calculateKDEDistributions(analysisData);
    return this.getStructuredStatsFromKDE(analysisData, kdeResults);
  }
  getStructuredStatsFromKDE(analysisData, kdeResults) {
    const centralityTypes = [
      { name: "Betweenness", key: "betweennessCentrality", kdeData: kdeResults.betweenness, resultKey: "betweenness" },
      { name: "Closeness", key: "closenessCentrality", kdeData: kdeResults.closeness, resultKey: "closeness" },
      { name: "Eigenvector", key: "eigenvectorCentrality", kdeData: kdeResults.eigenvector, resultKey: "eigenvector" }
    ];
    const result = {
      betweenness: null,
      closeness: null,
      eigenvector: null
    };
    for (const { name, key, kdeData, resultKey } of centralityTypes) {
      const totalCount = this.countNotesWithMetric(analysisData, key);
      if (totalCount === 0) {
        continue;
      }
      const allValues = this.extractCentralityValues(analysisData, key, true);
      const values = this.extractCentralityValues(analysisData, key, false);
      const count2 = totalCount;
      const min8 = allValues.length > 0 ? Math.min(...allValues) : 0;
      const max8 = allValues.length > 0 ? Math.max(...allValues) : 0;
      const mean2 = values.length > 0 ? mean(values) : 0;
      const median2 = values.length > 0 ? median(values) : 0;
      const stdDev = values.length > 0 ? standardDeviation(values) : 0;
      let skewness = 0;
      let skewnessDesc = "Symmetric";
      if (values.length > 0) {
        try {
          skewness = sampleSkewness(values);
        } catch {
          skewness = this.calculateSkewness(values, mean2, stdDev);
        }
        skewnessDesc = skewness > 0.5 ? "Right-skewed" : skewness < -0.5 ? "Left-skewed" : "Symmetric";
      }
      let modality = "unimodal";
      if (kdeData.x.length > 0 && kdeData.y.length > 0) {
        const peakCount = this.countPeaks(kdeData.y);
        modality = peakCount === 1 ? "unimodal" : peakCount === 2 ? "bimodal" : `multimodal (${peakCount} peaks)`;
      }
      const percentiles = [10, 25, 50, 75, 90, 95];
      const percentileValues = [];
      if (values.length > 0) {
        const sortedValues = values.slice().sort((a2, b) => a2 - b);
        percentileValues.push(...percentiles.map((p) => {
          try {
            return quantileSorted(sortedValues, p / 100);
          } catch {
            return quantile(values, p / 100);
          }
        }));
      } else {
        percentileValues.push(...percentiles.map(() => 0));
      }
      const interpretation = this.generateInterpretation(name, mean2, median2, stdDev, skewness, percentileValues);
      result[resultKey] = {
        name,
        count: count2,
        mean: mean2,
        median: median2,
        range: { min: min8, max: max8 },
        distribution: skewnessDesc,
        modality,
        interpretation
      };
    }
    return result;
  }
};

// src/utils/ConnectivityAnalysisService.ts
var import_obsidian6 = require("obsidian");
var ConnectivityAnalysisService = class {
  /**
   * Get comprehensive connectivity statistics and patterns
   */
  getConnectivityStats(app, analysisData) {
    const linkStats = this.computeLinkStats(app, analysisData);
    const patterns = this.identifyPatterns(linkStats, analysisData);
    const notesWithLinks = linkStats.filter((n) => n.totalLinks > 0);
    const totalOutbound = linkStats.reduce((sum2, n) => sum2 + n.outboundLinks, 0);
    const totalInbound = linkStats.reduce((sum2, n) => sum2 + n.inboundLinks, 0);
    return {
      totalNotes: linkStats.length,
      notesWithLinks: notesWithLinks.length,
      totalOutboundLinks: totalOutbound,
      totalInboundLinks: totalInbound,
      avgOutboundLinks: notesWithLinks.length > 0 ? totalOutbound / notesWithLinks.length : 0,
      avgInboundLinks: notesWithLinks.length > 0 ? totalInbound / notesWithLinks.length : 0,
      patterns
    };
  }
  /**
   * Generate comprehensive connectivity summary for AI context
   * Similar to KDECalculationService.getComprehensiveStats()
   */
  getComprehensiveConnectivitySummary(app, analysisData) {
    const stats = this.getConnectivityStats(app, analysisData);
    const sections = [];
    sections.push("=== CONNECTIVITY OVERVIEW ===");
    sections.push(`Total Notes: ${stats.totalNotes}`);
    sections.push(`Notes with Links: ${stats.notesWithLinks}`);
    sections.push(`Total Outbound Links: ${stats.totalOutboundLinks}`);
    sections.push(`Total Inbound Links: ${stats.totalInboundLinks}`);
    sections.push(`Average Outbound Links: ${stats.avgOutboundLinks.toFixed(2)}`);
    sections.push(`Average Inbound Links: ${stats.avgInboundLinks.toFixed(2)}`);
    sections.push("");
    if (stats.patterns.integrationOpportunities.length > 0) {
      sections.push("=== INTEGRATION OPPORTUNITIES ===");
      sections.push(`Notes with high outbound links but low inbound links (need incoming connections): ${stats.patterns.integrationOpportunities.length}`);
      sections.push("Top integration opportunities:");
      stats.patterns.integrationOpportunities.slice(0, 15).forEach((note, index2) => {
        sections.push(`  ${index2 + 1}. ${note.title} (${note.path})`);
        sections.push(`     Outbound: ${note.outboundLinks}, Inbound: ${note.inboundLinks}, Ratio: ${note.linkRatio.toFixed(2)}`);
      });
      if (stats.patterns.integrationOpportunities.length > 15) {
        sections.push(`  ... and ${stats.patterns.integrationOpportunities.length - 15} more`);
      }
      sections.push("");
    }
    if (stats.patterns.isolatedNotes.length > 0) {
      sections.push("=== ISOLATED NOTES ===");
      sections.push(`Notes with low connectivity (few links in both directions): ${stats.patterns.isolatedNotes.length}`);
      sections.push("Top isolated notes:");
      stats.patterns.isolatedNotes.slice(0, 10).forEach((note, index2) => {
        sections.push(`  ${index2 + 1}. ${note.title} (${note.path})`);
        sections.push(`     Outbound: ${note.outboundLinks}, Inbound: ${note.inboundLinks}`);
      });
      if (stats.patterns.isolatedNotes.length > 10) {
        sections.push(`  ... and ${stats.patterns.isolatedNotes.length - 10} more`);
      }
      sections.push("");
    }
    if (stats.patterns.hubNotes.length > 0) {
      sections.push("=== HUB NOTES ===");
      sections.push(`Well-connected notes (high both inbound and outbound): ${stats.patterns.hubNotes.length}`);
      sections.push("Top hub notes:");
      stats.patterns.hubNotes.slice(0, 10).forEach((note, index2) => {
        sections.push(`  ${index2 + 1}. ${note.title} (${note.path})`);
        sections.push(`     Outbound: ${note.outboundLinks}, Inbound: ${note.inboundLinks}`);
      });
      if (stats.patterns.hubNotes.length > 10) {
        sections.push(`  ... and ${stats.patterns.hubNotes.length - 10} more`);
      }
      sections.push("");
    }
    if (stats.patterns.orphanNotes.length > 0) {
      sections.push("=== ORPHAN NOTES ===");
      sections.push(`Notes with zero links (urgent attention needed): ${stats.patterns.orphanNotes.length}`);
      sections.push("Orphan notes:");
      stats.patterns.orphanNotes.slice(0, 15).forEach((note, index2) => {
        sections.push(`  ${index2 + 1}. ${note.title} (${note.path})`);
      });
      if (stats.patterns.orphanNotes.length > 15) {
        sections.push(`  ... and ${stats.patterns.orphanNotes.length - 15} more`);
      }
      sections.push("");
    }
    if (stats.patterns.bridgeTypeNotes.length > 0) {
      sections.push("=== BRIDGE-TYPE NOTES ===");
      sections.push(`Notes that connect different areas (high betweenness, low eigenvector): ${stats.patterns.bridgeTypeNotes.length}`);
      sections.push("Top bridge-type notes:");
      stats.patterns.bridgeTypeNotes.slice(0, 10).forEach((note, index2) => {
        sections.push(`  ${index2 + 1}. ${note.title} (${note.path})`);
      });
      if (stats.patterns.bridgeTypeNotes.length > 10) {
        sections.push(`  ... and ${stats.patterns.bridgeTypeNotes.length - 10} more`);
      }
      sections.push("");
    }
    if (stats.patterns.authorityTypeNotes.length > 0) {
      sections.push("=== AUTHORITY-TYPE NOTES ===");
      sections.push(`Influential notes (high eigenvector, low betweenness): ${stats.patterns.authorityTypeNotes.length}`);
      sections.push("Top authority-type notes:");
      stats.patterns.authorityTypeNotes.slice(0, 10).forEach((note, index2) => {
        sections.push(`  ${index2 + 1}. ${note.title} (${note.path})`);
      });
      if (stats.patterns.authorityTypeNotes.length > 10) {
        sections.push(`  ... and ${stats.patterns.authorityTypeNotes.length - 10} more`);
      }
      sections.push("");
    }
    if (stats.patterns.balancedNotes.length > 0) {
      sections.push("=== BALANCED KEY NOTES ===");
      sections.push(`Critical notes (high both betweenness and eigenvector): ${stats.patterns.balancedNotes.length}`);
      sections.push("Top balanced key notes:");
      stats.patterns.balancedNotes.slice(0, 10).forEach((note, index2) => {
        sections.push(`  ${index2 + 1}. ${note.title} (${note.path})`);
      });
      if (stats.patterns.balancedNotes.length > 10) {
        sections.push(`  ... and ${stats.patterns.balancedNotes.length - 10} more`);
      }
      sections.push("");
    }
    return sections.join("\n");
  }
  /**
   * Compute link statistics for all notes in vault analysis
   */
  computeLinkStats(app, analysisData) {
    const allFiles = getIncludedMarkdownFiles(app);
    const linkStatsMap = /* @__PURE__ */ new Map();
    const inboundLinkCounts = /* @__PURE__ */ new Map();
    for (const file of allFiles) {
      try {
        const cache = app.metadataCache.getFileCache(file);
        if (!cache) continue;
        const allLinks = [
          ...cache.links || [],
          ...cache.embeds || [],
          ...cache.frontmatterLinks || []
        ];
        for (const link of allLinks) {
          const resolvedFile = app.metadataCache.getFirstLinkpathDest(link.link, file.path);
          if (resolvedFile) {
            const currentCount = inboundLinkCounts.get(resolvedFile.path) || 0;
            inboundLinkCounts.set(resolvedFile.path, currentCount + 1);
          }
        }
      } catch {
      }
    }
    for (const result of analysisData.results) {
      const abstractFile = app.vault.getAbstractFileByPath(result.path);
      if (!abstractFile || !(abstractFile instanceof import_obsidian6.TFile)) continue;
      const file = abstractFile;
      try {
        const cache = app.metadataCache.getFileCache(file);
        const outboundLinks = (cache?.links?.length || 0) + (cache?.embeds?.length || 0) + (cache?.frontmatterLinks?.length || 0);
        const inboundLinks = inboundLinkCounts.get(result.path) || 0;
        const totalLinks = outboundLinks + inboundLinks;
        const linkRatio = inboundLinks > 0 ? outboundLinks / inboundLinks : outboundLinks > 0 ? Infinity : 0;
        linkStatsMap.set(result.path, {
          path: result.path,
          title: result.title,
          outboundLinks,
          inboundLinks,
          totalLinks,
          linkRatio
        });
      } catch {
      }
    }
    return Array.from(linkStatsMap.values());
  }
  /**
   * Identify connectivity patterns from link stats
   */
  identifyPatterns(linkStats, analysisData) {
    const patterns = {
      integrationOpportunities: [],
      isolatedNotes: [],
      hubNotes: [],
      orphanNotes: [],
      bridgeTypeNotes: [],
      authorityTypeNotes: [],
      balancedNotes: []
    };
    if (linkStats.length === 0) return patterns;
    const outboundValues = linkStats.map((n) => n.outboundLinks).sort((a2, b) => b - a2);
    const inboundValues = linkStats.map((n) => n.inboundLinks).sort((a2, b) => b - a2);
    const p75Outbound = outboundValues[Math.floor(outboundValues.length * 0.25)] || 0;
    const p75Inbound = inboundValues[Math.floor(inboundValues.length * 0.25)] || 0;
    const p25Outbound = outboundValues[Math.floor(outboundValues.length * 0.75)] || 0;
    const p25Inbound = inboundValues[Math.floor(inboundValues.length * 0.75)] || 0;
    const vaultResultsMap = /* @__PURE__ */ new Map();
    analysisData.results.forEach((r) => vaultResultsMap.set(r.path, r));
    for (const note of linkStats) {
      const vaultResult = vaultResultsMap.get(note.path);
      if (note.totalLinks === 0) {
        patterns.orphanNotes.push(note);
      } else if (note.outboundLinks >= p75Outbound && note.inboundLinks <= p25Inbound) {
        patterns.integrationOpportunities.push(note);
      } else if (note.outboundLinks >= p75Outbound && note.inboundLinks >= p75Inbound) {
        patterns.hubNotes.push(note);
      } else if (note.outboundLinks <= p25Outbound && note.inboundLinks <= p25Inbound && note.totalLinks > 0) {
        patterns.isolatedNotes.push(note);
      }
      if (vaultResult?.graphMetrics) {
        const betweenness = vaultResult.graphMetrics.betweennessCentrality || 0;
        const eigenvector = vaultResult.graphMetrics.eigenvectorCentrality || 0;
        const allBetweenness = analysisData.results.map((r) => r.graphMetrics?.betweennessCentrality || 0).filter((v) => v > 0).sort((a2, b) => b - a2);
        const allEigenvector = analysisData.results.map((r) => r.graphMetrics?.eigenvectorCentrality || 0).filter((v) => v > 0).sort((a2, b) => b - a2);
        const top20Betweenness = allBetweenness[Math.floor(allBetweenness.length * 0.2)] || 0;
        const top20Eigenvector = allEigenvector[Math.floor(allEigenvector.length * 0.2)] || 0;
        const lowThreshold = Math.min(top20Betweenness, top20Eigenvector) * 0.3;
        if (betweenness >= top20Betweenness && eigenvector <= lowThreshold) {
          patterns.bridgeTypeNotes.push(note);
        } else if (eigenvector >= top20Eigenvector && betweenness <= lowThreshold) {
          patterns.authorityTypeNotes.push(note);
        } else if (betweenness >= top20Betweenness && eigenvector >= top20Eigenvector) {
          patterns.balancedNotes.push(note);
        }
      }
    }
    patterns.integrationOpportunities.sort((a2, b) => b.linkRatio - a2.linkRatio);
    patterns.isolatedNotes.sort((a2, b) => a2.totalLinks - b.totalLinks);
    patterns.hubNotes.sort((a2, b) => b.totalLinks - a2.totalLinks);
    patterns.orphanNotes.sort((a2, b) => a2.title.localeCompare(b.title));
    return patterns;
  }
};

// src/services/AIContextPreparationService.ts
var DEFAULT_AICONTEXT_CONFIG = {
  binSize: 0.05,
  topKPerCentrality: 15,
  includeMultiCentralityHubs: true,
  includeRepresentativeNotes: true
};
var AIContextPreparationService = class {
  constructor(config = {}) {
    this.config = { ...DEFAULT_AICONTEXT_CONFIG, ...config };
    this.kdeService = new KDECalculationService();
  }
  /**
   * Prepare optimized context from vault analysis data
   */
  prepareOptimizedContext(analysisData) {
    const results = analysisData.results.filter((r) => r.graphMetrics);
    const metadata = this.extractMetadata(analysisData, results);
    const topNotes = {
      betweenness: this.extractTopNotes(results, "betweennessCentrality", this.config.topKPerCentrality),
      closeness: this.extractTopNotes(results, "closenessCentrality", this.config.topKPerCentrality),
      eigenvector: this.extractTopNotes(results, "eigenvectorCentrality", this.config.topKPerCentrality),
      multiCentralityHubs: this.config.includeMultiCentralityHubs ? this.extractMultiCentralityHubs(results, this.config.topKPerCentrality) : void 0
    };
    const intervalSummaries = {
      betweenness: this.generateIntervalSummaries(results, "betweennessCentrality", this.config.binSize),
      closeness: this.generateIntervalSummaries(results, "closenessCentrality", this.config.binSize),
      eigenvector: this.generateIntervalSummaries(results, "eigenvectorCentrality", this.config.binSize)
    };
    const domainDistribution = this.calculateDomainDistribution(results);
    return {
      metadata,
      topNotes,
      intervalSummaries,
      domainDistribution
    };
  }
  /**
   * Extract compact metadata
   */
  extractMetadata(analysisData, results) {
    const dates = results.map((r) => new Date(r.created)).filter((d) => !isNaN(d.getTime())).sort((a2, b) => a2.getTime() - b.getTime());
    let dateRange;
    if (dates.length > 0) {
      const start2 = dates[0].toISOString().substring(0, 7);
      const end = dates[dates.length - 1].toISOString().substring(0, 7);
      dateRange = start2 === end ? start2 : `${start2} to ${end}`;
    }
    return {
      totalNotes: analysisData.totalFiles,
      analyzedNotes: results.length,
      dateRange
    };
  }
  /**
   * Extract top-k notes for a specific centrality type
   */
  extractTopNotes(results, centralityType, k) {
    const notesWithScores = results.map((result, index2) => {
      const score2 = result.graphMetrics?.[centralityType];
      const rank = result.centralityRankings?.[centralityType === "betweennessCentrality" ? "betweennessRank" : centralityType === "closenessCentrality" ? "closenessRank" : "eigenvectorRank"];
      if (score2 === void 0 || score2 === null || score2 <= 0) {
        return null;
      }
      return {
        result,
        score: score2,
        rank: rank ?? index2 + 1
      };
    }).filter((item) => item !== null).sort((a2, b) => b.score - a2.score).slice(0, k);
    return notesWithScores.map((item, index2) => ({
      id: item.result.id,
      title: item.result.title,
      path: item.result.path,
      score: item.score,
      rank: index2 + 1,
      // Re-rank after sorting
      keywords: item.result.keywords,
      domains: item.result.knowledgeDomains || []
    }));
  }
  /**
   * Extract notes that rank high in multiple centrality types (hubs)
   */
  extractMultiCentralityHubs(results, k) {
    const betweennessScores = results.map((r) => r.graphMetrics?.betweennessCentrality).filter((s) => s !== void 0 && s !== null && s > 0).sort((a2, b) => b - a2);
    const closenessScores = results.map((r) => r.graphMetrics?.closenessCentrality).filter((s) => s !== void 0 && s !== null && s > 0).sort((a2, b) => b - a2);
    const eigenvectorScores = results.map((r) => r.graphMetrics?.eigenvectorCentrality).filter((s) => s !== void 0 && s !== null && s > 0).sort((a2, b) => b - a2);
    const top10PercentIndex = Math.max(1, Math.floor(betweennessScores.length * 0.1));
    const betweennessThreshold = betweennessScores[top10PercentIndex - 1] || 0;
    const closenessThreshold = closenessScores[top10PercentIndex - 1] || 0;
    const eigenvectorThreshold = eigenvectorScores[top10PercentIndex - 1] || 0;
    const hubs = results.map((result) => {
      const betweenness = result.graphMetrics?.betweennessCentrality || 0;
      const closeness = result.graphMetrics?.closenessCentrality || 0;
      const eigenvector = result.graphMetrics?.eigenvectorCentrality || 0;
      const highCount = [
        betweenness >= betweennessThreshold,
        closeness >= closenessThreshold,
        eigenvector >= eigenvectorThreshold
      ].filter(Boolean).length;
      if (highCount < 2) return null;
      const scores = [betweenness, closeness, eigenvector].filter((s) => s > 0);
      const compositeScore = scores.reduce((a2, b) => a2 + b, 0) / scores.length;
      return {
        result,
        compositeScore,
        highCount
      };
    }).filter((item) => item !== null).sort((a2, b) => {
      if (a2.highCount !== b.highCount) {
        return b.highCount - a2.highCount;
      }
      return b.compositeScore - a2.compositeScore;
    }).slice(0, k);
    return hubs.map((item, index2) => ({
      id: item.result.id,
      title: item.result.title,
      path: item.result.path,
      score: item.compositeScore,
      rank: index2 + 1,
      keywords: item.result.keywords,
      domains: item.result.knowledgeDomains || []
    }));
  }
  /**
   * Generate interval summaries for a centrality type
   */
  generateIntervalSummaries(results, centralityType, binSize) {
    const notesWithScores = results.map((result) => ({
      result,
      score: result.graphMetrics?.[centralityType]
    })).filter(
      (item) => item.score !== void 0 && item.score !== null && item.score >= 0
    );
    if (notesWithScores.length === 0) {
      return [];
    }
    const maxScore = Math.max(...notesWithScores.map((item) => item.score));
    const upperBound = Math.ceil(maxScore / binSize) * binSize;
    const numBins = Math.ceil(upperBound / binSize);
    const bins = /* @__PURE__ */ new Map();
    notesWithScores.forEach(({ result, score: score2 }) => {
      const binIndex = Math.min(Math.floor(score2 / binSize), numBins - 1);
      if (!bins.has(binIndex)) {
        bins.set(binIndex, []);
      }
      bins.get(binIndex).push(result);
    });
    const summaries = [];
    for (let i = 0; i < numBins; i++) {
      const notes = bins.get(i);
      if (!notes || notes.length === 0) continue;
      const min8 = i * binSize;
      const max8 = Math.min((i + 1) * binSize, upperBound);
      const range2 = `${min8.toFixed(2)}-${max8.toFixed(2)}`;
      const keywordCounts = /* @__PURE__ */ new Map();
      notes.forEach((note) => {
        const keywords = note.keywords.split(",").map((k) => k.trim()).filter((k) => k.length > 0);
        keywords.forEach((keyword) => {
          keywordCounts.set(keyword, (keywordCounts.get(keyword) || 0) + 1);
        });
      });
      const topKeywords = Array.from(keywordCounts.entries()).sort((a2, b) => b[1] - a2[1]).slice(0, 5).map(([keyword]) => keyword);
      const domainCounts = /* @__PURE__ */ new Map();
      notes.forEach((note) => {
        (note.knowledgeDomains || []).forEach((domain) => {
          domainCounts.set(domain, (domainCounts.get(domain) || 0) + 1);
        });
      });
      const topDomains = Array.from(domainCounts.entries()).sort((a2, b) => b[1] - a2[1]).slice(0, 3).map(([domain]) => domain);
      let representativeNote;
      if (this.config.includeRepresentativeNotes) {
        const sortedNotes = [...notes].sort((a2, b) => {
          const scoreA = a2.graphMetrics?.[centralityType] || 0;
          const scoreB = b.graphMetrics?.[centralityType] || 0;
          return scoreB - scoreA;
        });
        representativeNote = sortedNotes[0]?.title;
      }
      summaries.push({
        range: range2,
        noteCount: notes.length,
        topKeywords,
        topDomains,
        representativeNote
      });
    }
    return summaries;
  }
  /**
   * Calculate domain distribution summary
   */
  calculateDomainDistribution(results) {
    const domainMap = /* @__PURE__ */ new Map();
    results.forEach((result) => {
      const domains = result.knowledgeDomains || [];
      domains.forEach((domain) => {
        if (!domainMap.has(domain)) {
          domainMap.set(domain, {
            notes: [],
            betweennessSum: 0,
            closenessSum: 0,
            eigenvectorSum: 0
          });
        }
        const domainData = domainMap.get(domain);
        domainData.notes.push(result);
        const betweenness = result.graphMetrics?.betweennessCentrality || 0;
        const closeness = result.graphMetrics?.closenessCentrality || 0;
        const eigenvector = result.graphMetrics?.eigenvectorCentrality || 0;
        domainData.betweennessSum += betweenness;
        domainData.closenessSum += closeness;
        domainData.eigenvectorSum += eigenvector;
      });
    });
    return Array.from(domainMap.entries()).map(([domain, data]) => ({
      domain,
      noteCount: data.notes.length,
      avgBetweenness: data.betweennessSum / data.notes.length,
      avgCloseness: data.closenessSum / data.notes.length,
      avgEigenvector: data.eigenvectorSum / data.notes.length
    })).sort((a2, b) => b.noteCount - a2.noteCount);
  }
  /**
   * Format optimized context for AI consumption
   */
  formatForAI(context, comprehensiveStats) {
    const sections = [];
    sections.push("=== VAULT METADATA ===");
    sections.push(`Total Notes: ${context.metadata.totalNotes}`);
    sections.push(`Analyzed Notes: ${context.metadata.analyzedNotes}`);
    if (context.metadata.dateRange) {
      sections.push(`Date Range: ${context.metadata.dateRange}`);
    }
    sections.push("");
    sections.push("=== CENTRALITY DISTRIBUTION ANALYSIS (Comprehensive Statistics) ===");
    sections.push(comprehensiveStats);
    sections.push("");
    sections.push("=== TOP NOTES BY CENTRALITY ===");
    ["betweenness", "closeness", "eigenvector"].forEach((centralityType) => {
      const notes = context.topNotes[centralityType];
      if (notes.length === 0) return;
      sections.push(`
${centralityType.toUpperCase()} Centrality (Top ${notes.length}):`);
      notes.forEach((note) => {
        sections.push(`  ${note.rank}. ${note.title} (${note.path})`);
        sections.push(`     Score: ${note.score.toFixed(4)}, Keywords: ${note.keywords}, Domains: ${note.domains.join(", ")}`);
      });
    });
    if (context.topNotes.multiCentralityHubs && context.topNotes.multiCentralityHubs.length > 0) {
      sections.push(`
MULTI-CENTRALITY HUBS (High in 2+ centralities, Top ${context.topNotes.multiCentralityHubs.length}):`);
      context.topNotes.multiCentralityHubs.forEach((hub) => {
        sections.push(`  ${hub.rank}. ${hub.title} (${hub.path})`);
        sections.push(`     Composite Score: ${hub.score.toFixed(4)}, Keywords: ${hub.keywords}, Domains: ${hub.domains.join(", ")}`);
      });
    }
    sections.push("");
    sections.push("=== CENTRALITY DISTRIBUTION BY INTERVALS ===");
    ["betweenness", "closeness", "eigenvector"].forEach((centralityType) => {
      const summaries = context.intervalSummaries[centralityType];
      if (summaries.length === 0) return;
      sections.push(`
${centralityType.toUpperCase()} Centrality Distribution:`);
      summaries.forEach((summary) => {
        sections.push(`  Range ${summary.range}: ${summary.noteCount} notes`);
        if (summary.topKeywords.length > 0) {
          sections.push(`    Top Keywords: ${summary.topKeywords.join(", ")}`);
        }
        if (summary.topDomains.length > 0) {
          sections.push(`    Top Domains: ${summary.topDomains.join(", ")}`);
        }
        if (summary.representativeNote) {
          sections.push(`    Representative Note: ${summary.representativeNote}`);
        }
      });
    });
    sections.push("");
    sections.push("=== KNOWLEDGE DOMAIN DISTRIBUTION ===");
    sections.push(`Total Domains: ${context.domainDistribution.length}`);
    sections.push("\nTop Domains by Note Count:");
    context.domainDistribution.slice(0, 20).forEach((domain, index2) => {
      sections.push(`  ${index2 + 1}. ${domain.domain} (${domain.noteCount} notes)`);
      sections.push(`     Avg Betweenness: ${domain.avgBetweenness.toFixed(4)}, Avg Closeness: ${domain.avgCloseness.toFixed(4)}, Avg Eigenvector: ${domain.avgEigenvector.toFixed(4)}`);
    });
    if (context.domainDistribution.length > 20) {
      sections.push(`  ... and ${context.domainDistribution.length - 20} more domains`);
    }
    return sections.join("\n");
  }
  /**
   * Prepare evolution-specific context from vault analysis data
   * Focuses on temporal data: notes grouped by period, domain first appearance, growth trends
   */
  prepareEvolutionContext(analysisData) {
    const results = analysisData.results.filter((r) => r.created);
    const metadata = this.extractEvolutionMetadata(results);
    const timelinePeriods = this.groupNotesByPeriod(results);
    const domainEvolution = this.calculateDomainEvolution(results);
    return {
      metadata,
      timelinePeriods,
      domainEvolution
    };
  }
  /**
   * Extract evolution-specific metadata
   */
  extractEvolutionMetadata(results) {
    const dates = results.map((r) => new Date(r.created)).filter((d) => !isNaN(d.getTime())).sort((a2, b) => a2.getTime() - b.getTime());
    let dateRange;
    let timeSpan;
    if (dates.length > 0) {
      const start2 = dates[0];
      const end = dates[dates.length - 1];
      const startStr = start2.toISOString().substring(0, 7);
      const endStr = end.toISOString().substring(0, 7);
      dateRange = startStr === endStr ? startStr : `${startStr} to ${endStr}`;
      const monthsDiff = (end.getFullYear() - start2.getFullYear()) * 12 + (end.getMonth() - start2.getMonth());
      if (monthsDiff < 1) {
        timeSpan = "Less than 1 month";
      } else if (monthsDiff === 1) {
        timeSpan = "1 month";
      } else {
        timeSpan = `${monthsDiff} months`;
      }
    }
    return {
      totalNotes: results.length,
      dateRange: dateRange || "Unknown",
      timeSpan: timeSpan || "Unknown"
    };
  }
  /**
   * Group notes by time period (quarterly)
   */
  groupNotesByPeriod(results) {
    const periodMap = /* @__PURE__ */ new Map();
    const domainFirstAppearance = /* @__PURE__ */ new Map();
    results.forEach((note) => {
      const date = new Date(note.created);
      if (isNaN(date.getTime())) return;
      const year = date.getFullYear();
      const quarter = Math.floor(date.getMonth() / 3) + 1;
      const period = `${year}-Q${quarter}`;
      if (!periodMap.has(period)) {
        periodMap.set(period, {
          notes: [],
          domains: /* @__PURE__ */ new Set(),
          keywords: /* @__PURE__ */ new Map()
        });
      }
      const periodData = periodMap.get(period);
      periodData.notes.push(note);
      (note.knowledgeDomains || []).forEach((domain) => {
        periodData.domains.add(domain);
        if (!domainFirstAppearance.has(domain)) {
          domainFirstAppearance.set(domain, period);
        }
      });
      note.keywords.split(",").forEach((keyword) => {
        const trimmed = keyword.trim();
        if (trimmed) {
          periodData.keywords.set(trimmed, (periodData.keywords.get(trimmed) || 0) + 1);
        }
      });
    });
    const sortedPeriods = Array.from(periodMap.entries()).sort((a2, b) => a2[0].localeCompare(b[0]));
    return sortedPeriods.map(([period, data]) => {
      const topKeywords = Array.from(data.keywords.entries()).sort((a2, b) => b[1] - a2[1]).slice(0, 5).map(([keyword]) => keyword);
      const topDomains = Array.from(data.domains).slice(0, 5);
      const newDomains = Array.from(data.domains).filter(
        (domain) => domainFirstAppearance.get(domain) === period
      );
      return {
        period,
        noteCount: data.notes.length,
        topDomains,
        newDomains,
        topKeywords
      };
    });
  }
  /**
   * Calculate domain evolution (first appearance and total notes - factual data only)
   */
  calculateDomainEvolution(results) {
    const domainMap = /* @__PURE__ */ new Map();
    results.forEach((note) => {
      const noteDate = new Date(note.created);
      if (isNaN(noteDate.getTime())) return;
      (note.knowledgeDomains || []).forEach((domain) => {
        if (!domainMap.has(domain)) {
          domainMap.set(domain, {
            firstAppeared: noteDate,
            notes: []
          });
        }
        const domainData = domainMap.get(domain);
        domainData.notes.push(note);
        if (noteDate < domainData.firstAppeared) {
          domainData.firstAppeared = noteDate;
        }
      });
    });
    return Array.from(domainMap.entries()).map(([domain, data]) => ({
      domain,
      firstAppeared: data.firstAppeared.toISOString().substring(0, 7),
      // YYYY-MM
      totalNotes: data.notes.length
    })).sort((a2, b) => new Date(a2.firstAppeared).getTime() - new Date(b.firstAppeared).getTime());
  }
  /**
   * Format evolution context for AI consumption
   */
  formatEvolutionContextForAI(context) {
    const sections = [];
    sections.push("=== EVOLUTION METADATA ===");
    sections.push(`Total Notes: ${context.metadata.totalNotes}`);
    sections.push(`Date Range: ${context.metadata.dateRange}`);
    sections.push(`Time Span: ${context.metadata.timeSpan}`);
    sections.push("");
    sections.push("=== TIMELINE PERIODS (Quarterly) ===");
    context.timelinePeriods.forEach((period) => {
      sections.push(`
${period.period}:`);
      sections.push(`  Notes: ${period.noteCount}`);
      sections.push(`  Top Domains: ${period.topDomains.join(", ")}`);
      if (period.newDomains.length > 0) {
        sections.push(`  New Domains (first appeared): ${period.newDomains.join(", ")}`);
      }
      sections.push(`  Top Keywords: ${period.topKeywords.join(", ")}`);
    });
    sections.push("");
    sections.push("=== DOMAIN EVOLUTION ===");
    sections.push(`Total Domains: ${context.domainEvolution.length}`);
    sections.push("\nDomain First Appearance:");
    context.domainEvolution.slice(0, 30).forEach((domain, index2) => {
      sections.push(`  ${index2 + 1}. ${domain.domain}`);
      sections.push(`     First Appeared: ${domain.firstAppeared}, Total Notes: ${domain.totalNotes}`);
    });
    if (context.domainEvolution.length > 30) {
      sections.push(`  ... and ${context.domainEvolution.length - 30} more domains`);
    }
    return sections.join("\n");
  }
  /**
   * Prepare actions-specific context from vault analysis data
   * Combines vault data, connectivity insights, and centrality patterns
   */
  prepareActionsContext(app, analysisData) {
    const connectivityService = new ConnectivityAnalysisService();
    const connectivitySummary = connectivityService.getComprehensiveConnectivitySummary(app, analysisData);
    const results = analysisData.results.filter((r) => r.graphMetrics);
    const topBetweenness = this.extractTopNotes(results, "betweennessCentrality", 10);
    const topEigenvector = this.extractTopNotes(results, "eigenvectorCentrality", 10);
    const metadata = this.extractMetadata(analysisData, results);
    return {
      metadata,
      connectivitySummary,
      topBetweennessNotes: topBetweenness,
      topEigenvectorNotes: topEigenvector
    };
  }
  /**
   * Format actions context for AI consumption
   */
  formatActionsContextForAI(context) {
    const sections = [];
    sections.push("=== VAULT METADATA ===");
    sections.push(`Total Notes: ${context.metadata.totalNotes}`);
    sections.push(`Analyzed Notes: ${context.metadata.analyzedNotes}`);
    if (context.metadata.dateRange) {
      sections.push(`Date Range: ${context.metadata.dateRange}`);
    }
    sections.push("");
    sections.push(context.connectivitySummary);
    sections.push("");
    sections.push("=== TOP NOTES BY CENTRALITY ===");
    if (context.topBetweennessNotes.length > 0) {
      sections.push(`
Top Betweenness Centrality Notes (Bridge-type):`);
      context.topBetweennessNotes.slice(0, 10).forEach((note) => {
        sections.push(`  ${note.rank}. ${note.title} (${note.path})`);
        sections.push(`     Score: ${note.score.toFixed(4)}, Keywords: ${note.keywords}, Domains: ${note.domains.join(", ")}`);
      });
    }
    if (context.topEigenvectorNotes.length > 0) {
      sections.push(`
Top Eigenvector Centrality Notes (Authority-type):`);
      context.topEigenvectorNotes.slice(0, 10).forEach((note) => {
        sections.push(`  ${note.rank}. ${note.title} (${note.path})`);
        sections.push(`     Score: ${note.score.toFixed(4)}, Keywords: ${note.keywords}, Domains: ${note.domains.join(", ")}`);
      });
    }
    return sections.join("\n");
  }
};

// src/ai/MasterAnalysisManager.ts
var MasterAnalysisManager = class {
  constructor(app, settings, dataStore) {
    this.app = app;
    this.settings = settings;
    this.aiService = new AIModelService(app, settings);
    this.dataStore = dataStore;
  }
  async loadCachedTabAnalysis(tabName, preloadedVaultData) {
    try {
      const loaded = await this.dataStore.getTabAnalysis(tabName);
      if (!loaded) {
        return null;
      }
      const data = { ...loaded };
      const currentAnalysisData = preloadedVaultData !== void 0 ? preloadedVaultData : await this.loadVaultAnalysisData();
      if (currentAnalysisData && data?.sourceAnalysisId !== this.generateAnalysisId(currentAnalysisData)) {
        data.isOutdated = true;
      } else {
        data.isOutdated = false;
      }
      return data;
    } catch {
      return null;
    }
  }
  async loadVaultAnalysisData() {
    return this.dataStore.getVaultAnalysis();
  }
  generateAnalysisId(analysisData) {
    return generateVaultAnalysisId(analysisData);
  }
  /**
   * Validate that network node data contains real notes from the vault
   */
  validateNetworkNodeData(knowledgeNetwork, analysisData) {
    const vaultNotes = new Map(analysisData.results.map((n) => [n.path, n]));
    const vaultTitles = new Set(analysisData.results.map((n) => n.title));
    const categories = ["bridges", "foundations", "authorities"];
    let issuesFound = 0;
    for (const category of categories) {
      const categoryData = knowledgeNetwork[category];
      if (!categoryData || !Array.isArray(categoryData)) continue;
      for (let domainIndex = 0; domainIndex < categoryData.length; domainIndex++) {
        const domain = categoryData[domainIndex];
        const topNotes = domain?.topNotes;
        if (!topNotes || !Array.isArray(topNotes)) continue;
        for (let noteIndex = 0; noteIndex < topNotes.length; noteIndex++) {
          const note = topNotes[noteIndex];
          const noteTitle = note?.title ?? "";
          const notePath = note?.path ?? "";
          if (noteTitle === "Note Title" || notePath === "path/to/note.md" || noteTitle.includes("Example") || noteTitle.includes("Sample")) {
            issuesFound++;
            continue;
          }
          if (!vaultNotes.has(notePath)) {
            if (vaultTitles.has(noteTitle)) {
              const matchingNote = analysisData.results.find((n) => n.title === noteTitle);
              if (matchingNote) {
                note.path = matchingNote.path;
              }
            } else {
              issuesFound++;
            }
          } else {
            const vaultNote = vaultNotes.get(notePath);
            if (vaultNote && vaultNote.title !== noteTitle) {
              note.title = vaultNote.title;
            }
          }
        }
      }
    }
    if (issuesFound > 0) {
    } else {
    }
  }
  updateSettings(settings) {
    this.settings = settings;
    this.aiService.updateSettings(settings);
  }
  promptWithLanguage(system, context, instruction, analysisData) {
    const sample = buildContextSampleFromVaultRows(analysisData.results);
    const languageSection = buildLanguagePromptSection(this.settings, sample);
    return `${system}

${context}

${instruction}

${languageSection}`;
  }
  /**
   * NEW: Generate Knowledge Structure Analysis using structured output
   */
  async generateKnowledgeStructureAnalysis() {
    try {
      const analysisData = await this.loadVaultAnalysisData();
      if (!analysisData) {
        throw new Error("No vault analysis data found. Please generate vault analysis first.");
      }
      const contextService = new AIContextPreparationService();
      const optimizedContext = contextService.prepareOptimizedContext(analysisData);
      const kdeService = new KDECalculationService();
      const comprehensiveStats = kdeService.getComprehensiveStats(analysisData);
      const formattedContext = contextService.formatForAI(optimizedContext, comprehensiveStats);
      const system = "You are an expert in knowledge management. You are highly skilled in applying graph theory and network analysis to knowledge graphs. Use your expertise to extract insights from the provided context which contains knowledge domains and centrality rankings. Please focus on network analysis and determining knowledge gaps.";
      const context = `VAULT ANALYSIS DATA (Optimized):
${formattedContext}`;
      const instruction = `Analyze the vault data to identify key knowledge domains using network centrality metrics. Return a JSON object matching the required schema.

**Network Analysis Framework:**
- **Knowledge Bridges** (Betweenness Centrality): Domains that connect disparate knowledge areas and facilitate interdisciplinary thinking
- **Knowledge Foundations** (Closeness Centrality): Core domains that are central to the knowledge network and serve as conceptual starting points  
- **Knowledge Authorities** (Eigenvector Centrality): Domains representing areas of expertise with deep interconnections to other important concepts

**Instructions:**
1. Identify top-ranking domains for each centrality type based on the provided data
2. For each domain, output top 3 contributing notes with the highest centrality ranking for each domain
3. Explain why each domain qualifies as a bridge/foundation/authority based on its network position
4. Use only domains explicitly present in the vault data - do not invent domains
5. Treat domains as independent entities (multiple domains from one note are separate)`;
      const prompt = this.promptWithLanguage(system, context, instruction, analysisData);
      const responseSchema = this.aiService.createKnowledgeNetworkSchema();
      const response = await this.aiService.generateStructuredAnalysis(
        prompt,
        responseSchema,
        8192,
        // maxOutputTokens
        0.3,
        // temperature
        0.72
        // topP
      );
      const structureData = this.parseStructuredKnowledgeNetwork(response.result, analysisData);
      const tabData = {
        generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
        sourceAnalysisId: this.generateAnalysisId(analysisData),
        apiProvider: "Google Gemini",
        knowledgeStructure: structureData
      };
      await this.cacheTabAnalysis("structure", tabData);
      return tabData;
    } catch (error) {
      if (error instanceof SemanticAnalysisError && error.errorType === "quota_exhausted") {
        new import_obsidian7.Notice(getUserFriendlyMessage(error));
      }
      throw error;
    }
  }
  /**
   * NEW: Parse structured knowledge network response (replaces old parseKnowledgeStructure)
   */
  parseStructuredKnowledgeNetwork(structuredResponse, analysisData) {
    try {
      const resp = structuredResponse;
      const knowledgeNetwork = resp.knowledgeNetwork ?? {
        bridges: [],
        foundations: [],
        authorities: []
      };
      this.validateNetworkNodeData(knowledgeNetwork, analysisData);
      const knowledgeGaps = resp.knowledgeGaps ?? [];
      return {
        knowledgeNetwork,
        gaps: knowledgeGaps
      };
    } catch (err) {
      const errorMessage = err instanceof Error ? err.message : String(err);
      throw new Error(`Failed to parse structured knowledge network: ${errorMessage}`);
    }
  }
  // NEW: Cache tab-specific analysis
  async cacheTabAnalysis(tabName, data) {
    try {
      await this.dataStore.setTabAnalysis(tabName, data);
    } catch {
    }
  }
  // TODO: Implement these methods tomorrow with structured output approach
  /**
   * Generate Knowledge Evolution Analysis using structured output
   */
  async generateKnowledgeEvolutionAnalysis() {
    try {
      const analysisData = await this.loadVaultAnalysisData();
      if (!analysisData) {
        throw new Error("No vault analysis data found. Please generate vault analysis first.");
      }
      const contextService = new AIContextPreparationService();
      const evolutionContext = contextService.prepareEvolutionContext(analysisData);
      const formattedContext = contextService.formatEvolutionContextForAI(evolutionContext);
      const system = "You are an expert in knowledge management and learning analytics. You specialize in analyzing how knowledge evolves over time, identifying patterns in topic introduction, and detecting shifts in intellectual focus. Use your expertise to extract insights from the provided temporal context which contains notes grouped by period and domain evolution data.";
      const context = `VAULT EVOLUTION DATA (Optimized):
${formattedContext}`;
      const instruction = `Analyze the vault evolution data to identify knowledge development patterns over time. Return a JSON object matching the required schema.

**Analysis Framework:**

1. **Knowledge Development Timeline**: Identify distinct phases in the knowledge development journey, describing key periods, dominant domains, and overall trends in productivity, diversity, and depth.

2. **Topic Introduction Patterns**: Analyze when different knowledge domains first appeared, identify acquisition patterns (burst, gradual, or project-based), and assess the learning strategy (depth-first, breadth-first, or balanced).

3. **Focus Shift Analysis**: Detect significant changes in knowledge focus between periods, identify new areas being explored, areas with increased/decreased attention, and consistent areas. Determine the frequency and direction of focus shifts.

**Instructions:**
1. Group notes into meaningful phases (typically 3-6 phases) based on domain activity and note creation patterns
2. For each phase, provide key domains, metrics (note count, word count), and a narrative description
3. Identify when domains first appeared and characterize the acquisition pattern
4. Detect focus shifts by comparing domain activity across periods
5. Use only domains and data explicitly present in the vault data - do not invent domains or metrics
6. Provide insights that are specific, actionable, and grounded in the actual data`;
      const prompt = this.promptWithLanguage(system, context, instruction, analysisData);
      const responseSchema = this.aiService.createKnowledgeEvolutionSchema();
      const response = await this.aiService.generateStructuredAnalysis(
        prompt,
        responseSchema,
        8192,
        // maxOutputTokens
        0.3,
        // temperature
        0.72
        // topP
      );
      const evolutionData = this.parseStructuredKnowledgeEvolution(response.result, analysisData);
      const tabData = {
        generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
        sourceAnalysisId: this.generateAnalysisId(analysisData),
        apiProvider: "Google Gemini",
        knowledgeEvolution: evolutionData
      };
      await this.cacheTabAnalysis("evolution", tabData);
      return tabData;
    } catch (error) {
      if (error instanceof SemanticAnalysisError && error.errorType === "quota_exhausted") {
        new import_obsidian7.Notice(getUserFriendlyMessage(error));
      }
      throw error;
    }
  }
  /**
   * Parse structured knowledge evolution response
   */
  parseStructuredKnowledgeEvolution(structuredResponse, _analysisData) {
    try {
      const resp = structuredResponse;
      const timeline = resp.timeline ?? {
        narrative: { title: "", content: "", keyPoints: [] },
        phases: [],
        trends: { productivity: "stable", diversity: "stable", depth: "stable" }
      };
      const topicPatterns = resp.topicPatterns ?? {
        exploration: { title: "", content: "", keyPoints: [] },
        introductionTimeline: [],
        strategy: { style: "balanced", consistency: "mixed" }
      };
      const focusShift = resp.focusShift ?? {
        narrative: { title: "", content: "", keyPoints: [] },
        shifts: [],
        patterns: { frequency: "occasional", direction: "expanding" }
      };
      const insights = resp.insights ?? [];
      return {
        timeline,
        topicPatterns,
        focusShift,
        insights
      };
    } catch (err) {
      const errorMessage = err instanceof Error ? err.message : String(err);
      throw new Error(`Failed to parse structured knowledge evolution: ${errorMessage}`);
    }
  }
  /**
   * Generate Recommended Actions Analysis using structured output
   */
  async generateRecommendedActionsAnalysis() {
    try {
      const analysisData = await this.loadVaultAnalysisData();
      if (!analysisData) {
        throw new Error("No vault analysis data found. Please generate vault analysis first.");
      }
      const contextService = new AIContextPreparationService();
      const actionsContext = contextService.prepareActionsContext(this.app, analysisData);
      const formattedContext = contextService.formatActionsContextForAI(actionsContext);
      const system = "You are an expert in knowledge management and knowledge graph optimization. You specialize in identifying notes that need maintenance, suggesting connections between related concepts, and optimizing knowledge structure. Use your expertise to analyze the provided connectivity and centrality data to generate actionable recommendations.";
      const context = `VAULT ANALYSIS DATA WITH CONNECTIVITY INSIGHTS:
${formattedContext}`;
      const instruction = `Analyze the vault data and connectivity insights to generate actionable recommendations. Return a JSON object matching the required schema.

**Analysis Framework:**

1. **Knowledge Maintenance**: Identify notes that need attention based on:
   - Integration opportunities (high outbound, low inbound links) - these notes need incoming connections
   - Isolated notes (low connectivity) - these need more links
   - Orphan notes (zero links) - these need urgent attention
   - Notes with high centrality but low connectivity - important concepts that are underlinked
   - Notes that haven't been modified recently but are important (check modified dates)
   - Notes that serve as bridges or authorities but need reinforcement

2. **Connection Recommendations**: Suggest links between notes based on:
   - Integration opportunities - notes that should receive incoming links
   - Same knowledge domains but no existing links
   - Complementary content (based on keywords and summaries)
   - Missing bridges between knowledge clusters
   - Notes that would benefit from cross-domain connections

**Instructions:**
1. For maintenance actions, prioritize based on urgency:
   - High priority: Orphan notes, important notes with zero inbound links, critical bridges/authorities that are underlinked
   - Medium priority: Isolated notes, integration opportunities, notes needing updates
   - Low priority: Notes that could benefit from minor improvements
   - Limit to the top 12 most impactful maintenance items.
   - Provide a concise reason (1-2 sentences) and a specific action for each.

2. For connection recommendations, provide:
   - sourceId: the note that will RECEIVE the new link (we will add [[target]] inside this note)
   - targetId: the note being linked to
   - Clear, concise reason (1-2 sentences) why the connection makes sense
   - Confidence score (0.0-1.0) based on how strong the connection rationale is
   - Focus on high-value connections (integration opportunities, domain bridges)
   - Limit to the top 20 highest-value connection suggestions.

3. Use only notes and data explicitly present in the vault data - do not invent notes or paths.
4. Use the EXACT path format from the vault data (e.g. "Folder/Note.md") for noteId, sourceId, and targetId.
5. Provide specific, actionable recommendations grounded in the connectivity and centrality patterns.
6. For learningPaths and organization, return empty arrays (to be implemented in future).`;
      const prompt = this.promptWithLanguage(system, context, instruction, analysisData);
      const responseSchema = this.aiService.createRecommendedActionsSchema();
      const response = await this.aiService.generateStructuredAnalysis(
        prompt,
        responseSchema,
        8192,
        // maxOutputTokens
        0.3,
        // temperature
        0.72
        // topP
      );
      const actionsData = this.parseStructuredRecommendedActions(response.result, analysisData);
      const tabData = {
        generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
        sourceAnalysisId: this.generateAnalysisId(analysisData),
        apiProvider: "Google Gemini",
        recommendedActions: actionsData
      };
      await this.cacheTabAnalysis("actions", tabData);
      return tabData;
    } catch (error) {
      if (error instanceof SemanticAnalysisError && error.errorType === "quota_exhausted") {
        new import_obsidian7.Notice(getUserFriendlyMessage(error));
      }
      throw error;
    }
  }
  /**
   * Parse structured recommended actions response
   */
  parseStructuredRecommendedActions(structuredResponse, _analysisData) {
    try {
      const resp = structuredResponse;
      const maintenance = resp.maintenance ?? [];
      const connections = resp.connections ?? [];
      const learningPaths = resp.learningPaths ?? [];
      const organization = resp.organization ?? [];
      const validatedMaintenance = maintenance.map((action) => {
        const noteId = NoteResolver.resolveToPath(
          this.app,
          action.noteId ?? action.path ?? action.title ?? ""
        );
        return {
          noteId,
          title: action.title ?? "",
          reason: action.reason ?? "",
          priority: action.priority === "high" || action.priority === "medium" || action.priority === "low" ? action.priority : "medium",
          action: action.action ?? ""
        };
      }).filter((a2) => Boolean(a2.noteId));
      const validatedConnections = connections.map((conn) => {
        const sourceId = NoteResolver.resolveToPath(this.app, conn.sourceId ?? "");
        const targetId = NoteResolver.resolveToPath(this.app, conn.targetId ?? "");
        return {
          sourceId,
          targetId,
          reason: conn.reason ?? "",
          confidence: Math.max(0, Math.min(1, conn.confidence ?? 0.5))
        };
      }).filter((c4) => Boolean(c4.sourceId && c4.targetId && c4.sourceId !== c4.targetId));
      return {
        maintenance: validatedMaintenance,
        connections: validatedConnections,
        learningPaths,
        organization
      };
    } catch (err) {
      const errorMessage = err instanceof Error ? err.message : String(err);
      throw new Error(`Failed to parse structured recommended actions: ${errorMessage}`);
    }
  }
};
function generateVaultAnalysisId(analysisData) {
  return `${analysisData.generatedAt}_${analysisData.totalFiles}`;
}

// src/ai/visualization/KnowledgeStructureManager.ts
var import_obsidian9 = require("obsidian");

// src/components/domain-distribution/DomainDistributionChart.ts
var import_obsidian8 = require("obsidian");
var DomainDistributionChart = class {
  constructor(app, settings, container, options = {}) {
    this.data = null;
    this.app = app;
    this.settings = settings;
    this.container = container;
    this.options = {
      chartType: "sunburst",
      showTooltips: true,
      showLabels: true,
      ...options
    };
    const win = this.container.ownerDocument.defaultView;
    this._themeChangeHandler = () => {
      if (this._themeChangeTimeout) {
        win.clearTimeout(this._themeChangeTimeout);
      }
      this._themeChangeTimeout = win.setTimeout(() => {
        if (this.container.children.length > 0) {
          void this.refresh();
        }
      }, 150);
    };
    const doc = this.container.ownerDocument;
    const workspace = doc.querySelector(".workspace");
    if (workspace) {
      workspace.addEventListener("css-change", this._themeChangeHandler);
    }
    this._themeObserver = new MutationObserver((mutations) => {
      for (const mutation of mutations) {
        if (mutation.type === "attributes" && mutation.attributeName === "class" && mutation.target === doc.body) {
          const classList2 = mutation.target.className;
          if (classList2.includes("theme-") || classList2.includes("color-scheme-")) {
            this._themeChangeHandler?.();
          }
          break;
        }
      }
    });
    this._themeObserver.observe(doc.body, {
      attributes: true,
      attributeFilter: ["class"]
    });
    this._documentObserver = new MutationObserver((mutations) => {
      for (const mutation of mutations) {
        if (mutation.type === "attributes" && mutation.attributeName === "style" && mutation.target === doc.documentElement) {
          const style = mutation.target.getAttribute("style") || "";
          if (style.includes("--accent") || style.includes("--text-accent") || style.includes("--interactive-accent")) {
            this._themeChangeHandler?.();
          }
          break;
        }
      }
    });
    this._documentObserver.observe(doc.documentElement, {
      attributes: true,
      attributeFilter: ["style"]
    });
  }
  destroy() {
    const workspace = this.container.ownerDocument.querySelector(".workspace");
    if (workspace && this._themeChangeHandler) {
      workspace.removeEventListener("css-change", this._themeChangeHandler);
    }
    if (this._themeObserver) {
      this._themeObserver.disconnect();
    }
    if (this._documentObserver) {
      this._documentObserver.disconnect();
    }
    if (this._themeChangeTimeout) {
      this.container.ownerDocument.defaultView.clearTimeout(this._themeChangeTimeout);
    }
  }
  render() {
    this.container.empty();
    if (!this.data || !this.data.domainHierarchy || this.data.domainHierarchy.length === 0) {
      this.renderPlaceholder();
      return Promise.resolve();
    }
    const chartContainer = this.container.createEl("div", { cls: "domain-chart-container" });
    this.renderSunburstChart(chartContainer);
    return Promise.resolve();
  }
  renderPlaceholder() {
    const placeholder = this.container.createEl("div", { cls: "domain-chart-placeholder" });
    const content = placeholder.createEl("div", { cls: "placeholder-content" });
    const iconEl = content.createEl("div", { cls: "placeholder-icon" });
    (0, import_obsidian8.setIcon)(iconEl, "pie-chart");
    content.createEl("div", { cls: "placeholder-title", text: t("domainChart.noHierarchy") });
    content.createEl("div", { cls: "placeholder-text", text: t("domainChart.generateFirst") });
  }
  renderSunburstChart(container = this.container) {
    const getVividAccentColor = (i, total) => {
      return this.generateAccentColor(i, total);
    };
    const containerWidth = container.clientWidth || 500;
    const width = containerWidth * 0.8;
    const height = width;
    const radius = width / 6;
    const svgEl = container.ownerDocument.createElementNS("http://www.w3.org/2000/svg", "svg");
    container.appendChild(svgEl);
    const hierarchyData = this.prepareOptimizedHierarchy();
    const hierarchy2 = hierarchy(hierarchyData).sum((d) => d.value || 0).sort((a2, b) => (b.value || 0) - (a2.value || 0));
    const root2 = partition_default().size([2 * Math.PI, hierarchy2.height + 1])(hierarchy2);
    const arc = arc_default().startAngle((d) => d.x0).endAngle((d) => d.x1).padAngle((d) => Math.min((d.x1 - d.x0) / 2, 5e-3)).padRadius(radius * 1.5).innerRadius((d) => d.y0 * radius).outerRadius((d) => Math.max(d.y0 * radius, d.y1 * radius - 1));
    const arcVisible = (d) => {
      return d.y0 >= 1 && d.x1 > d.x0;
    };
    const labelVisible = (d) => {
      return d.y0 >= 1 && (d.y1 - d.y0) * (d.x1 - d.x0) > 0.03;
    };
    const labelTransform = (d) => {
      const x3 = (d.x0 + d.x1) / 2 * 180 / Math.PI;
      const y3 = (d.y0 + d.y1) / 2 * radius;
      return `rotate(${x3 - 90}) translate(${y3},0) rotate(${x3 < 180 ? 0 : 180})`;
    };
    const svg = select_default2(svgEl);
    svg.attr("width", width).attr("height", height).attr("viewBox", [-width / 2, -height / 2, width, height]).attr("class", "domain-sunburst-chart").style("display", "block").style("margin", "0 auto").style("font", "10px sans-serif");
    const g2 = svg.append("g");
    const descendants = root2.descendants().slice(1);
    const totalTopLevel = hierarchyData.children?.length || 1;
    const paths = g2.selectAll("path").data(descendants).enter().append("path").attr("d", arc).attr("data-index", (d) => {
      let topIndex = 0;
      let ancestor = d;
      while (ancestor.depth > 1 && ancestor.parent) ancestor = ancestor.parent;
      if (ancestor.parent?.children) {
        topIndex = ancestor.parent.children.indexOf(ancestor);
      } else if (ancestor.depth === 1) {
        topIndex = descendants.filter((x3) => x3.depth === 1).indexOf(ancestor);
      }
      return topIndex;
    }).attr("fill", (d) => {
      let topIndex = 0;
      let ancestor = d;
      while (ancestor.depth > 1 && ancestor.parent) ancestor = ancestor.parent;
      if (ancestor.parent?.children) {
        topIndex = ancestor.parent.children.indexOf(ancestor);
      } else if (ancestor.depth === 1) {
        topIndex = descendants.filter((x3) => x3.depth === 1).indexOf(ancestor);
      }
      return getVividAccentColor(topIndex, totalTopLevel);
    }).attr("fill-opacity", (d) => arcVisible(d) ? d.children ? 0.8 : 0.9 : 0).attr("stroke", "var(--background-primary)").attr("stroke-width", 1).attr("pointer-events", (d) => arcVisible(d) ? "auto" : "none").style("cursor", "default").style("transition", "fill 0.3s ease, opacity 0.2s ease, filter 0.2s ease");
    const format2 = format(",d");
    paths.append("title").text((d) => {
      const path2 = d.ancestors().map((ancestor) => ancestor.data.name).reverse().join(" \u2192 ");
      const info = [
        `${path2}`,
        `${format2(d.value || d.data.noteCount || 0)} notes`
      ];
      if (d.data.ddcCode) {
        info.push(`Domain: ${d.data.ddcCode}`);
      }
      if (d.data.avgCentrality !== void 0) {
        info.push(`Centrality: ${d.data.avgCentrality.toFixed(3)}`);
      }
      return info.join("\n");
    });
    const labelGroups = g2.append("g").attr("pointer-events", "none").attr("text-anchor", "middle").style("user-select", "none").selectAll("g").data(root2.descendants().slice(1)).enter().append("g").attr("transform", (d) => labelTransform(d)).style("opacity", (d) => +labelVisible(d));
    labelGroups.each(function(d) {
      const group = select_default2(this);
      const arcSize = (d.y1 - d.y0) * (d.x1 - d.x0);
      const name = d.data.name;
      const availableWidth = Math.max(10, (d.y1 - d.y0) * radius * 0.8);
      const fontSize = Math.max(8, radius * 0.08 * Math.max(0.6, 1 - (d.depth - 1) * 0.1));
      if (arcSize < 0.02) return;
      if (arcSize < 0.1) {
        group.append("text").attr("dy", "0.35em").attr("fill", "var(--chart-text, var(--text-normal))").style("font-size", `${fontSize}px`).style("transition", "fill 0.3s ease").text(name.length > 8 ? name.substring(0, 8) + "..." : name);
        return;
      }
      const words = name.split(/\s+/);
      let lineNumber = 0;
      group.append("text").attr("dy", 0).attr("fill", "var(--chart-text, var(--text-normal))").style("font-size", `${fontSize}px`).style("transition", "fill 0.3s ease").append("tspan").attr("x", 0).attr("y", 0);
      let currentLine = "";
      words.forEach((word) => {
        const testLine = currentLine ? `${currentLine} ${word}` : word;
        const estimatedWidth = testLine.length * (fontSize * 0.6);
        if (estimatedWidth > availableWidth && currentLine) {
          group.select("text").append("tspan").attr("x", 0).attr("y", 0).attr("dy", `${++lineNumber * 1.1}em`).text(currentLine);
          currentLine = word;
        } else {
          currentLine = testLine;
        }
      });
      if (currentLine) {
        group.select("text").append("tspan").attr("x", 0).attr("y", 0).attr("dy", `${lineNumber * 1.1}em`).text(currentLine);
      }
      const textElement = group.select("text");
      const tspanSelection = textElement.selectAll("tspan");
      const numLines = tspanSelection.size();
      if (numLines > 1) {
        const offset = -(numLines - 1) * 0.5 * 1.1;
        tspanSelection.each(function(_d, i) {
          select_default2(this).attr("dy", `${offset + i * 1.1}em`);
        });
      } else {
        textElement.attr("dy", "0.35em");
      }
    });
    const centerRadius = Math.max(radius * 0.9, 40);
    g2.append("circle").datum(root2).attr("r", centerRadius).attr("fill", "var(--chart-background, var(--background-secondary))").attr("stroke", "var(--background-modifier-border)").attr("stroke-width", 2).style("opacity", 0.95).style("cursor", "default").style("transition", "fill 0.3s ease, stroke 0.3s ease");
    const centerInfo = g2.append("g").attr("class", "center-info-panel");
    const updateCenterInfo = (data = null) => {
      centerInfo.selectAll("text").transition().duration(150).style("opacity", 0).remove();
      const textContainer = centerInfo.append("text").attr("text-anchor", "middle").attr("x", 0).attr("y", 0).style("opacity", 0);
      if (data && data !== root2) {
        const percentage = ((data.value || data.data.noteCount || 0) / (root2.value || 1) * 100).toFixed(1);
        const layerNames = ["Root", "Domain", "Subdivision", "User Domain"];
        const layerName = layerNames[data.depth] || `Layer ${data.depth}`;
        const domainName = data.data.name;
        const maxLineLength = 14;
        const nameLines = [];
        if (domainName.length <= maxLineLength) {
          nameLines.push(domainName);
        } else {
          const words = domainName.split(" ");
          let currentLine2 = "";
          for (const word of words) {
            if ((currentLine2 + " " + word).trim().length <= maxLineLength) {
              currentLine2 = currentLine2 ? currentLine2 + " " + word : word;
            } else {
              if (currentLine2) {
                nameLines.push(currentLine2);
              }
              currentLine2 = word;
            }
          }
          if (currentLine2) {
            nameLines.push(currentLine2);
          }
        }
        const lineHeight = "1.2em";
        let currentLine = 0;
        nameLines.forEach((line, index2) => {
          textContainer.append("tspan").attr("x", 0).attr("dy", index2 === 0 ? "0em" : lineHeight).style("font-size", Math.max(centerRadius * 0.16, 10) + "px").style("font-weight", "600").style("fill", "var(--chart-accent-color, var(--text-accent))").style("transition", "fill 0.3s ease").text(line);
          currentLine++;
        });
        const nameBlockHeight = currentLine * 1.2;
        textContainer.attr("y", -(nameBlockHeight / 2) + "em");
        textContainer.append("tspan").attr("x", 0).attr("dy", "1.6em").style("font-size", "1px").text("");
        textContainer.append("tspan").attr("x", 0).attr("dy", "1.2em").style("font-size", Math.max(centerRadius * 0.1, 8) + "px").style("fill", "var(--chart-muted, var(--text-muted))").style("transition", "fill 0.3s ease").text(layerName);
        currentLine++;
        textContainer.append("tspan").attr("x", 0).attr("dy", lineHeight).style("font-size", Math.max(centerRadius * 0.24, 14) + "px").style("font-weight", "700").style("fill", "var(--chart-text, var(--text-normal))").style("transition", "fill 0.3s ease").text(data.value || data.data.noteCount || 0);
        currentLine++;
        textContainer.append("tspan").attr("x", 0).attr("dy", lineHeight).style("font-size", Math.max(centerRadius * 0.1, 7) + "px").style("fill", "var(--text-muted)").text(t("domainChart.notes"));
        currentLine++;
        textContainer.append("tspan").attr("x", 0).attr("dy", lineHeight).style("font-size", Math.max(centerRadius * 0.12, 9) + "px").style("font-weight", "500").style("fill", "var(--text-accent)").text(`${percentage}%`);
        currentLine++;
        if (data.data.avgCentrality !== void 0) {
          textContainer.append("tspan").attr("x", 0).attr("dy", lineHeight).style("font-size", Math.max(centerRadius * 0.09, 7) + "px").style("fill", "var(--text-muted)").text(t("domainChart.centrality", { value: data.data.avgCentrality.toFixed(3) }));
          currentLine++;
        }
        const totalHeight = currentLine * 1.2;
        textContainer.attr("y", -(totalHeight / 2) + "em");
      } else {
        const totalDomainSections = root2.descendants().filter((d) => d.depth > 0).length;
        const layerCount = hierarchy2.height;
        textContainer.append("tspan").attr("x", 0).attr("dy", "0em").style("font-size", Math.max(centerRadius * 0.14, 11) + "px").style("font-weight", "600").style("fill", "var(--text-accent)").text(t("domainChart.knowledgeDomains"));
        if (totalDomainSections > 0) {
          textContainer.append("tspan").attr("x", 0).attr("dy", "1.4em").style("font-size", "1px").text("");
          textContainer.append("tspan").attr("x", 0).attr("dy", "1.2em").style("font-size", Math.max(centerRadius * 0.26, 16) + "px").style("font-weight", "700").style("fill", "var(--text-normal)").text(totalDomainSections.toString());
          textContainer.append("tspan").attr("x", 0).attr("dy", "1.2em").style("font-size", Math.max(centerRadius * 0.12, 9) + "px").style("fill", "var(--text-muted)").text(t("domainChart.subdivisions"));
          textContainer.append("tspan").attr("x", 0).attr("dy", "1.4em").style("font-size", "1px").text("");
          textContainer.append("tspan").attr("x", 0).attr("dy", "1.2em").style("font-size", Math.max(centerRadius * 0.1, 7) + "px").style("fill", "var(--text-muted)").text(t("domainChart.layers", { count: layerCount }));
          textContainer.append("tspan").attr("x", 0).attr("dy", "1.2em").style("font-size", Math.max(centerRadius * 0.08, 6) + "px").style("fill", "var(--text-faint)").text(t("domainChart.hoverExplore"));
        }
        textContainer.attr("y", "-2.5em");
      }
      textContainer.transition().duration(300).style("opacity", 1);
    };
    updateCenterInfo();
    if (this.options.showTooltips) {
      paths.on("mouseover", (event, d) => {
        select_default2(event.currentTarget).style("opacity", 1).style("filter", "brightness(1.1)");
        updateCenterInfo(d);
      }).on("mouseout", (event) => {
        select_default2(event.currentTarget).style("opacity", null).style("filter", "none");
        updateCenterInfo();
      });
    }
  }
  // Prepare optimized hierarchy - data is now pre-built by MasterAnalysisManager
  prepareOptimizedHierarchy() {
    const root2 = { name: "Knowledge Domains", children: [] };
    const convertHierarchy = (nodes) => {
      return nodes.map((node) => {
        const d3Node = {
          name: node.name,
          ddcCode: node.ddcCode,
          noteCount: node.noteCount,
          keywords: node.keywords,
          level: node.level
        };
        if ((node.level === 2 || !node.children || node.children.length === 0) && node.noteCount) {
          d3Node.value = node.noteCount;
        }
        if (node.children && node.children.length > 0) {
          d3Node.children = convertHierarchy(node.children);
        }
        return d3Node;
      });
    };
    if (this.data?.domainHierarchy) {
      root2.children = convertHierarchy(this.data.domainHierarchy);
    }
    return root2;
  }
  async renderWithData(data) {
    this.data = data;
    await this.render();
  }
  setOptions(options) {
    this.options = { ...this.options, ...options };
  }
  updateSettings(settings) {
    this.settings = settings;
  }
  async refresh() {
    if (this.updateColorsInPlace()) {
      return;
    }
    this.container.empty();
    this.data = null;
    await this.render();
  }
  updateColorsInPlace() {
    const svg = this.container.querySelector(".domain-sunburst-chart");
    if (!svg || !this.data?.domainHierarchy) {
      return false;
    }
    try {
      const paths = svg.querySelectorAll("path");
      const totalTopLevel = this.data.domainHierarchy.length;
      paths.forEach((path2) => {
        const pathElement = path2;
        const dataIndex = parseInt(pathElement.getAttribute("data-index") || "0");
        const newColor = this.generateAccentColor(dataIndex, totalTopLevel);
        pathElement.setAttribute("fill", newColor);
      });
      const centerCircle = svg.querySelector("circle");
      if (centerCircle) {
        centerCircle.setAttribute("fill", "var(--chart-background, var(--background-secondary))");
      }
      return true;
    } catch {
      return false;
    }
  }
  // Extract color generation logic for reuse
  generateAccentColor(i, total) {
    if (total <= 1) {
      return `var(--text-accent)`;
    } else if (total <= 3) {
      const opacity = 0.5 + 0.5 * (i / (total - 1));
      return `color-mix(in srgb, var(--text-accent) ${Math.round(opacity * 100)}%, transparent)`;
    } else {
      const mixRatio = 60 + 30 * (i / (total - 1));
      const mixIndex = i % 4;
      const mixColors = ["var(--background-secondary)", "var(--text-muted)", "var(--background-modifier-border)", "var(--background-primary-alt)"];
      return `color-mix(in srgb, var(--text-accent) ${Math.round(mixRatio)}%, ${mixColors[mixIndex]})`;
    }
  }
};

// src/ai/knowledge-domains.json
var knowledge_domains_default = {
  knowledge_domains: {
    title: "Modern Knowledge Taxonomy",
    version: "1.0",
    domains: [
      {
        id: "1",
        name: "Technology & Computing",
        subdivisions: [
          { id: "1-1", name: "Software Development" },
          { id: "1-2", name: "AI & Machine Learning" },
          { id: "1-3", name: "Data Science & Analytics" },
          { id: "1-4", name: "Web & Mobile Development" },
          { id: "1-5", name: "DevOps & Infrastructure" },
          { id: "1-6", name: "Cybersecurity" },
          { id: "1-7", name: "Hardware & Systems" },
          { id: "1-8", name: "Emerging Technology" }
        ]
      },
      {
        id: "2",
        name: "Science & Research",
        subdivisions: [
          { id: "2-1", name: "Mathematics & Statistics" },
          { id: "2-2", name: "Physics & Astronomy" },
          { id: "2-3", name: "Chemistry & Materials" },
          { id: "2-4", name: "Biology & Life Sciences" },
          { id: "2-5", name: "Earth & Environmental Science" },
          { id: "2-6", name: "Research Methods" },
          { id: "2-7", name: "Interdisciplinary Science" }
        ]
      },
      {
        id: "3",
        name: "Business & Economics",
        subdivisions: [
          { id: "3-1", name: "Entrepreneurship & Startups" },
          { id: "3-2", name: "Management & Leadership" },
          { id: "3-3", name: "Marketing & Sales" },
          { id: "3-4", name: "Finance & Investing" },
          { id: "3-5", name: "Economics & Markets" },
          { id: "3-6", name: "Product & Project Management" },
          { id: "3-7", name: "Career & Professional Growth" }
        ]
      },
      {
        id: "4",
        name: "Creative & Design",
        subdivisions: [
          { id: "4-1", name: "Visual Design & Graphics" },
          { id: "4-2", name: "UX & Product Design" },
          { id: "4-3", name: "Writing & Content" },
          { id: "4-4", name: "Music & Audio" },
          { id: "4-5", name: "Photography & Video" },
          { id: "4-6", name: "Architecture & Spaces" },
          { id: "4-7", name: "Crafts & Making" }
        ]
      },
      {
        id: "5",
        name: "Personal Development",
        subdivisions: [
          { id: "5-1", name: "Productivity & Organization" },
          { id: "5-2", name: "Learning & Education" },
          { id: "5-3", name: "Mindfulness & Reflection" },
          { id: "5-4", name: "Communication & Influence" },
          { id: "5-5", name: "Goal Setting & Planning" },
          { id: "5-6", name: "Habits & Behavior Change" }
        ]
      },
      {
        id: "6",
        name: "Health & Wellness",
        subdivisions: [
          { id: "6-1", name: "Physical Fitness & Exercise" },
          { id: "6-2", name: "Nutrition & Diet" },
          { id: "6-3", name: "Mental Health & Psychology" },
          { id: "6-4", name: "Sleep & Recovery" },
          { id: "6-5", name: "Medicine & Healthcare" },
          { id: "6-6", name: "Longevity & Aging" }
        ]
      },
      {
        id: "7",
        name: "Society & Culture",
        subdivisions: [
          { id: "7-1", name: "History & Civilization" },
          { id: "7-2", name: "Politics & Government" },
          { id: "7-3", name: "Sociology & Demographics" },
          { id: "7-4", name: "Language & Linguistics" },
          { id: "7-5", name: "Geography & Places" },
          { id: "7-6", name: "Current Events & News" },
          { id: "7-7", name: "Law & Justice" }
        ]
      },
      {
        id: "8",
        name: "Philosophy & Ideas",
        subdivisions: [
          { id: "8-1", name: "Ethics & Morality" },
          { id: "8-2", name: "Logic & Critical Thinking" },
          { id: "8-3", name: "Metaphysics & Existence" },
          { id: "8-4", name: "Religion & Spirituality" },
          { id: "8-5", name: "Epistemology & Knowledge" },
          { id: "8-6", name: "Aesthetics & Beauty" }
        ]
      },
      {
        id: "9",
        name: "Practical Life",
        subdivisions: [
          { id: "9-1", name: "Home & Living" },
          { id: "9-2", name: "Travel & Exploration" },
          { id: "9-3", name: "Relationships & Social" },
          { id: "9-4", name: "Parenting & Family" },
          { id: "9-5", name: "Hobbies & Recreation" },
          { id: "9-6", name: "Food & Cooking" },
          { id: "9-7", name: "Personal Finance" }
        ]
      },
      {
        id: "10",
        name: "Reference & Meta",
        subdivisions: [
          { id: "10-1", name: "Tools & Resources" },
          { id: "10-2", name: "Templates & Frameworks" },
          { id: "10-3", name: "Indexes & Catalogs" },
          { id: "10-4", name: "People & Biographies" },
          { id: "10-5", name: "Books & Media Reviews" },
          { id: "10-6", name: "Meta & PKM" }
        ]
      }
    ]
  }
};

// src/ai/KnowledgeDomainHelper.ts
var _KnowledgeDomainHelper = class _KnowledgeDomainHelper {
  constructor(app) {
    this.domainTemplate = null;
    this.domains = {};
    this.subdivisions = {};
    this.subdivisionsList = [];
    this.app = app;
  }
  static getInstance(app) {
    if (!_KnowledgeDomainHelper.instance) {
      _KnowledgeDomainHelper.instance = new _KnowledgeDomainHelper(app);
    }
    return _KnowledgeDomainHelper.instance;
  }
  getAllSubdivisions() {
    return this.subdivisionsList;
  }
  async loadDomainTemplate() {
    if (this.domainTemplate) return;
    try {
      const parsed = knowledge_domains_default;
      if (!parsed || typeof parsed !== "object" || !("knowledge_domains" in parsed)) {
        throw new Error("Knowledge domains template has invalid structure. Expected knowledge_domains.");
      }
      this.domainTemplate = parsed;
      this.domains = {};
      this.subdivisions = {};
      this.subdivisionsList = [];
      if (this.domainTemplate?.knowledge_domains?.domains) {
        this.domainTemplate.knowledge_domains.domains.forEach((domain) => {
          this.domains[domain.id] = domain.name;
          domain.subdivisions.forEach((subdivision) => {
            this.subdivisions[subdivision.id] = subdivision.name;
            this.subdivisionsList.push({
              id: subdivision.id,
              name: subdivision.name,
              domain: domain.name,
              domainId: domain.id
            });
          });
        });
      } else {
        throw new Error("Knowledge domains template has invalid structure. Expected knowledge_domains.domains array.");
      }
    } catch (error) {
      this.domainTemplate = null;
      this.domains = {};
      this.subdivisions = {};
      this.subdivisionsList = [];
      throw error;
    }
  }
  async ensureDomainTemplateLoaded() {
    try {
      await this.loadDomainTemplate();
      return true;
    } catch {
      return false;
    }
  }
  getDomainTemplate() {
    return this.domainTemplate;
  }
  isValidSubdivisionId(subdivisionId) {
    if (this.subdivisions[subdivisionId]) return true;
    const parts = subdivisionId.split("-");
    if (parts.length === 2) {
      const domainId = parts[0];
      const subId = parts[1];
      const constructed = `${domainId}-${subId}`;
      if (this.subdivisions[constructed]) return true;
    }
    return false;
  }
  getSubdivisionInfo(subdivisionId) {
    return this.subdivisionsList.find((subdivision) => subdivision.id === subdivisionId) || null;
  }
  getSubdivisionsInDomain(domainId) {
    return this.subdivisionsList.filter((subdivision) => subdivision.domainId === domainId);
  }
  getDomainCodeToNameMap() {
    const map2 = /* @__PURE__ */ new Map();
    this.subdivisionsList.forEach((subdivision) => {
      map2.set(subdivision.id, subdivision.name);
    });
    if (this.domainTemplate && this.domainTemplate.knowledge_domains && this.domainTemplate.knowledge_domains.domains) {
      this.domainTemplate.knowledge_domains.domains.forEach((domain) => {
        map2.set(domain.id, domain.name);
      });
    }
    Object.entries(this.domains).forEach(([code, name]) => {
      map2.set(code, name);
    });
    Object.entries(this.subdivisions).forEach(([code, name]) => {
      map2.set(code, name);
    });
    return map2;
  }
  getDomainIdFromSubdivision(subdivisionId) {
    return subdivisionId.split("-")[0];
  }
};
_KnowledgeDomainHelper.instance = null;
var KnowledgeDomainHelper = _KnowledgeDomainHelper;

// src/components/kde-chart/CentralityKDEChart.ts
var CentralityKDEChart = class {
  constructor(container, data, options = {}) {
    this.svg = null;
    this.tooltip = null;
    this.container = container;
    this.data = data;
    this.options = {
      width: 800,
      height: 400,
      margin: { top: 20, right: 80, bottom: 70, left: 60 },
      ...options
    };
  }
  render() {
    this.container.empty();
    const hasData = this.data.totals.betweenness > 0 || this.data.totals.closeness > 0 || this.data.totals.eigenvector > 0;
    if (!hasData) {
      this.container.createEl("p", {
        text: "No centrality data available for distribution analysis.",
        cls: "kde-chart-no-data"
      });
      return;
    }
    const { width, height, margin } = this.options;
    const innerWidth = width - margin.left - margin.right;
    const innerHeight = height - margin.top - margin.bottom;
    this.svg = select_default2(this.container).append("svg").attr("width", width).attr("height", height).attr("viewBox", `0 0 ${width} ${height}`).attr("style", "max-width: 100%; height: auto;");
    if (!this.svg) return;
    const g2 = this.svg.append("g").attr("transform", `translate(${margin.left},${margin.top})`);
    let maxCount = 0;
    this.data.bins.forEach((bin) => {
      maxCount = Math.max(maxCount, bin.betweenness, bin.closeness, bin.eigenvector);
    });
    const xScale = band().domain(this.data.bins.map((bin) => bin.range)).range([0, innerWidth]).padding(0.1);
    const yScale = linear2().domain([0, maxCount]).nice().range([innerHeight, 0]);
    const generateAccentColorVariant = (index2) => {
      const mixStrategies = [
        // Betweenness: High accent ratio with light background (bright, vibrant)
        { ratio: 85, mixColor: "var(--background-secondary)" },
        // Closeness: Medium accent ratio with muted background (moderate)
        { ratio: 55, mixColor: "var(--text-muted)" },
        // Eigenvector: Lower accent ratio with border color (softer)
        { ratio: 35, mixColor: "var(--background-modifier-border)" }
      ];
      const strategy = mixStrategies[index2];
      return `color-mix(in srgb, var(--text-accent) ${strategy.ratio}%, ${strategy.mixColor})`;
    };
    const colors = {
      betweenness: generateAccentColorVariant(0),
      // Bright, vibrant variant
      closeness: generateAccentColorVariant(1),
      // Moderate variant
      eigenvector: generateAccentColorVariant(2)
      // Softer variant
    };
    const barWidth = xScale.bandwidth() / 3;
    const barOffset = barWidth * 0.1;
    const centralityTypes = [
      { key: "betweenness", color: colors.betweenness, offset: -barWidth },
      { key: "closeness", color: colors.closeness, offset: 0 },
      { key: "eigenvector", color: colors.eigenvector, offset: barWidth }
    ];
    centralityTypes.forEach(({ key, color: color2, offset }) => {
      this.data.bins.forEach((bin, binIndex) => {
        const count2 = bin[key];
        if (count2 > 0) {
          const x3 = (xScale(bin.range) || 0) + barWidth + offset;
          const barHeight = innerHeight - yScale(count2);
          const bar = g2.append("rect").attr("x", x3).attr("y", yScale(count2)).attr("width", barWidth - barOffset * 2).attr("height", barHeight).attr("fill", color2).attr("rx", 2).attr("ry", 2).style("cursor", "pointer");
          bar.on("mouseover", (event) => {
            this.showTooltip(event, bin.range, key, count2);
          }).on("mousemove", (event) => {
            this.updateTooltipPosition(event);
          }).on("mouseout", () => {
            this.hideTooltip();
          });
        }
      });
    });
    const numBins = this.data.bins.length;
    const desiredTicks = Math.min(12, Math.max(5, Math.floor(numBins / 10)));
    const tickStep2 = Math.max(1, Math.floor(numBins / desiredTicks));
    const tickValues = this.data.bins.filter((_, i) => i % tickStep2 === 0 || i === numBins - 1).map((bin) => bin.range);
    const xAxis = axisBottom(xScale).tickValues(tickValues).tickFormat((d) => {
      const range2 = typeof d === "string" ? d : typeof d === "number" ? String(d) : "";
      return range2.split("-")[0] ?? range2;
    });
    const xAxisGroup = g2.append("g").attr("transform", `translate(0,${innerHeight})`).call(xAxis);
    xAxisGroup.selectAll(".tick text").attr("transform", "rotate(-45)").attr("dx", "-0.5em").attr("dy", "0.5em").style("text-anchor", "end").style("font-size", "10px");
    xAxisGroup.append("text").attr("x", innerWidth / 2).attr("y", 50).attr("fill", "var(--text-normal)").style("text-anchor", "middle").style("font-size", "12px").text("Centrality Score Range");
    const yAxis = axisLeft(yScale).ticks(Math.min(10, maxCount)).tickFormat((d) => typeof d === "number" ? String(d) : "");
    const yAxisGroup = g2.append("g").call(yAxis);
    yAxisGroup.selectAll(".tick text").attr("fill", "var(--text-muted)").style("font-size", "11px");
    yAxisGroup.append("text").attr("transform", "rotate(-90)").attr("y", -40).attr("x", -innerHeight / 2).attr("fill", "var(--text-normal)").style("text-anchor", "middle").style("font-size", "12px").text("Number of Notes");
    const legend = g2.append("g").attr("transform", `translate(${innerWidth - 150}, 20)`);
    const legendItems = [
      { label: "Betweenness", color: colors.betweenness },
      { label: "Closeness", color: colors.closeness },
      { label: "Eigenvector", color: colors.eigenvector }
    ];
    legendItems.forEach((item, i) => {
      const legendItem = legend.append("g").attr("transform", `translate(0, ${i * 25})`);
      legendItem.append("rect").attr("x", 0).attr("y", -8).attr("width", 16).attr("height", 16).attr("fill", item.color).attr("rx", 2).attr("ry", 2);
      legendItem.append("text").attr("x", 20).attr("y", 4).attr("fill", "var(--text-normal)").style("font-size", "12px").text(item.label);
    });
    g2.selectAll(".domain, .tick line").attr("stroke", "var(--background-modifier-border)");
  }
  showTooltip(event, range2, centralityType, count2) {
    this.hideTooltip();
    const doc = this.container.ownerDocument;
    const tooltip = doc.createElement("div");
    tooltip.className = "histogram-tooltip";
    const centralityName = centralityType.charAt(0).toUpperCase() + centralityType.slice(1);
    tooltip.createEl("div", { text: `${centralityName} Centrality`, cls: "histogram-tooltip-title" });
    tooltip.createEl("div", { text: `Range: ${range2}`, cls: "histogram-tooltip-range" });
    tooltip.createEl("div", {
      text: `Count: ${count2} note${count2 !== 1 ? "s" : ""}`,
      cls: "histogram-tooltip-count"
    });
    doc.body.appendChild(tooltip);
    this.tooltip = tooltip;
    this.updateTooltipPosition(event);
  }
  updateTooltipPosition(event) {
    if (!this.tooltip) return;
    const rect = this.tooltip.getBoundingClientRect();
    const x3 = event.pageX - rect.width / 2;
    const y3 = event.pageY - rect.height - 10;
    this.tooltip.style.setProperty("left", `${x3}px`);
    this.tooltip.style.setProperty("top", `${y3}px`);
  }
  hideTooltip() {
    if (this.tooltip) {
      this.tooltip.remove();
      this.tooltip = null;
    }
  }
  destroy() {
    this.hideTooltip();
    if (this.svg) {
      this.svg.remove();
      this.svg = null;
    }
    this.container.empty();
  }
};

// src/ai/visualization/KnowledgeStructureManager.ts
var KnowledgeStructureManager = class {
  constructor(app, settings, dataStore, createEmptyStateFn) {
    this.domainHierarchy = [];
    this.domainConnections = [];
    this.data = null;
    this.app = app;
    this.settings = settings;
    this.dataStore = dataStore;
    this.createEmptyStateFn = createEmptyStateFn || this.defaultCreateEmptyState.bind(this);
  }
  /**
   * Default empty state implementation for when no callback is provided
   */
  defaultCreateEmptyState(container, message) {
    const doc = container.ownerDocument;
    const emptyState = doc.createElement("div");
    emptyState.className = "network-empty-state";
    container.appendChild(emptyState);
    const iconEl = doc.createElement("div");
    iconEl.className = "network-empty-state-icon";
    emptyState.appendChild(iconEl);
    (0, import_obsidian9.setIcon)(iconEl, "bar-chart-2");
    const textEl = doc.createElement("p");
    textEl.className = "network-empty-state-text";
    textEl.textContent = message;
    emptyState.appendChild(textEl);
  }
  async loadCachedStructureData() {
    try {
      const tab = await this.dataStore.getTabAnalysis("structure");
      if (tab?.knowledgeStructure) {
        this.data = tab.knowledgeStructure;
        return this.data;
      }
      return null;
    } catch {
      return null;
    }
  }
  async renderStructureAnalysis(container) {
    this.container = container;
    this.container.empty();
    if (!this.data) {
      await this.loadCachedStructureData();
    }
    await this.createKnowledgeDomainDistributionSection();
    await this.createKnowledgeNetworkAnalysisSection();
    await this.createKnowledgeGapSection();
  }
  /**
   * Section 1: Knowledge Domain Distribution
   */
  async createKnowledgeDomainDistributionSection() {
    const section = this.container.createEl("div", {
      cls: "vault-analysis-section"
    });
    section.createEl("h3", {
      text: t("structure.domainDistribution"),
      cls: "vault-analysis-section-title"
    });
    await this.createDomainDistributionChart(section);
  }
  /**
   * Create domain distribution chart - centralized method
   * Uses vault analysis data directly without relying on cached structure files
   * @param preloadedData - Optional vault analysis data to avoid re-reading from disk
   */
  async createDomainDistributionChart(container, preloadedData, preloadedDomain) {
    try {
      const domainData = preloadedDomain ?? await this.buildDomainHierarchyFromVaultAnalysis(preloadedData);
      if (!domainData || !domainData.domainHierarchy || domainData.domainHierarchy.length === 0) {
        this.createEmptyStateFn(container, "Generate vault analysis to see your knowledge domain distribution.");
        return;
      }
      const chartContainer = container.createEl("div", {
        cls: "domain-chart-container"
      });
      const domainChart = new DomainDistributionChart(
        this.app,
        this.settings,
        chartContainer,
        {
          chartType: "sunburst",
          showTooltips: true,
          showLabels: true
        }
      );
      await this.scheduleChartRender(container, () => domainChart.renderWithData(domainData));
    } catch (err) {
      const errorMsg = container.createEl("div", { cls: "error-message" });
      const errorMessage = err instanceof Error ? err.message : String(err);
      errorMsg.createEl("p", {
        text: `Failed to create domain chart: ${errorMessage}`,
        cls: "error-text"
      });
    }
  }
  /**
   * Build domain hierarchy from vault analysis data
   * This is now centralized in KnowledgeStructureManager
   * @param preloadedData - Optional vault analysis data to avoid re-reading from disk
   */
  async buildDomainHierarchyFromVaultAnalysis(preloadedData) {
    try {
      const raw = preloadedData ?? await this.dataStore.getVaultAnalysis();
      if (!raw) {
        return null;
      }
      const analysisData = raw;
      if (!analysisData?.results || analysisData.results.length === 0) {
        return null;
      }
      const domainHelper = KnowledgeDomainHelper.getInstance(this.app);
      await domainHelper.ensureDomainTemplateLoaded();
      const domainMap = /* @__PURE__ */ new Map();
      const subdivisionMap = /* @__PURE__ */ new Map();
      const subdivisionCounts = /* @__PURE__ */ new Map();
      const subdivisionNotes = /* @__PURE__ */ new Map();
      const nameToCodeMap = /* @__PURE__ */ new Map();
      const codeToNameMap = domainHelper.getDomainCodeToNameMap();
      const domainTemplate = domainHelper.getDomainTemplate();
      if (domainTemplate?.knowledge_domains?.domains) {
        domainTemplate.knowledge_domains.domains.forEach((domain) => {
          codeToNameMap.set(domain.id, domain.name);
        });
      }
      codeToNameMap.forEach((name, code) => {
        nameToCodeMap.set(name, code);
      });
      analysisData.results.forEach((note) => {
        if (note.knowledgeDomains && note.knowledgeDomains.length > 0) {
          note.knowledgeDomains.forEach((domain) => {
            let subdivisionId = "";
            if (domainHelper.isValidSubdivisionId(domain)) {
              subdivisionId = domain;
            } else if (nameToCodeMap.has(domain)) {
              subdivisionId = nameToCodeMap.get(domain) || "";
            } else {
              return;
            }
            if (!subdivisionId) return;
            const domainId = domainHelper.getDomainIdFromSubdivision(subdivisionId);
            subdivisionCounts.set(subdivisionId, (subdivisionCounts.get(subdivisionId) || 0) + 1);
            if (!subdivisionNotes.has(subdivisionId)) {
              subdivisionNotes.set(subdivisionId, []);
            }
            subdivisionNotes.get(subdivisionId)?.push(note);
            if (!domainMap.has(domainId)) {
              const domainName = codeToNameMap.get(domainId) || domainId;
              domainMap.set(domainId, {
                ddcCode: domainId,
                name: domainName,
                noteCount: 0,
                level: 1,
                children: []
              });
            }
            if (!subdivisionMap.has(subdivisionId)) {
              const subdivisionNode = {
                ddcCode: subdivisionId,
                name: codeToNameMap.get(subdivisionId) || subdivisionId,
                noteCount: 0,
                level: 2,
                parent: domainMap.get(domainId)?.ddcCode
              };
              subdivisionMap.set(subdivisionId, subdivisionNode);
              domainMap.get(domainId)?.children?.push(subdivisionNode);
            }
            const subdivision = subdivisionMap.get(subdivisionId);
            if (subdivision) {
              subdivision.noteCount += 1;
            }
            const domainNode = domainMap.get(domainId);
            if (domainNode) {
              domainNode.noteCount += 1;
            }
          });
        }
      });
      subdivisionMap.forEach((subdivision, subdivisionId) => {
        const notes = subdivisionNotes.get(subdivisionId) || [];
        const keywords = /* @__PURE__ */ new Set();
        notes.forEach((note) => {
          if (note.keywords) {
            note.keywords.split(",").forEach((keyword) => {
              const trimmed = keyword.trim();
              if (trimmed) keywords.add(trimmed);
            });
          }
        });
        subdivision.keywords = Array.from(keywords);
      });
      const domainHierarchy = Array.from(domainMap.values()).filter((d) => d.noteCount > 0).sort((a2, b) => b.noteCount - a2.noteCount);
      return {
        domainHierarchy,
        domainConnections: []
      };
    } catch {
      return null;
    }
  }
  /**
   * Section 2: Knowledge Network Analysis
   */
  async createKnowledgeNetworkAnalysisSection(customContainer) {
    const targetContainer = customContainer || this.container;
    const hasKDEChart = targetContainer.querySelector(".kde-chart-container") !== null;
    let section;
    if (hasKDEChart) {
      section = targetContainer;
    } else {
      section = targetContainer.createEl("div", {
        cls: "vault-analysis-section vault-analysis-section--network-cards"
      });
      section.createEl("h3", {
        text: t("structure.networkAnalysis"),
        cls: "vault-analysis-section-title"
      });
      await this.renderKDEDistributionChart(section);
    }
    const networkData = this.data?.knowledgeNetwork;
    if (!networkData || !networkData.bridges?.length && !networkData.foundations?.length && !networkData.authorities?.length) {
      if (!hasKDEChart) {
        this.createEmptyStateFn(section, "Generate AI analysis to identify knowledge bridges, foundations, and authorities in your vault's network structure.");
      }
      return;
    }
    section.addClass("vault-analysis-section--network-cards");
    this.renderNetworkCards(section, networkData);
  }
  /**
   * Render KDE distribution chart for centrality scores
   * This method fetches data directly from vault-analysis.json and displays independently of AI analysis
   * @param preloadedData - Optional vault analysis data to avoid re-reading from disk
   */
  async renderKDEDistributionChart(section, preloadedData, preloadedCentrality) {
    try {
      const analysisData = preloadedData ?? await this.dataStore.getVaultAnalysis();
      if (!analysisData) {
        return;
      }
      const kdeService = new KDECalculationService();
      const histogramResults = preloadedCentrality?.histogram ?? kdeService.calculateHistogramDistributions(analysisData);
      const hasData = histogramResults.totals.betweenness > 0 || histogramResults.totals.closeness > 0 || histogramResults.totals.eigenvector > 0;
      if (!hasData) {
        return;
      }
      const chartContainer = section.createEl("div", { cls: "kde-chart-container" });
      const titleContainer = chartContainer.createEl("div", { cls: "kde-chart-title-container" });
      const iconEl = titleContainer.createEl("div", { cls: "kde-chart-icon" });
      (0, import_obsidian9.setIcon)(iconEl, "bar-chart-2");
      titleContainer.createEl("h4", {
        text: t("structure.centralityDistributions"),
        cls: "kde-chart-title"
      });
      const svgContainer = chartContainer.createEl("div", { cls: "kde-chart-svg-container" });
      const chart = new CentralityKDEChart(svgContainer, histogramResults, {
        width: 800,
        height: 400
      });
      await this.scheduleChartRender(chartContainer, () => {
        chart.render();
        return Promise.resolve();
      });
      const structuredStats = preloadedCentrality?.stats ?? kdeService.getStructuredStats(analysisData);
      this.renderInsightsPanel(chartContainer, structuredStats);
    } catch {
    }
  }
  scheduleChartRender(container, fn) {
    return new Promise((resolve, reject) => {
      const win = container.ownerDocument.defaultView ?? window;
      const run = () => {
        try {
          resolve(fn());
        } catch (e) {
          reject(e instanceof Error ? e : new Error(String(e)));
        }
      };
      if (typeof win.requestAnimationFrame === "function") {
        win.requestAnimationFrame(run);
      } else {
        run();
      }
    });
  }
  /**
   * Render insights panel with statistical information below the chart
   */
  renderInsightsPanel(container, stats) {
    const insightsContainer = container.createEl("div", { cls: "kde-chart-insights" });
    const centralityTypes = [
      { key: "betweenness", name: "Betweenness Centrality", icon: "git-branch" },
      { key: "closeness", name: "Closeness Centrality", icon: "target" },
      { key: "eigenvector", name: "Eigenvector Centrality", icon: "star" }
    ];
    centralityTypes.forEach(({ key, name, icon }) => {
      const stat = stats[key];
      if (!stat) return;
      const card = insightsContainer.createEl("div", { cls: "kde-chart-insight-card" });
      const header = card.createEl("div", { cls: "kde-chart-insight-header" });
      const iconEl = header.createEl("div", { cls: "kde-chart-insight-icon" });
      (0, import_obsidian9.setIcon)(iconEl, icon);
      const titleEl = header.createEl("span", { cls: "kde-chart-insight-title" });
      titleEl.textContent = name;
      const statsLine = card.createEl("div", { cls: "kde-chart-insight-stats" });
      const statsParts = [
        `N=${stat.count}`,
        `Mean: ${stat.mean.toFixed(3)}`,
        `Range: ${stat.range.min.toFixed(2)}-${stat.range.max.toFixed(2)}`,
        stat.distribution
      ];
      statsParts.forEach((part) => {
        const span = statsLine.createEl("span");
        span.textContent = part;
      });
      const interpretationEl = card.createEl("div", { cls: "kde-chart-insight-interpretation" });
      interpretationEl.textContent = stat.interpretation;
    });
  }
  /**
   * Render network analysis in tabbed card-based layout
   */
  renderNetworkCards(section, networkData) {
    const tabs = [
      {
        id: "bridges",
        label: "Knowledge Bridges",
        icon: "route",
        description: "Domains that connect different areas of knowledge",
        data: networkData.bridges || []
      },
      {
        id: "foundations",
        label: "Knowledge Foundations",
        icon: "star",
        description: "Core domains that serve as central access points",
        data: networkData.foundations || []
      },
      {
        id: "authorities",
        label: "Knowledge Authorities",
        icon: "orbit",
        description: "Influential domains with high connectivity",
        data: networkData.authorities || []
      }
    ];
    const tabsContainer = this.container.ownerDocument.createElement("div");
    tabsContainer.className = "knowledge-network-tabs-container";
    section.appendChild(tabsContainer);
    const tabBar = this.container.ownerDocument.createElement("div");
    tabBar.className = "knowledge-network-tab-bar";
    tabsContainer.appendChild(tabBar);
    const contentContainer = this.container.ownerDocument.createElement("div");
    contentContainer.className = "knowledge-network-tab-content";
    tabsContainer.appendChild(contentContainer);
    const tabButtons = /* @__PURE__ */ new Map();
    const tabPanels = /* @__PURE__ */ new Map();
    const activeTabId = tabs.find((tab) => tab.data.length > 0)?.id || tabs[0].id;
    tabs.forEach((tab) => {
      const tabButton = this.createTabButton(tab, tab.id === activeTabId);
      tabBar.appendChild(tabButton);
      tabButtons.set(tab.id, tabButton);
      const tabPanel = this.container.ownerDocument.createElement("div");
      tabPanel.className = `knowledge-network-tab-panel ${tab.id}${tab.id === activeTabId ? " active" : ""}`;
      contentContainer.appendChild(tabPanel);
      tabPanels.set(tab.id, tabPanel);
      tabButton.addEventListener("click", (e) => {
        e.preventDefault();
        e.stopPropagation();
        this.switchNetworkTab(tab.id, tabs, tabButtons, tabPanels);
      });
    });
    tabs.forEach((tab) => {
      const panel = tabPanels.get(tab.id);
      if (!panel) return;
      if (tab.data.length > 0) {
        const cardsContainer = this.container.ownerDocument.createElement("div");
        cardsContainer.className = "knowledge-network-cards-container network-cards-container";
        panel.appendChild(cardsContainer);
        tab.data.forEach((node) => {
          this.createDomainCard(cardsContainer, tab.id, node);
        });
      } else {
        const emptyState = this.container.ownerDocument.createElement("div");
        emptyState.className = "network-empty-state";
        const iconEl = this.container.ownerDocument.createElement("div");
        iconEl.className = "network-empty-state-icon";
        (0, import_obsidian9.setIcon)(iconEl, tab.icon);
        emptyState.appendChild(iconEl);
        const textEl = this.container.ownerDocument.createElement("p");
        textEl.className = "network-empty-state-text";
        textEl.textContent = `No ${tab.label.toLowerCase()} found.`;
        emptyState.appendChild(textEl);
        panel.appendChild(emptyState);
      }
    });
  }
  /**
   * Create a tab button element
   */
  createTabButton(tab, isActive) {
    const tabButton = this.container.ownerDocument.createElement("button");
    tabButton.className = `knowledge-network-tab ${isActive ? "active" : ""}`;
    tabButton.setAttribute("data-tab-id", tab.id);
    const iconEl = this.container.ownerDocument.createElement("span");
    (0, import_obsidian9.setIcon)(iconEl, tab.icon);
    tabButton.appendChild(iconEl);
    const labelEl = this.container.ownerDocument.createElement("span");
    labelEl.textContent = tab.label;
    tabButton.appendChild(labelEl);
    return tabButton;
  }
  /**
   * Switch to a different tab
   */
  switchNetworkTab(tabId, tabs, tabButtons, tabPanels) {
    tabs.forEach((tab) => {
      const btn = tabButtons.get(tab.id);
      const panel = tabPanels.get(tab.id);
      if (!btn || !panel) return;
      const isActive = tab.id === tabId;
      btn.classList.toggle("active", isActive);
      panel.classList.toggle("active", isActive);
    });
  }
  /**
   * Create a card for a specific network category
   */
  createNetworkCard(parent, type2, title, description, nodes) {
    const card = this.container.ownerDocument.createElement("div");
    card.className = "network-card";
    parent.appendChild(card);
    const header = this.container.ownerDocument.createElement("div");
    header.className = "network-card-header";
    card.appendChild(header);
    const iconEl = this.container.ownerDocument.createElement("div");
    iconEl.className = "network-card-icon";
    header.appendChild(iconEl);
    if (type2 === "bridges") {
      (0, import_obsidian9.setIcon)(iconEl, "route");
    } else if (type2 === "foundations") {
      (0, import_obsidian9.setIcon)(iconEl, "star");
    } else if (type2 === "authorities") {
      (0, import_obsidian9.setIcon)(iconEl, "orbit");
    }
    const titleContainer = this.container.ownerDocument.createElement("div");
    titleContainer.className = "network-card-title-container";
    header.appendChild(titleContainer);
    const titleEl = this.container.ownerDocument.createElement("h4");
    titleEl.className = "network-card-title";
    titleEl.textContent = title;
    titleContainer.appendChild(titleEl);
    const metaContainer = this.container.ownerDocument.createElement("div");
    metaContainer.className = "network-card-meta";
    titleContainer.appendChild(metaContainer);
    const countEl = this.container.ownerDocument.createElement("span");
    countEl.className = "network-card-count";
    countEl.textContent = `${nodes.length} domain${nodes.length !== 1 ? "s" : ""}`;
    metaContainer.appendChild(countEl);
    const descEl = this.container.ownerDocument.createElement("span");
    descEl.className = "network-card-description";
    descEl.textContent = description;
    metaContainer.appendChild(descEl);
    const content = this.container.ownerDocument.createElement("div");
    content.className = "network-card-content";
    card.appendChild(content);
    nodes.slice(0, 3).forEach((node) => {
      const domainItem = this.container.ownerDocument.createElement("div");
      domainItem.className = "network-domain-item";
      content.appendChild(domainItem);
      const domainHeader = this.container.ownerDocument.createElement("div");
      domainHeader.className = "network-domain-header";
      domainItem.appendChild(domainHeader);
      const domainName = this.container.ownerDocument.createElement("strong");
      domainName.className = "network-domain-name";
      domainName.textContent = node.domain;
      domainHeader.appendChild(domainName);
      const explanation = this.container.ownerDocument.createElement("p");
      explanation.className = "network-domain-explanation";
      explanation.textContent = node.explanation;
      domainItem.appendChild(explanation);
      if (node.topNotes && node.topNotes.length > 0) {
        const notesSection = this.container.ownerDocument.createElement("div");
        notesSection.className = "network-notes-section";
        domainItem.appendChild(notesSection);
        const notesHeader = this.container.ownerDocument.createElement("div");
        notesHeader.className = "network-notes-header";
        notesSection.appendChild(notesHeader);
        const notesIcon = this.container.ownerDocument.createElement("span");
        notesHeader.appendChild(notesIcon);
        (0, import_obsidian9.setIcon)(notesIcon, "file-text");
        const notesText = this.container.ownerDocument.createElement("span");
        notesText.textContent = "Top notes";
        notesHeader.appendChild(notesText);
        const notesList = this.container.ownerDocument.createElement("ul");
        notesList.className = "network-notes-list";
        notesSection.appendChild(notesList);
        node.topNotes.slice(0, 3).forEach((note) => {
          const noteItem = this.container.ownerDocument.createElement("li");
          noteItem.className = "network-note-item";
          notesList.appendChild(noteItem);
          const noteLink = this.container.ownerDocument.createElement("span");
          noteLink.className = "network-note-link";
          noteLink.textContent = note.title;
          noteItem.appendChild(noteLink);
          noteLink.addEventListener("click", () => {
            void (async () => {
              try {
                const tFile = this.app.vault.getFileByPath(note.path);
                if (tFile) {
                  const leaf = this.app.workspace.getLeaf(false);
                  await leaf.openFile(tFile);
                } else {
                  await this.app.workspace.openLinkText(note.title, "");
                }
              } catch {
                try {
                  await this.app.workspace.openLinkText(note.path, "");
                } catch {
                }
              }
            })();
          });
        });
      }
      if (node.connections && node.connections.length > 0) {
        const connectionsSection = this.container.ownerDocument.createElement("div");
        connectionsSection.className = "network-connections-section";
        domainItem.appendChild(connectionsSection);
        const connectionsHeader = this.container.ownerDocument.createElement("div");
        connectionsHeader.className = "network-connections-header";
        connectionsSection.appendChild(connectionsHeader);
        const connectionsIcon = this.container.ownerDocument.createElement("span");
        connectionsHeader.appendChild(connectionsIcon);
        (0, import_obsidian9.setIcon)(connectionsIcon, "link");
        const connectionsText = this.container.ownerDocument.createElement("span");
        connectionsText.textContent = "Connections";
        connectionsHeader.appendChild(connectionsText);
        const connectionsList = this.container.ownerDocument.createElement("div");
        connectionsList.className = "network-connections-list";
        connectionsSection.appendChild(connectionsList);
        node.connections.forEach((connection) => {
          const connectionItem = this.container.ownerDocument.createElement("span");
          connectionItem.className = "network-connection-item";
          connectionItem.textContent = connection;
          connectionsList.appendChild(connectionItem);
        });
      }
      if (node.coverage && node.coverage.length > 0) {
        const coverageSection = this.container.ownerDocument.createElement("div");
        coverageSection.className = "network-coverage-section";
        domainItem.appendChild(coverageSection);
        const coverageHeader = this.container.ownerDocument.createElement("div");
        coverageHeader.className = "network-coverage-header";
        coverageSection.appendChild(coverageHeader);
        const coverageIcon = this.container.ownerDocument.createElement("span");
        coverageHeader.appendChild(coverageIcon);
        (0, import_obsidian9.setIcon)(coverageIcon, "layers");
        const coverageText = this.container.ownerDocument.createElement("span");
        coverageText.textContent = "Coverage";
        coverageHeader.appendChild(coverageText);
        const coverageList = this.container.ownerDocument.createElement("div");
        coverageList.className = "network-coverage-list";
        coverageSection.appendChild(coverageList);
        node.coverage.forEach((coverage) => {
          const coverageItem = this.container.ownerDocument.createElement("span");
          coverageItem.className = "network-coverage-item";
          coverageItem.textContent = coverage;
          coverageList.appendChild(coverageItem);
        });
      }
      if (node.influence && node.influence.length > 0) {
        const influenceSection = this.container.ownerDocument.createElement("div");
        influenceSection.className = "network-influence-section";
        domainItem.appendChild(influenceSection);
        const influenceHeader = this.container.ownerDocument.createElement("div");
        influenceHeader.className = "network-influence-header";
        influenceSection.appendChild(influenceHeader);
        const influenceIcon = this.container.ownerDocument.createElement("span");
        influenceHeader.appendChild(influenceIcon);
        (0, import_obsidian9.setIcon)(influenceIcon, "zap");
        const influenceText = this.container.ownerDocument.createElement("span");
        influenceText.textContent = "Influence";
        influenceHeader.appendChild(influenceText);
        const influenceList = this.container.ownerDocument.createElement("div");
        influenceList.className = "network-influence-list";
        influenceSection.appendChild(influenceList);
        node.influence.forEach((influence) => {
          const influenceItem = this.container.ownerDocument.createElement("span");
          influenceItem.className = "network-influence-item";
          influenceItem.textContent = influence;
          influenceList.appendChild(influenceItem);
        });
      }
      if (node.insights) {
        const insightsSection = this.container.ownerDocument.createElement("div");
        insightsSection.className = "network-insights-section";
        domainItem.appendChild(insightsSection);
        const insightsHeader = this.container.ownerDocument.createElement("div");
        insightsHeader.className = "network-insights-header";
        insightsSection.appendChild(insightsHeader);
        const insightsIcon = this.container.ownerDocument.createElement("span");
        insightsHeader.appendChild(insightsIcon);
        (0, import_obsidian9.setIcon)(insightsIcon, "lightbulb");
        const insightsText = this.container.ownerDocument.createElement("span");
        insightsText.textContent = "Insights";
        insightsHeader.appendChild(insightsText);
        const insightsContent = this.container.ownerDocument.createElement("p");
        insightsContent.className = "network-insights-content";
        insightsContent.textContent = node.insights;
        insightsSection.appendChild(insightsContent);
      }
    });
  }
  /**
   * Section 3: Knowledge Gap Analysis
   */
  createKnowledgeGapSection() {
    const section = this.container.createEl("div", {
      cls: "vault-analysis-section"
    });
    section.createEl("h3", {
      text: t("structure.gapAnalysis"),
      cls: "vault-analysis-section-title"
    });
    if (this.data?.gaps && this.data.gaps.length > 0) {
      const gapsContainer = section.createEl("div", {
        cls: "ai-insights-container"
      });
      const titleEl = gapsContainer.createEl("h4", {
        cls: "ai-insights-title"
      });
      const iconEl = titleEl.createEl("span", { cls: "ai-insights-icon" });
      (0, import_obsidian9.setIcon)(iconEl, "target");
      titleEl.createEl("span", { text: t("structure.identifiedGaps") });
      const gapsList = gapsContainer.createEl("ul", {
        cls: "gaps-list"
      });
      this.data.gaps.slice(0, 8).forEach((gap) => {
        gapsList.createEl("li", { text: gap });
      });
    } else {
      this.createEmptyStateFn(section, "Generate AI analysis to identify potential knowledge gaps and areas for expansion in your vault.");
    }
    return Promise.resolve();
  }
  /**
   * Create a card for a single domain node (used in tabbed view)
   */
  createDomainCard(parent, type2, node) {
    const card = this.container.ownerDocument.createElement("div");
    card.className = "network-card network-card-standalone";
    parent.appendChild(card);
    const tempContainer = this.container.ownerDocument.createElement("div");
    card.appendChild(tempContainer);
    const content = this.container.ownerDocument.createElement("div");
    content.className = "network-card-content network-card-content-padded";
    tempContainer.appendChild(content);
    const domainHeader = this.container.ownerDocument.createElement("div");
    domainHeader.className = "network-domain-header";
    content.appendChild(domainHeader);
    const domainName = this.container.ownerDocument.createElement("strong");
    domainName.className = "network-domain-name";
    domainName.textContent = node.domain;
    domainHeader.appendChild(domainName);
    const explanation = this.container.ownerDocument.createElement("p");
    explanation.className = "network-domain-explanation";
    explanation.textContent = node.explanation;
    content.appendChild(explanation);
    if (node.topNotes && node.topNotes.length > 0) {
      const notesSection = this.container.ownerDocument.createElement("div");
      notesSection.className = "network-notes-section";
      content.appendChild(notesSection);
      const notesHeader = this.container.ownerDocument.createElement("div");
      notesHeader.className = "network-notes-header";
      notesSection.appendChild(notesHeader);
      const notesIcon = this.container.ownerDocument.createElement("span");
      notesHeader.appendChild(notesIcon);
      (0, import_obsidian9.setIcon)(notesIcon, "file-text");
      const notesText = this.container.ownerDocument.createElement("span");
      notesText.textContent = "Top notes";
      notesHeader.appendChild(notesText);
      const notesList = this.container.ownerDocument.createElement("ul");
      notesList.className = "network-notes-list";
      notesSection.appendChild(notesList);
      node.topNotes.slice(0, 3).forEach((note) => {
        const noteItem = this.container.ownerDocument.createElement("li");
        noteItem.className = "network-note-item";
        notesList.appendChild(noteItem);
        const noteLink = this.container.ownerDocument.createElement("span");
        noteLink.className = "network-note-link";
        noteLink.textContent = note.title;
        noteItem.appendChild(noteLink);
        noteLink.addEventListener("click", () => {
          void (async () => {
            try {
              const tFile = this.app.vault.getFileByPath(note.path);
              if (tFile) {
                const leaf = this.app.workspace.getLeaf(false);
                await leaf.openFile(tFile);
              } else {
                await this.app.workspace.openLinkText(note.title, "");
              }
            } catch {
            }
          })();
        });
      });
    }
    this.addNodeSections(content, node);
  }
  addNodeSections(container, node) {
    if (node.connections && node.connections.length > 0) {
      this.addSection(container, "Connections", "link", node.connections);
    }
    if (node.coverage && node.coverage.length > 0) {
      this.addSection(container, "Coverage", "layers", node.coverage);
    }
    if (node.influence && node.influence.length > 0) {
      this.addSection(container, "Influence", "zap", node.influence);
    }
    if (node.insights) {
      const insightsSection = this.container.ownerDocument.createElement("div");
      insightsSection.className = "network-insights-section";
      container.appendChild(insightsSection);
      const insightsHeader = this.container.ownerDocument.createElement("div");
      insightsHeader.className = "network-insights-header";
      insightsSection.appendChild(insightsHeader);
      const insightsIcon = this.container.ownerDocument.createElement("span");
      insightsHeader.appendChild(insightsIcon);
      (0, import_obsidian9.setIcon)(insightsIcon, "lightbulb");
      const insightsText = this.container.ownerDocument.createElement("span");
      insightsText.textContent = "Insights";
      insightsHeader.appendChild(insightsText);
      const insightsContent = this.container.ownerDocument.createElement("div");
      insightsContent.className = "network-insights-content";
      insightsContent.textContent = node.insights;
      insightsSection.appendChild(insightsContent);
    }
  }
  addSection(container, title, iconName, items) {
    const section = this.container.ownerDocument.createElement("div");
    section.className = "network-connections-section";
    container.appendChild(section);
    const header = this.container.ownerDocument.createElement("div");
    header.className = "network-connections-header";
    section.appendChild(header);
    const icon = this.container.ownerDocument.createElement("span");
    header.appendChild(icon);
    (0, import_obsidian9.setIcon)(icon, iconName);
    const text = this.container.ownerDocument.createElement("span");
    text.textContent = title;
    header.appendChild(text);
    const list = this.container.ownerDocument.createElement("div");
    list.className = "network-connections-list";
    section.appendChild(list);
    items.forEach((item) => {
      const itemEl = this.container.ownerDocument.createElement("span");
      itemEl.className = "network-connection-item";
      itemEl.textContent = item;
      list.appendChild(itemEl);
    });
  }
  updateSettings(settings) {
    this.settings = settings;
  }
  setData(data) {
    this.data = data;
  }
  setDomainHierarchy(hierarchy2) {
    this.domainHierarchy = hierarchy2;
  }
  setDomainConnections(connections) {
    this.domainConnections = connections;
  }
  async renderWithData(container, data, domainHierarchy) {
    this.data = data;
    if (domainHierarchy) {
      this.domainHierarchy = domainHierarchy;
    }
    await this.renderStructureAnalysis(container);
  }
  /**
   * Public method to render just the network analysis section
   */
  async renderNetworkAnalysis(container, data) {
    this.container = container;
    if (data) {
      this.data = data;
    }
    if (!this.data) {
      await this.loadCachedStructureData();
    }
    const hasKDEChart = container.querySelector(".kde-chart-container") !== null;
    if (!hasKDEChart) {
      container.empty();
    }
    if (!this.data) {
      if (!hasKDEChart) {
        this.createEmptyStateFn(container, "Generate AI analysis to identify knowledge bridges, foundations, and authorities in your vault's network structure.");
      }
      return;
    }
    await this.createKnowledgeNetworkAnalysisSection(container);
  }
};

// src/services/VisualizationDerivationService.ts
var VisualizationDerivationService = class _VisualizationDerivationService {
  constructor(app, dataStore) {
    this.app = app;
    this.dataStore = dataStore;
    this.kdeService = new KDECalculationService();
  }
  static reviveCalendarDays(serialized) {
    return serialized.map((day) => ({
      date: new Date(day.date),
      value: day.value,
      wordCount: day.wordCount,
      fileCount: day.fileCount
    }));
  }
  static serializeCalendarDays(calendar) {
    return calendar.map((day) => ({
      date: day.date.toISOString().split("T")[0],
      value: day.value,
      wordCount: day.wordCount,
      fileCount: day.fileCount
    }));
  }
  static buildCalendarSummaryContext(analysisData, calendar) {
    const totalNotes = analysisData.results.length;
    const totalWords = calendar.reduce((sum2, day) => sum2 + day.wordCount, 0);
    const createdTimes = analysisData.results.map((r) => new Date(r.created).getTime()).filter((t2) => !isNaN(t2));
    let vaultDurationDays = 0;
    if (createdTimes.length > 0) {
      const first = Math.min(...createdTimes);
      vaultDurationDays = Math.ceil((Date.now() - first) / (1e3 * 3600 * 24));
    }
    return { totalNotes, totalWords, vaultDurationDays };
  }
  isStale(analysisData, cached) {
    if (!cached) {
      return true;
    }
    return cached.sourceAnalysisId !== generateVaultAnalysisId(analysisData);
  }
  async compute(analysisData) {
    const domainDistribution = await this.buildDomainHierarchy(analysisData);
    const { histogram, stats } = this.kdeService.computeCentralityInsights(analysisData);
    const calendar = this.buildCalendarFromVaultAnalysis(analysisData);
    return {
      sourceAnalysisId: generateVaultAnalysisId(analysisData),
      computedAt: (/* @__PURE__ */ new Date()).toISOString(),
      domainDistribution: domainDistribution ?? { domainHierarchy: [], domainConnections: [] },
      centralityHistogram: histogram,
      centralityStats: stats,
      calendar: _VisualizationDerivationService.serializeCalendarDays(calendar)
    };
  }
  async computeIfStale(analysisData, cached) {
    const existing = cached ?? await this.dataStore.getDerivedVisualizations();
    if (!this.isStale(analysisData, existing)) {
      return existing;
    }
    return this.compute(analysisData);
  }
  async computeAndPersist(analysisData) {
    const derived = await this.compute(analysisData);
    await this.dataStore.setDerivedVisualizations(derived);
    return derived;
  }
  async buildDomainHierarchy(analysisData) {
    if (!analysisData?.results?.length) {
      return null;
    }
    try {
      const domainHelper = KnowledgeDomainHelper.getInstance(this.app);
      await domainHelper.ensureDomainTemplateLoaded();
      const domainMap = /* @__PURE__ */ new Map();
      const subdivisionMap = /* @__PURE__ */ new Map();
      const subdivisionNotes = /* @__PURE__ */ new Map();
      const nameToCodeMap = /* @__PURE__ */ new Map();
      const codeToNameMap = domainHelper.getDomainCodeToNameMap();
      const domainTemplate = domainHelper.getDomainTemplate();
      if (domainTemplate?.knowledge_domains?.domains) {
        domainTemplate.knowledge_domains.domains.forEach((domain) => {
          codeToNameMap.set(domain.id, domain.name);
        });
      }
      codeToNameMap.forEach((name, code) => {
        nameToCodeMap.set(name, code);
      });
      analysisData.results.forEach((note) => {
        if (!note.knowledgeDomains?.length) {
          return;
        }
        note.knowledgeDomains.forEach((domain) => {
          let subdivisionId = "";
          if (domainHelper.isValidSubdivisionId(domain)) {
            subdivisionId = domain;
          } else if (nameToCodeMap.has(domain)) {
            subdivisionId = nameToCodeMap.get(domain) || "";
          } else {
            return;
          }
          if (!subdivisionId) {
            return;
          }
          const domainId = domainHelper.getDomainIdFromSubdivision(subdivisionId);
          if (!subdivisionNotes.has(subdivisionId)) {
            subdivisionNotes.set(subdivisionId, []);
          }
          subdivisionNotes.get(subdivisionId)?.push(note);
          if (!domainMap.has(domainId)) {
            const domainName = codeToNameMap.get(domainId) || domainId;
            domainMap.set(domainId, {
              ddcCode: domainId,
              name: domainName,
              noteCount: 0,
              level: 1,
              children: []
            });
          }
          if (!subdivisionMap.has(subdivisionId)) {
            const subdivisionNode = {
              ddcCode: subdivisionId,
              name: codeToNameMap.get(subdivisionId) || subdivisionId,
              noteCount: 0,
              level: 2,
              parent: domainMap.get(domainId)?.ddcCode
            };
            subdivisionMap.set(subdivisionId, subdivisionNode);
            domainMap.get(domainId)?.children?.push(subdivisionNode);
          }
          const subdivision = subdivisionMap.get(subdivisionId);
          if (subdivision) {
            subdivision.noteCount += 1;
          }
          const domainNode = domainMap.get(domainId);
          if (domainNode) {
            domainNode.noteCount += 1;
          }
        });
      });
      subdivisionMap.forEach((subdivision, subdivisionId) => {
        const notes = subdivisionNotes.get(subdivisionId) || [];
        const keywords = /* @__PURE__ */ new Set();
        notes.forEach((note) => {
          if (note.keywords) {
            note.keywords.split(",").forEach((keyword) => {
              const trimmed = keyword.trim();
              if (trimmed) {
                keywords.add(trimmed);
              }
            });
          }
        });
        subdivision.keywords = Array.from(keywords);
      });
      const domainHierarchy = Array.from(domainMap.values()).filter((d) => d.noteCount > 0).sort((a2, b) => b.noteCount - a2.noteCount);
      return {
        domainHierarchy,
        domainConnections: []
      };
    } catch {
      return null;
    }
  }
  buildCalendarFromVaultAnalysis(analysisData) {
    const dailyActivity = /* @__PURE__ */ new Map();
    for (const note of analysisData.results) {
      if (!note.created) {
        continue;
      }
      const createdDate = new Date(note.created);
      if (isNaN(createdDate.getTime())) {
        continue;
      }
      const dateKey = createdDate.toISOString().split("T")[0];
      const charCount = note.charCount ?? 0;
      let dayData = dailyActivity.get(dateKey);
      if (!dayData) {
        dayData = {
          date: new Date(dateKey),
          value: 0,
          wordCount: 0,
          fileCount: 0
        };
        dailyActivity.set(dateKey, dayData);
      }
      dayData.wordCount += charCount;
      dayData.fileCount += 1;
      dayData.value = dayData.wordCount;
    }
    const dailyActivities = Array.from(dailyActivity.values());
    dailyActivities.sort((a2, b) => a2.date.getTime() - b.date.getTime());
    return dailyActivities;
  }
};

// src/views/VaultAnalysisModals.ts
var VaultAnalysisModal = class extends import_obsidian10.Modal {
  constructor(app, analysisData, hasExistingData, vaultSemanticAnalysisManager, settings, dataStore, initialView = "semantic") {
    super(app);
    this.currentView = "semantic";
    this.analysisResultsContainer = null;
    this.knowledgeEvolutionData = null;
    this.derivedVisualizations = null;
    this.derivedSourceAnalysisId = null;
    // Tab-specific analysis data
    this.structureAnalysisData = null;
    this.evolutionAnalysisData = null;
    this.actionsAnalysisData = null;
    this.knowledgeStructureManager = null;
    // Pagination state
    this.currentPage = 1;
    this.itemsPerPage = 20;
    this.filteredResults = [];
    this.paginationContainer = null;
    this.resultsSection = null;
    this.resultsContainer = null;
    this.resultsWrapper = null;
    this.analysisData = analysisData;
    this.hasExistingData = hasExistingData;
    this.vaultSemanticAnalysisManager = vaultSemanticAnalysisManager;
    this.settings = settings;
    this.masterAnalysisManager = new MasterAnalysisManager(app, settings, dataStore);
    this.pluginDataStore = dataStore;
    this.visualizationDerivation = new VisualizationDerivationService(app, dataStore);
    this.currentView = initialView;
  }
  /** Get the plugin instance (a Component) for MarkdownRenderer lifecycle management */
  get markdownComponent() {
    const plugins = this.app.plugins?.plugins;
    const plugin = plugins?.["knowledge-graph-analysis"];
    if (!plugin || !(plugin instanceof import_obsidian10.Component)) {
      throw new Error("Plugin not found or not a Component - cannot render markdown safely");
    }
    return plugin;
  }
  async ensureDerivedVisualizations() {
    if (!this.analysisData?.results?.length) {
      return null;
    }
    const currentId = generateVaultAnalysisId(this.analysisData);
    if (this.derivedVisualizations && this.derivedSourceAnalysisId === currentId) {
      return this.derivedVisualizations;
    }
    const cached = await this.pluginDataStore.getDerivedVisualizations();
    if (cached && cached.sourceAnalysisId === currentId) {
      this.derivedVisualizations = cached;
      this.derivedSourceAnalysisId = currentId;
      return cached;
    }
    try {
      const derived = await this.visualizationDerivation.computeIfStale(this.analysisData, cached);
      if (derived) {
        await this.pluginDataStore.setDerivedVisualizations(derived);
        this.derivedVisualizations = derived;
        this.derivedSourceAnalysisId = currentId;
      }
      return derived;
    } catch {
      return null;
    }
  }
  getCalendarDataFromDerived(derived) {
    const calendar = VisualizationDerivationService.reviveCalendarDays(derived.calendar);
    KnowledgeCalendarChart.setCachedCalendar(derived.sourceAnalysisId, calendar);
    return calendar;
  }
  async renderCalendarChart(chartContainer, derived) {
    const calendarChart = new KnowledgeCalendarChart(this.app, chartContainer, { cellSize: 11 });
    if (derived && this.analysisData) {
      const calendarData = this.getCalendarDataFromDerived(derived);
      const summary = VisualizationDerivationService.buildCalendarSummaryContext(
        this.analysisData,
        calendarData
      );
      await calendarChart.renderWithData(calendarData, summary);
      return;
    }
    await calendarChart.render();
  }
  onOpen() {
    const { contentEl, modalEl } = this;
    contentEl.empty();
    modalEl.addClass("vault-analysis-modal");
    contentEl.addClass("vault-analysis-modal-content");
    this.createHeader(contentEl);
    this.contentContainer = contentEl.createEl("div", {
      cls: "vault-analysis-content-container"
    });
    void this.loadView(this.currentView);
    if (this.hasExistingData && this.analysisData) {
      void this.ensureDerivedVisualizations();
    }
  }
  createHeader(container) {
    const headerContainer = container.createEl("div", {
      cls: "vault-analysis-header"
    });
    const headerRow = headerContainer.createEl("div", {
      cls: "vault-analysis-header-row"
    });
    const titleIcon = headerRow.createEl("div", {
      cls: "vault-analysis-main-icon"
    });
    (0, import_obsidian10.setIcon)(titleIcon, "waypoints");
    const navContainer = headerRow.createEl("div", {
      cls: "vault-analysis-nav"
    });
    const tabs = [
      { id: "semantic", label: t("vaultAnalysis.tabSemantic"), icon: "search" },
      { id: "structure", label: t("vaultAnalysis.tabStructure"), icon: "layout-panel-top" },
      { id: "evolution", label: t("vaultAnalysis.tabEvolution"), icon: "trending-up" },
      { id: "actions", label: t("vaultAnalysis.tabActions"), icon: "lightbulb" }
    ];
    tabs.forEach((tab) => {
      const isDisabled = tab.id !== "semantic" && !this.hasExistingData;
      const tabButton = navContainer.createEl("button", {
        cls: `vault-analysis-tab${this.currentView === tab.id ? " active" : ""}${isDisabled ? " is-disabled" : ""}`,
        text: tab.label
      });
      const icon = tabButton.createEl("span", { cls: "tab-icon" });
      (0, import_obsidian10.setIcon)(icon, tab.icon);
      tabButton.prepend(icon);
      if (isDisabled) {
        tabButton.setAttribute("aria-disabled", "true");
        tabButton.setAttribute("title", t("vaultAnalysis.tabDisabledTitle"));
      } else {
        tabButton.addEventListener("click", () => {
          void this.switchView(tab.id);
        });
      }
    });
  }
  async switchView(viewId) {
    this.currentView = viewId;
    const tabs = this.contentEl.querySelectorAll(".vault-analysis-tab");
    tabs.forEach((tab) => {
      tab.removeClass("active");
    });
    const activeTab = this.contentEl.querySelector(`.vault-analysis-tab:nth-child(${["semantic", "structure", "evolution", "actions"].indexOf(viewId) + 1})`);
    if (activeTab) {
      activeTab.addClass("active");
    }
    await this.loadView(viewId);
  }
  async loadView(viewId) {
    this.contentContainer.empty();
    switch (viewId) {
      case "semantic":
        await this.loadSemanticAnalysisView();
        break;
      case "structure":
        await this.loadKnowledgeStructureView();
        break;
      case "evolution":
        await this.loadKnowledgeEvolutionView();
        break;
      case "actions":
        await this.loadRecommendedActionsView();
        break;
      default:
        await this.loadSemanticAnalysisView();
    }
  }
  async loadSemanticAnalysisView() {
    if (!this.hasExistingData || !this.analysisData) {
      this.showEmptyState();
      return;
    }
    const summarySection = this.contentContainer.createEl("div", {
      cls: "vault-analysis-section"
    });
    summarySection.createEl("h3", {
      text: t("vaultAnalysis.summary"),
      cls: "vault-analysis-section-title"
    });
    const summaryContainer = summarySection.createEl("div", {
      cls: "vault-analysis-summary"
    });
    summaryContainer.createEl("p", {
      text: `Total files analyzed: ${this.analysisData.totalFiles}`
    });
    const generatedFiles = this.analysisData.generatedFiles ?? this.analysisData.totalFiles;
    summaryContainer.createEl("p", {
      text: `Generated: ${generatedFiles} files on ${new Date(this.analysisData.generatedAt).toLocaleString()}`
    });
    if (this.analysisData.updatedAt) {
      const updatedFiles = this.analysisData.updatedFiles ?? 0;
      summaryContainer.createEl("p", {
        text: `Updated: ${updatedFiles} files on ${new Date(this.analysisData.updatedAt).toLocaleString()}`
      });
    }
    summaryContainer.createEl("p", {
      text: `API Provider: ${this.analysisData.apiProvider}`
    });
    if (this.analysisData.tokenUsage) {
      const { promptTokens, candidatesTokens, totalTokens } = this.analysisData.tokenUsage;
      const formatted = (n) => n.toLocaleString();
      summaryContainer.createEl("p", {
        text: `Token usage: ${formatted(totalTokens)} (prompt: ${formatted(promptTokens)} + output: ${formatted(candidatesTokens)})`
      });
    }
    const searchSection = this.contentContainer.createEl("div", {
      cls: "vault-analysis-section"
    });
    searchSection.createEl("h3", {
      text: t("vaultAnalysis.searchFilter"),
      cls: "vault-analysis-section-title"
    });
    const searchContainer = searchSection.createEl("div", {
      cls: "vault-analysis-search"
    });
    const searchInput = searchContainer.createEl("input", {
      type: "text",
      placeholder: "Search notes by title, keywords, or domain...",
      cls: "vault-analysis-search-input"
    });
    this.resultsSection = this.contentContainer.createEl("div", {
      cls: "vault-analysis-section vault-analysis-results-section"
    });
    this.resultsSection.createEl("h3", {
      text: t("vaultAnalysis.results"),
      cls: "vault-analysis-section-title"
    });
    this.resultsWrapper = this.resultsSection.createEl("div", {
      cls: "vault-analysis-results-wrapper"
    });
    this.resultsContainer = this.resultsWrapper.createEl("div", {
      cls: "vault-analysis-results"
    });
    const displayResults = (filteredResults) => {
      this.filteredResults = filteredResults;
      this.currentPage = 1;
      if (filteredResults.length === 0) {
        if (this.resultsContainer) {
          this.resultsContainer.empty();
          this.resultsContainer.createEl("p", {
            text: t("vaultAnalysis.noSearchResults"),
            cls: "no-results"
          });
        }
        if (this.paginationContainer) {
          this.paginationContainer.remove();
          this.paginationContainer = null;
        }
        return;
      }
      this.renderCurrentPage();
      const totalPages = Math.ceil(filteredResults.length / this.itemsPerPage);
      const totalResults = filteredResults.length;
      if (this.resultsSection) {
        if (this.paginationContainer) {
          this.paginationContainer.remove();
          this.paginationContainer = null;
        }
        this.createPaginationControls(this.resultsSection, totalPages, totalResults);
      }
    };
    this.currentPage = 1;
    displayResults(this.analysisData.results);
    const buttonWrapper = this.contentContainer.createEl("div", { cls: "semantic-update-button-wrapper" });
    await this.createUpdateAnalysisButtonSection(buttonWrapper, "semantic", false, true);
    void this.vaultSemanticAnalysisManager.hasPendingSemanticChanges(this.analysisData).then((isOutdated) => {
      buttonWrapper.empty();
      void this.createUpdateAnalysisButtonSection(buttonWrapper, "semantic", isOutdated);
    });
    searchInput.addEventListener("input", (e) => {
      const searchTerm = e.target.value.toLowerCase();
      this.currentPage = 1;
      if (!searchTerm || !this.analysisData?.results) {
        displayResults(this.analysisData?.results || []);
        return;
      }
      const filteredResults = this.analysisData.results.filter(
        (result) => result.title.toLowerCase().includes(searchTerm) || result.summary.toLowerCase().includes(searchTerm) || result.keywords.toLowerCase().includes(searchTerm) || result.knowledgeDomains && result.knowledgeDomains.some(
          (domain) => domain.toLowerCase().includes(searchTerm)
        )
      );
      displayResults(filteredResults);
    });
  }
  renderCurrentPage() {
    if (!this.resultsContainer) return;
    const startIndex = (this.currentPage - 1) * this.itemsPerPage;
    const endIndex = startIndex + this.itemsPerPage;
    const paginatedResults = this.filteredResults.slice(startIndex, endIndex);
    this.resultsContainer.empty();
    paginatedResults.forEach((result) => {
      const resultItem = this.resultsContainer.createEl("div", {
        cls: "vault-analysis-result-item"
      });
      const titleEl = resultItem.createEl("h3", {
        text: result.title,
        cls: "result-title"
      });
      titleEl.addEventListener("click", () => {
        const file = this.app.vault.getAbstractFileByPath(result.path);
        if (file) {
          void this.app.workspace.openLinkText(file.path, "").then(() => this.close());
        }
      });
      resultItem.createEl("p", {
        text: result.summary,
        cls: "result-summary"
      });
      resultItem.createEl("p", {
        text: `Keywords: ${result.keywords}`,
        cls: "result-keywords"
      });
      resultItem.createEl("p", {
        text: `Knowledge Domain: ${(result.knowledgeDomains && result.knowledgeDomains.length > 0 ? result.knowledgeDomains.join(", ") : "Unknown").replace(/\s*\([^)]*\)/g, "")}`,
        cls: "result-domain"
      });
      if (result.graphMetrics) {
        const metrics = [
          { key: "degreeCentrality", label: "Degree" },
          { key: "betweennessCentrality", label: "Betweenness" },
          { key: "closenessCentrality", label: "Closeness" },
          { key: "eigenvectorCentrality", label: "Eigenvector" }
        ];
        const metricValues = metrics.map((metric) => {
          const value = result.graphMetrics[metric.key];
          return value !== void 0 && value !== null ? `${metric.label}-${value.toFixed(3)}` : null;
        }).filter(Boolean);
        if (metricValues.length > 0) {
          resultItem.createEl("p", {
            text: `Graph Centrality Metrics: ${metricValues.join(", ")}`,
            cls: "result-domain"
          });
        }
      }
      const metaContainer = resultItem.createEl("div", {
        cls: "result-meta"
      });
      metaContainer.createEl("span", {
        text: `${result.charCount ?? result.wordCount ?? 0} chars`,
        cls: "result-word-count"
      });
      const dateInfo = [];
      if (result.created) {
        dateInfo.push(`Created: ${new Date(result.created).toLocaleDateString()}`);
      }
      if (result.modified) {
        dateInfo.push(`Modified: ${new Date(result.modified).toLocaleDateString()}`);
      }
      if (dateInfo.length > 0) {
        metaContainer.createEl("span", {
          text: ` \u2022 ${dateInfo.join(" \u2022 ")}`,
          cls: "result-date"
        });
      }
    });
  }
  createPaginationControls(parentContainer, totalPages, totalResults) {
    if (this.paginationContainer) {
      this.paginationContainer.remove();
      this.paginationContainer = null;
    }
    if (totalPages <= 1 || totalResults === 0) {
      return;
    }
    this.paginationContainer = parentContainer.createEl("div", {
      cls: "vault-analysis-pagination"
    });
    const controlsWrapper = this.paginationContainer.createEl("div", {
      cls: "pagination-controls"
    });
    const prevButton = controlsWrapper.createEl("button", {
      text: t("vaultAnalysis.previous"),
      cls: "pagination-button pagination-prev"
    });
    prevButton.disabled = this.currentPage === 1;
    prevButton.addEventListener("click", () => {
      if (this.currentPage > 1) {
        this.updatePage(this.currentPage - 1);
      }
    });
    const pageNumbersContainer = controlsWrapper.createEl("div", {
      cls: "pagination-page-numbers"
    });
    let startPage = Math.max(1, this.currentPage - 2);
    let endPage = Math.min(totalPages, this.currentPage + 2);
    if (endPage - startPage < 4) {
      if (startPage === 1) {
        endPage = Math.min(totalPages, startPage + 4);
      } else if (endPage === totalPages) {
        startPage = Math.max(1, endPage - 4);
      }
    }
    if (startPage > 1) {
      const firstButton = pageNumbersContainer.createEl("button", {
        text: "1",
        cls: "pagination-page-number"
      });
      firstButton.addEventListener("click", () => {
        this.updatePage(1);
      });
      if (startPage > 2) {
        pageNumbersContainer.createEl("span", {
          text: "...",
          cls: "pagination-ellipsis"
        });
      }
    }
    for (let i = startPage; i <= endPage; i++) {
      const pageButton = pageNumbersContainer.createEl("button", {
        text: i.toString(),
        cls: `pagination-page-number ${i === this.currentPage ? "active" : ""}`
      });
      if (i === this.currentPage) {
        pageButton.classList.add("active");
      }
      pageButton.addEventListener("click", () => {
        this.updatePage(i);
      });
    }
    if (endPage < totalPages) {
      if (endPage < totalPages - 1) {
        pageNumbersContainer.createEl("span", {
          text: "...",
          cls: "pagination-ellipsis"
        });
      }
      const lastButton = pageNumbersContainer.createEl("button", {
        text: totalPages.toString(),
        cls: "pagination-page-number"
      });
      lastButton.addEventListener("click", () => {
        this.updatePage(totalPages);
      });
    }
    const nextButton = controlsWrapper.createEl("button", {
      text: t("vaultAnalysis.next"),
      cls: "pagination-button pagination-next"
    });
    nextButton.disabled = this.currentPage === totalPages;
    nextButton.addEventListener("click", () => {
      if (this.currentPage < totalPages) {
        this.updatePage(this.currentPage + 1);
      }
    });
    const startIndex = (this.currentPage - 1) * this.itemsPerPage + 1;
    const endIndex = Math.min(this.currentPage * this.itemsPerPage, totalResults);
    this.paginationContainer.createEl("div", {
      text: `Page ${this.currentPage} of ${totalPages} (showing ${startIndex}-${endIndex} of ${totalResults} items)`,
      cls: "pagination-info"
    });
  }
  updatePage(newPage) {
    if (!this.resultsSection || !this.resultsContainer) return;
    this.currentPage = newPage;
    this.renderCurrentPage();
    const totalPages = Math.ceil(this.filteredResults.length / this.itemsPerPage);
    const totalResults = this.filteredResults.length;
    if (this.resultsSection) {
      if (this.paginationContainer) {
        this.paginationContainer.remove();
        this.paginationContainer = null;
      }
      this.createPaginationControls(this.resultsSection, totalPages, totalResults);
    }
  }
  showEmptyState() {
    const placeholderContainer = this.contentContainer.createEl("div", {
      cls: "vault-analysis-placeholder"
    });
    placeholderContainer.createEl("h3", {
      text: t("vaultAnalysis.noAnalysisYet")
    });
    placeholderContainer.createEl("p", {
      text: t("vaultAnalysis.generatePrompt")
    });
    this.createActionButtons();
  }
  createActionButtons() {
    const buttonContainer = this.contentContainer.createEl("div", {
      cls: "modal-button-container"
    });
    const actionButton = buttonContainer.createEl("button", {
      text: this.hasExistingData ? "Update Analysis" : "Generate Analysis",
      cls: "mod-cta"
    });
    actionButton.addEventListener("click", () => {
      this.close();
      void (async () => {
        try {
          const success = await this.vaultSemanticAnalysisManager.generateVaultAnalysis();
          if (success) {
            await this.vaultSemanticAnalysisManager.viewVaultAnalysisResults();
          }
        } catch {
        }
      })();
    });
  }
  async loadKnowledgeStructureView() {
    const structureContainer = this.contentContainer.createEl("div", {
      cls: "knowledge-structure-container vault-analysis-scroll-container"
    });
    if (!this.hasExistingData || !this.analysisData) {
      this.showStructureEmptyState(structureContainer);
      return;
    }
    const domainDistributionSection = structureContainer.createEl("div", {
      cls: "vault-analysis-section"
    });
    domainDistributionSection.createEl("h3", {
      text: t("vaultAnalysis.domainDistribution"),
      cls: "vault-analysis-section-title"
    });
    const networkAnalysisSection = structureContainer.createEl("div", {
      cls: "vault-analysis-section"
    });
    networkAnalysisSection.createEl("h3", {
      text: t("vaultAnalysis.networkAnalysis"),
      cls: "vault-analysis-section-title"
    });
    const gapsSection = structureContainer.createEl("div", {
      cls: "vault-analysis-section"
    });
    gapsSection.createEl("h3", {
      text: t("vaultAnalysis.knowledgeGaps"),
      cls: "vault-analysis-section-title"
    });
    try {
      this.structureAnalysisData = await this.masterAnalysisManager.loadCachedTabAnalysis("structure", this.analysisData);
      if (this.structureAnalysisData) {
      } else {
      }
    } catch {
      this.structureAnalysisData = null;
    }
    if (!this.knowledgeStructureManager) {
      this.knowledgeStructureManager = new KnowledgeStructureManager(this.app, this.settings, this.pluginDataStore, this.createEmptyState.bind(this));
    }
    const derived = await this.ensureDerivedVisualizations();
    const centralityPreload = derived ? { histogram: derived.centralityHistogram, stats: derived.centralityStats } : void 0;
    await Promise.all([
      this.knowledgeStructureManager.createDomainDistributionChart(
        domainDistributionSection,
        this.analysisData ?? void 0,
        derived?.domainDistribution
      ),
      this.knowledgeStructureManager.renderKDEDistributionChart(
        networkAnalysisSection,
        this.analysisData ?? void 0,
        centralityPreload
      )
    ]);
    if (this.structureAnalysisData?.knowledgeStructure) {
      await Promise.all([
        this.displayNetworkAnalysis(networkAnalysisSection),
        this.displayKnowledgeGaps(gapsSection)
      ]);
      await this.createUpdateAnalysisButtonSection(
        structureContainer,
        "structure",
        this.structureAnalysisData?.isOutdated ?? false
      );
    } else {
      this.showNetworkAnalysisPlaceholder(networkAnalysisSection);
      this.showKnowledgeGapsPlaceholder(gapsSection);
      await this.createAnalysisButtonSection(structureContainer, "structure");
    }
  }
  /**
   * Display network analysis from cached structure analysis data
   */
  async displayNetworkAnalysis(container) {
    if (!this.structureAnalysisData?.knowledgeStructure?.knowledgeNetwork) {
      this.showNetworkAnalysisPlaceholder(container);
      return;
    }
    if (!this.knowledgeStructureManager) {
      this.knowledgeStructureManager = new KnowledgeStructureManager(this.app, this.settings, this.pluginDataStore, this.createEmptyState.bind(this));
    }
    await this.knowledgeStructureManager.renderNetworkAnalysis(container, this.structureAnalysisData.knowledgeStructure);
  }
  /**
   * Display knowledge gaps from cached structure analysis data
   */
  displayKnowledgeGaps(container) {
    if (!this.structureAnalysisData?.knowledgeStructure?.gaps) {
      this.showKnowledgeGapsPlaceholder(container);
      return Promise.resolve();
    }
    const gaps = this.structureAnalysisData.knowledgeStructure.gaps;
    if (gaps && gaps.length > 0) {
      const gapsContainer = container.createEl("div", {
        cls: "ai-insights-container"
      });
      const titleEl = gapsContainer.createEl("h4", {
        cls: "ai-insights-title"
      });
      const iconEl = titleEl.createEl("span", { cls: "ai-insights-icon" });
      (0, import_obsidian10.setIcon)(iconEl, "target");
      titleEl.createEl("span", { text: t("vaultAnalysis.identifiedGaps") });
      const gapsList = gapsContainer.createEl("ul", {
        cls: "gaps-list"
      });
      gaps.slice(0, 8).forEach((gap) => {
        gapsList.createEl("li", { text: gap });
      });
    } else {
      this.showKnowledgeGapsPlaceholder(container);
    }
    return Promise.resolve();
  }
  /**
   * Create a consistent empty state with icon and message for all analysis tabs
   * Public method to be used by all knowledge analysis components
   */
  createEmptyState(container, message) {
    const doc = container.ownerDocument;
    const emptyState = doc.createElement("div");
    emptyState.className = "network-empty-state";
    container.appendChild(emptyState);
    const iconEl = doc.createElement("div");
    iconEl.className = "network-empty-state-icon";
    emptyState.appendChild(iconEl);
    (0, import_obsidian10.setIcon)(iconEl, "bar-chart-2");
    const textEl = doc.createElement("p");
    textEl.className = "network-empty-state-text";
    textEl.textContent = message;
    emptyState.appendChild(textEl);
  }
  /**
   * Show placeholder for network analysis section
   * Uses the centralized empty state method
   * Note: KDE chart is already displayed above, so this placeholder is for AI-generated network cards
   */
  showNetworkAnalysisPlaceholder(container) {
    const hasContent = container.querySelector(".kde-chart-container") !== null;
    if (hasContent) {
      const separator = container.createEl("div", { cls: "network-placeholder-separator" });
      this.createEmptyState(
        separator,
        "Generate AI analysis to identify knowledge bridges, foundations, and authorities in your vault's network structure."
      );
    } else {
      this.createEmptyState(
        container,
        "Generate AI analysis to identify knowledge bridges, foundations, and authorities in your vault's network structure."
      );
    }
  }
  /**
   * Show placeholder for knowledge gaps section
   * Uses the centralized empty state method
   */
  showKnowledgeGapsPlaceholder(container) {
    this.createEmptyState(
      container,
      "Generate AI analysis to identify potential knowledge gaps and areas for expansion in your vault."
    );
  }
  showStructureEmptyState(container) {
    const emptyState = container.createEl("div", {
      cls: "vault-analysis-placeholder"
    });
    emptyState.createEl("h3", {
      text: t("vaultAnalysis.structureEmptyTitle"),
      cls: "vault-analysis-section-title"
    });
    emptyState.createEl("p", {
      text: t("vaultAnalysis.structureEmptyDesc"),
      cls: "analysis-required"
    });
    const featureList = emptyState.createEl("ul", { cls: "feature-list" });
    const features = [
      t("vaultAnalysis.structureFeatureSunburst"),
      t("vaultAnalysis.structureFeatureNetwork"),
      t("vaultAnalysis.structureFeatureGaps"),
      t("vaultAnalysis.structureFeatureDistribution")
    ];
    features.forEach((feature) => {
      featureList.createEl("li", { text: feature });
    });
    const actionsSection = container.createEl("div", {
      cls: "vault-analysis-section"
    });
    actionsSection.createEl("h3", {
      text: t("vaultAnalysis.actions"),
      cls: "vault-analysis-section-title"
    });
    const originalContentContainer = this.contentContainer;
    this.contentContainer = actionsSection;
    this.createActionButtons();
    this.contentContainer = originalContentContainer;
  }
  createUpdateAnalysisButtonSection(container, tabName = "", isOutdated = false, isChecking = false) {
    const buttonContainer = container.createEl("div", {
      cls: "modal-button-container"
    });
    const statusIndicator = buttonContainer.createEl("div", {
      cls: "analysis-status-indicator"
    });
    if (this.vaultSemanticAnalysisManager.isAnalysisInProgress()) {
      statusIndicator.addClass("status-outdated");
      statusIndicator.createSpan({ cls: "status-dot" });
      statusIndicator.appendText(" Analysis in progress");
      const disabledButton = buttonContainer.createEl("button", {
        cls: "mod-cta is-disabled",
        text: t("vaultAnalysis.processing")
      });
      disabledButton.disabled = true;
      return Promise.resolve();
    }
    if (isChecking) {
      statusIndicator.addClass("status-outdated");
      statusIndicator.createSpan({ cls: "status-dot" });
      statusIndicator.appendText(" Checking for updates...");
      const disabledButton = buttonContainer.createEl("button", {
        cls: "mod-cta is-disabled",
        text: t("vaultAnalysis.updateAnalysis")
      });
      disabledButton.disabled = true;
      return Promise.resolve();
    }
    if (!isOutdated) {
      statusIndicator.addClass("status-current");
      statusIndicator.createSpan({ cls: "status-dot" });
      statusIndicator.appendText(" Analysis is current");
    } else {
      statusIndicator.addClass("status-outdated");
      statusIndicator.createSpan({ cls: "status-dot" });
      statusIndicator.appendText(" Analysis needs update");
    }
    const updateButton = buttonContainer.createEl("button", {
      cls: "mod-cta",
      text: t("vaultAnalysis.updateAnalysis")
    });
    if (!isOutdated) {
      updateButton.disabled = true;
      updateButton.addClass("is-disabled");
      updateButton.setAttribute("title", "Analysis is up to date with current vault");
    } else {
      updateButton.setAttribute("title", "Click to update analysis with recent vault changes");
    }
    updateButton.addEventListener("click", () => {
      if (updateButton.disabled) return;
      if (tabName === "semantic") {
        this.close();
        void (async () => {
          try {
            const success = await this.vaultSemanticAnalysisManager.generateVaultAnalysis();
            if (success) {
              await this.vaultSemanticAnalysisManager.viewVaultAnalysisResults();
            }
          } catch {
          }
        })();
        return;
      }
      if (tabName === "structure" || tabName === "evolution" || tabName === "actions") {
        const tabDisplayName = this.getTabDisplayName(tabName);
        new import_obsidian10.Notice(t("notices.updatingTabAnalysis", { tab: tabDisplayName }));
        this.vaultSemanticAnalysisManager.setAnalysisInProgress(tabName);
        this.close();
        void (async () => {
          try {
            if (tabName === "structure") {
              await this.masterAnalysisManager.generateKnowledgeStructureAnalysis();
            } else if (tabName === "evolution") {
              await this.masterAnalysisManager.generateKnowledgeEvolutionAnalysis();
            } else if (tabName === "actions") {
              await this.masterAnalysisManager.generateRecommendedActionsAnalysis();
            }
            await this.vaultSemanticAnalysisManager.reopenVaultAnalysisToTab(tabName);
          } catch (error) {
            new import_obsidian10.Notice(getUserFriendlyMessage(error instanceof Error ? error : new Error(String(error))));
          } finally {
            this.vaultSemanticAnalysisManager.clearAnalysisInProgress();
          }
        })();
      } else {
        void this.triggerAIAnalysis(buttonContainer, true, tabName);
      }
    });
    return Promise.resolve();
  }
  createAnalysisButtonSection(container, tabName = "") {
    const infoSection = container.createEl("div", {
      cls: "vault-analysis-section"
    });
    const infoContainer = infoSection.createEl("div", {
      cls: "vault-analysis-summary"
    });
    infoContainer.createEl("p", {
      text: t("vaultAnalysis.privacyNote1"),
      cls: "analysis-info-text"
    });
    infoContainer.createEl("p", {
      text: t("vaultAnalysis.privacyNote2"),
      cls: "analysis-info-text"
    });
    const buttonContainer = container.createEl("div", {
      cls: "modal-button-container"
    });
    const statusIndicator = buttonContainer.createEl("div", {
      cls: "analysis-status-indicator"
    });
    if (this.vaultSemanticAnalysisManager.isAnalysisInProgress()) {
      statusIndicator.addClass("status-outdated");
      statusIndicator.createSpan({ cls: "status-dot" });
      statusIndicator.appendText(" Analysis in progress");
      const disabledButton = buttonContainer.createEl("button", {
        cls: "mod-cta is-disabled",
        text: t("vaultAnalysis.processing")
      });
      disabledButton.disabled = true;
      return Promise.resolve();
    }
    statusIndicator.addClass("status-empty");
    statusIndicator.createSpan({ cls: "status-dot" });
    statusIndicator.appendText(" Analysis not generated yet");
    const analysisButton = buttonContainer.createEl("button", {
      cls: "mod-cta",
      text: t("vaultAnalysis.generateAnalysis")
    });
    analysisButton.setAttribute("title", "Click to generate analysis for this tab");
    analysisButton.addEventListener("click", () => {
      if (tabName === "structure" || tabName === "evolution" || tabName === "actions") {
        const tabDisplayName = this.getTabDisplayName(tabName);
        new import_obsidian10.Notice(t("notices.generatingTabAnalysis", { tab: tabDisplayName }));
        this.vaultSemanticAnalysisManager.setAnalysisInProgress(tabName);
        this.close();
        void (async () => {
          try {
            if (tabName === "structure") {
              await this.masterAnalysisManager.generateKnowledgeStructureAnalysis();
            } else if (tabName === "evolution") {
              await this.masterAnalysisManager.generateKnowledgeEvolutionAnalysis();
            } else if (tabName === "actions") {
              await this.masterAnalysisManager.generateRecommendedActionsAnalysis();
            }
            await this.vaultSemanticAnalysisManager.reopenVaultAnalysisToTab(tabName);
          } catch (error) {
            new import_obsidian10.Notice(getUserFriendlyMessage(error instanceof Error ? error : new Error(String(error))));
          } finally {
            this.vaultSemanticAnalysisManager.clearAnalysisInProgress();
          }
        })();
      } else {
        void this.triggerAIAnalysis(container, false, tabName);
      }
    });
    return Promise.resolve();
  }
  async triggerAIAnalysis(buttonSection, isUpdate = false, tabName = "") {
    buttonSection.empty();
    const loadingContainer = buttonSection.createEl("div", {
      cls: "evolution-loading"
    });
    const tabDisplay = tabName ? this.getTabDisplayName(tabName) : "";
    const loadingTitle = tabName ? isUpdate ? t("vaultAnalysis.loadingUpdatingTab", { tab: tabDisplay }) : t("vaultAnalysis.loadingGeneratingTab", { tab: tabDisplay }) : t("vaultAnalysis.loadingTitle");
    loadingContainer.createEl("h3", { text: loadingTitle });
    const loadingText = loadingContainer.createEl("p");
    const estTime = tabName ? "1\u20132 minutes" : "3\u20136 minutes";
    const strongTitle = loadingText.createEl("strong", { cls: "ai-loading-title" });
    strongTitle.setText(tabName ? t("vaultAnalysis.loadingGeneratingTab", { tab: tabDisplay }) : t("vaultAnalysis.loadingGeneratingAll"));
    loadingText.createEl("br");
    loadingText.appendText(tabName ? t("vaultAnalysis.loadingIncludesTab", { description: this.getTabDescription(tabName) }) : t("vaultAnalysis.loadingIncludesAll"));
    loadingText.createEl("br");
    const timeStrong = loadingText.createEl("strong");
    timeStrong.setText(t("vaultAnalysis.estimatedTime"));
    loadingText.appendText(`${estTime}.`);
    loadingText.createEl("br");
    const smallNote = loadingText.createEl("small", { cls: "ai-loading-note" });
    smallNote.setText(t("vaultAnalysis.cachedNote"));
    try {
      if (tabName === "structure") {
        this.structureAnalysisData = await this.masterAnalysisManager.generateKnowledgeStructureAnalysis();
      } else if (tabName === "evolution") {
        this.evolutionAnalysisData = await this.masterAnalysisManager.generateKnowledgeEvolutionAnalysis();
        this.knowledgeEvolutionData = this.evolutionAnalysisData.knowledgeEvolution;
      } else if (tabName === "actions") {
        this.actionsAnalysisData = await this.masterAnalysisManager.generateRecommendedActionsAnalysis();
      } else {
        this.structureAnalysisData = await this.masterAnalysisManager.generateKnowledgeStructureAnalysis();
        this.evolutionAnalysisData = await this.masterAnalysisManager.generateKnowledgeEvolutionAnalysis();
        this.knowledgeEvolutionData = this.evolutionAnalysisData.knowledgeEvolution;
        this.actionsAnalysisData = await this.masterAnalysisManager.generateRecommendedActionsAnalysis();
      }
      loadingContainer.remove();
      const successMessage = tabName ? t("notices.tabAnalysisComplete", { tab: this.getTabDisplayName(tabName) }) : t("vaultAnalysis.allAnalysesSuccess");
      new import_obsidian10.Notice(successMessage);
      if (this.currentView === "structure") {
        this.contentContainer.empty();
        await this.loadKnowledgeStructureView();
      } else if (this.currentView === "evolution") {
        await this.displayCachedAnalysis(buttonSection);
        await this.createUpdateAnalysisButtonSection(
          buttonSection,
          "evolution",
          this.evolutionAnalysisData?.isOutdated ?? false
        );
      } else if (this.currentView === "actions") {
        const aiResultsContainer = this.contentContainer.querySelector(".actions-ai-results-container");
        if (aiResultsContainer) {
          aiResultsContainer.empty();
          this.displayRecommendedActionsResults(aiResultsContainer);
          await this.createUpdateAnalysisButtonSection(
            aiResultsContainer,
            "actions",
            this.actionsAnalysisData?.isOutdated ?? false
          );
        } else {
          this.contentContainer.empty();
          await this.loadRecommendedActionsView();
        }
      } else {
        await this.displayCachedAnalysis(buttonSection);
        let isOutdated = false;
        if (this.currentView === "structure") {
          isOutdated = this.structureAnalysisData?.isOutdated ?? false;
        } else if (this.currentView === "evolution") {
          isOutdated = this.evolutionAnalysisData?.isOutdated ?? false;
        } else if (this.currentView === "actions") {
          isOutdated = this.actionsAnalysisData?.isOutdated ?? false;
        }
        await this.createUpdateAnalysisButtonSection(buttonSection, "", isOutdated);
      }
    } catch (error) {
      loadingContainer.remove();
      const err = error instanceof Error ? error : new Error(String(error));
      const message = getUserFriendlyMessage(err);
      const errorContainer = buttonSection.createEl("div", {
        cls: "evolution-error"
      });
      errorContainer.createEl("h4", { text: t("vaultAnalysis.errorTitle") });
      errorContainer.createEl("p", {
        text: t("vaultAnalysis.errorFailed", { message })
      });
      new import_obsidian10.Notice(t("notices.tabAnalysisFailed", { message }));
    }
  }
  // Helper function to get display name for tab
  getTabDisplayName(tabName) {
    switch (tabName) {
      case "structure":
        return t("vaultAnalysis.tabDisplayStructure");
      case "evolution":
        return t("vaultAnalysis.tabDisplayEvolution");
      case "actions":
        return t("vaultAnalysis.tabDisplayActions");
      default:
        return t("vaultAnalysis.tabDisplayDefault");
    }
  }
  // Helper function to get tab description
  getTabDescription(tabName) {
    switch (tabName) {
      case "structure":
        return t("vaultAnalysis.tabDescStructure");
      case "evolution":
        return t("vaultAnalysis.tabDescEvolution");
      case "actions":
        return t("vaultAnalysis.tabDescActions");
      default:
        return t("vaultAnalysis.tabDescDefault");
    }
  }
  async displayCachedAnalysis(container) {
    if (!this.knowledgeEvolutionData) return;
    const data = this.knowledgeEvolutionData;
    await this.createStructuredAnalysisSection(container, "timeline", data.timeline, true);
    await Promise.all([
      this.createStructuredAnalysisSection(container, "topic", data.topicPatterns, false),
      this.createStructuredAnalysisSection(container, "focus", data.focusShift, false)
    ]);
  }
  evolutionSectionTitle(sectionKind) {
    switch (sectionKind) {
      case "timeline":
        return t("vaultAnalysis.developmentTimeline");
      case "topic":
        return t("vaultAnalysis.sectionTopicPatterns");
      case "focus":
        return t("vaultAnalysis.sectionFocusShifts");
    }
  }
  /** Evolution insight data: timeline phases, topic intro, or focus shifts */
  async createStructuredAnalysisSection(container, sectionKind, analysisData, includeCalendar = false) {
    const section = container.createEl("div", { cls: "vault-analysis-section" });
    section.createEl("h3", {
      text: this.evolutionSectionTitle(sectionKind),
      cls: "vault-analysis-section-title"
    });
    const insightsContainer = section.createEl("div", { cls: "ai-insights-container-rounded" });
    if (includeCalendar) {
      const chartContainer = insightsContainer.createEl("div", {
        cls: "knowledge-calendar-wrapper"
      });
      const derived = await this.ensureDerivedVisualizations();
      await this.renderCalendarChart(chartContainer, derived);
    }
    if (sectionKind === "timeline" && "phases" in analysisData && analysisData.phases) {
      this.addTimelineVisualization(insightsContainer, analysisData.phases);
    } else if (sectionKind === "topic" && "introductionTimeline" in analysisData && analysisData.introductionTimeline) {
      this.addTopicVisualization(insightsContainer, analysisData.introductionTimeline);
    } else if (sectionKind === "focus" && "shifts" in analysisData && analysisData.shifts) {
      this.addFocusShiftVisualization(insightsContainer, analysisData.shifts);
    }
    const narrative = ("narrative" in analysisData ? analysisData.narrative : null) || ("exploration" in analysisData ? analysisData.exploration : null);
    if (narrative && narrative.content) {
      const conclusionSection = insightsContainer.createEl("div", { cls: "ai-conclusion-section" });
      const conclusionTitle = conclusionSection.createEl("div", { cls: "ai-conclusion-title" });
      const iconContainer = conclusionTitle.createEl("span", { cls: "ai-conclusion-icon" });
      (0, import_obsidian10.setIcon)(iconContainer, "sparkle");
      conclusionTitle.createEl("span", {
        text: t("vaultAnalysis.conclusion"),
        cls: "ai-conclusion-text"
      });
      const conclusionText = conclusionSection.createEl("div", {
        cls: "ai-conclusion-content"
      });
      void import_obsidian10.MarkdownRenderer.render(this.app, narrative.content, conclusionText, "", this.markdownComponent);
    }
  }
  // Visualization helper methods - each item in its own rounded container
  addTimelineVisualization(section, phases) {
    phases.forEach((phase) => {
      const phaseEl = section.createEl("div", { cls: "ai-bullet-item-container" });
      void import_obsidian10.MarkdownRenderer.render(this.app, `- **${phase.period}**: ${phase.description}`, phaseEl, "", this.markdownComponent);
    });
  }
  addTopicVisualization(section, timeline) {
    timeline.forEach((item) => {
      if (item.newDomains.length > 0) {
        const itemEl = section.createEl("div", { cls: "ai-bullet-item-container" });
        const cleanDomains = item.newDomains.map((domain) => {
          const domainParts = domain.match(/^(.+?)\s*\((.+)\)$/) || [null, domain, ""];
          return domainParts[1] || domain;
        });
        void import_obsidian10.MarkdownRenderer.render(this.app, `- **${item.period}**: ${cleanDomains.join(", ")}`, itemEl, "", this.markdownComponent);
      }
    });
  }
  addFocusShiftVisualization(section, shifts) {
    shifts.forEach((shift) => {
      const shiftEl = section.createEl("div", { cls: "ai-bullet-item-container" });
      const stats = t("vaultAnalysis.focusShiftStats", {
        newCount: String(shift.newAreas.length),
        reducedCount: String(shift.decreasedFocus.length)
      });
      void import_obsidian10.MarkdownRenderer.render(this.app, `- **${shift.period}**: ${stats}`, shiftEl, "", this.markdownComponent);
    });
  }
  async loadRecommendedActionsView() {
    const recommendationsSection = this.contentContainer.createEl("div", {
      cls: "recommended-actions-container"
    });
    recommendationsSection.addClass("vault-analysis-scroll-container");
    if (!this.hasExistingData || !this.analysisData) {
      const placeholderContainer = recommendationsSection.createEl("div", {
        cls: "vault-analysis-placeholder"
      });
      placeholderContainer.createEl("p", {
        text: t("vaultAnalysis.generateVaultFirst"),
        cls: "analysis-required"
      });
      const actionsSection = this.contentContainer.createEl("div", {
        cls: "vault-analysis-section"
      });
      actionsSection.createEl("h3", {
        text: t("vaultAnalysis.actions"),
        cls: "vault-analysis-section-title"
      });
      const originalContentContainer = this.contentContainer;
      this.contentContainer = actionsSection;
      this.createActionButtons();
      this.contentContainer = originalContentContainer;
      return;
    }
    const chartSection = recommendationsSection.createEl("div", {
      cls: "vault-analysis-section"
    });
    chartSection.createEl("h3", {
      text: t("vaultAnalysis.networkMetrics"),
      cls: "vault-analysis-section-title"
    });
    const chartWrapper = chartSection.createEl("div", {
      cls: "scatter-chart-wrapper"
    });
    const tabsContainer = chartWrapper.createEl("div", { cls: "knowledge-network-tab-bar" });
    const linksTab = tabsContainer.createEl("button", {
      cls: "knowledge-network-tab active",
      attr: { type: "button" }
    });
    (0, import_obsidian10.setIcon)(linksTab.createEl("span", { cls: "knowledge-network-tab-icon" }), "link");
    linksTab.createEl("span", { cls: "knowledge-network-tab-label", text: t("vaultAnalysis.inboundOutbound") });
    const centralityTab = tabsContainer.createEl("button", {
      cls: "knowledge-network-tab",
      attr: { type: "button" }
    });
    (0, import_obsidian10.setIcon)(centralityTab.createEl("span", { cls: "knowledge-network-tab-icon" }), "activity");
    centralityTab.createEl("span", { cls: "knowledge-network-tab-label", text: t("vaultAnalysis.betweennessEigenvector") });
    const chartContainer = chartWrapper.createEl("div", {
      cls: "connectivity-chart-section"
    });
    const scatterChart = new ConnectivityScatterChart(
      this.app,
      chartContainer,
      {
        width: 700,
        height: 500,
        mode: "links",
        analysisData: this.analysisData,
        // For centrality mode
        modal: this
        // Pass modal reference to close on note click
      }
    );
    await scatterChart.render();
    const updateTabStyles = (activeTab, inactiveTab) => {
      activeTab.classList.add("active");
      inactiveTab.classList.remove("active");
    };
    linksTab.addEventListener("click", () => {
      updateTabStyles(linksTab, centralityTab);
      void scatterChart.setMode("links");
    });
    centralityTab.addEventListener("click", () => {
      updateTabStyles(centralityTab, linksTab);
      void scatterChart.setMode("centrality");
    });
    const aiResultsContainer = recommendationsSection.createEl("div", {
      cls: "actions-ai-results-container"
    });
    void this.loadActionsAnalysisData().then((hasData) => {
      if (hasData) {
        this.displayRecommendedActionsResults(aiResultsContainer);
        void this.createUpdateAnalysisButtonSection(
          aiResultsContainer,
          "actions",
          this.actionsAnalysisData?.isOutdated ?? false
        );
      } else {
        this.showActionsEmptyState(aiResultsContainer);
      }
    });
  }
  // Helper method to load actions analysis data
  async loadActionsAnalysisData() {
    try {
      this.actionsAnalysisData = await this.masterAnalysisManager.loadCachedTabAnalysis("actions", this.analysisData);
      if (this.actionsAnalysisData) {
        return true;
      }
      return false;
    } catch {
      return false;
    }
  }
  displayRecommendedActionsResults(container) {
    const actionsData = this.actionsAnalysisData?.recommendedActions;
    if (!actionsData) return;
    if (actionsData.maintenance && actionsData.maintenance.length > 0) {
      const maintenanceSection = container.createEl("div", { cls: "vault-analysis-section" });
      maintenanceSection.createEl("h3", {
        text: t("vaultAnalysis.notesNeedingReview"),
        cls: "vault-analysis-section-title"
      });
      const analysisResults = this.analysisData?.results || [];
      const candidates = KnowledgeActionsManager.computeReviewCandidates(
        actionsData.maintenance,
        analysisResults,
        9
        // 3 rows x 3 columns
      );
      this.renderReviewCardsGrid(maintenanceSection, candidates);
    }
    if (actionsData.connections && actionsData.connections.length > 0) {
      const connectionsSection = container.createEl("div", { cls: "vault-analysis-section" });
      connectionsSection.createEl("h3", {
        text: t("vaultAnalysis.suggestedConnections"),
        cls: "vault-analysis-section-title"
      });
      const subgraphContainer = connectionsSection.createEl("div", {
        cls: "connection-subgraph-container"
      });
      const subGraph = new ConnectionSubGraph(
        this.app,
        subgraphContainer,
        actionsData.connections,
        {
          modal: this,
          connectionsAddedAt: this.actionsAnalysisData?.connectionsAddedAt,
          actionsAnalysisData: this.actionsAnalysisData ?? void 0,
          saveCacheFn: async (data) => {
            await this.masterAnalysisManager.cacheTabAnalysis("actions", data);
          }
        }
      );
      subGraph.render();
    }
  }
  /**
   * Render the 3-column review cards grid for maintenance candidates.
   * Each card is clickable and opens the note in a new Obsidian tab.
   */
  renderReviewCardsGrid(container, candidates) {
    const grid = container.createEl("div", { cls: "review-cards-grid" });
    for (const candidate of candidates) {
      const card = grid.createEl("div", { cls: `review-card priority-${candidate.priority}` });
      card.setAttribute("data-path", candidate.path);
      const tooltipText = candidate.reason ? `${candidate.reason}

Click to open "${candidate.title}" in a new tab` : `Click to open "${candidate.title}" in a new tab`;
      card.setAttribute("title", tooltipText);
      const header = card.createEl("div", { cls: "review-card-header" });
      header.createEl("span", {
        text: candidate.title,
        cls: "review-card-title"
      });
      header.createEl("span", {
        text: candidate.priority.toUpperCase(),
        cls: `review-card-badge badge-${candidate.priority}`
      });
      card.createEl("div", {
        text: candidate.reason,
        cls: "review-card-reason"
      });
      const footer = card.createEl("div", { cls: "review-card-footer" });
      if (candidate.lastModified) {
        const modifiedEl = footer.createEl("span", { cls: "review-card-modified" });
        const iconSpan = modifiedEl.createEl("span", { cls: "review-card-icon" });
        (0, import_obsidian10.setIcon)(iconSpan, "clock");
        modifiedEl.createEl("span", {
          text: this.getRelativeTime(candidate.lastModified)
        });
      }
      if (candidate.centralityRole !== "normal") {
        const roleEl = footer.createEl("span", { cls: `review-card-role role-${candidate.centralityRole}` });
        const roleIcon = candidate.centralityRole === "bridge" ? "git-branch" : candidate.centralityRole === "authority" ? "star" : "share-2";
        const roleIconSpan = roleEl.createEl("span", { cls: "review-card-icon" });
        (0, import_obsidian10.setIcon)(roleIconSpan, roleIcon);
        roleEl.createEl("span", {
          text: candidate.centralityRole.charAt(0).toUpperCase() + candidate.centralityRole.slice(1)
        });
      }
      card.addEventListener("click", () => {
        this.close();
        void this.app.workspace.openLinkText(candidate.path, "", "tab");
      });
    }
  }
  /**
   * Convert an ISO date string to a human-readable relative time (e.g., "3 months ago")
   */
  getRelativeTime(isoDate) {
    const date = new Date(isoDate);
    const now2 = /* @__PURE__ */ new Date();
    const diffMs = now2.getTime() - date.getTime();
    const diffDays = Math.floor(diffMs / (1e3 * 60 * 60 * 24));
    if (diffDays < 1) return "Today";
    if (diffDays === 1) return "Yesterday";
    if (diffDays < 7) return `${diffDays} days ago`;
    if (diffDays < 30) return `${Math.floor(diffDays / 7)} weeks ago`;
    if (diffDays < 365) return `${Math.floor(diffDays / 30)} months ago`;
    return `${Math.floor(diffDays / 365)} years ago`;
  }
  showActionsEmptyState(container) {
    const categories = [
      {
        title: "Notes Needing Review",
        message: "Generate analysis to identify important notes (hubs, bridges, authorities) that need review. Results are shown as interactive cards you can click to open."
      },
      {
        title: "Suggested Connections",
        message: "Generate analysis to discover missing links between related notes. Results are shown as an interactive graph you can edit before adding connections to your vault."
      }
    ];
    categories.forEach(({ title, message }) => {
      const section = container.createEl("div", { cls: "vault-analysis-section" });
      section.createEl("h3", {
        text: title,
        cls: "vault-analysis-section-title"
      });
      this.createEmptyState(section, message);
    });
    const infoSection = container.createEl("div", {
      cls: "vault-analysis-section"
    });
    const infoContainer = infoSection.createEl("div", {
      cls: "vault-analysis-summary"
    });
    infoContainer.createEl("p", {
      text: t("vaultAnalysis.privacyNote1"),
      cls: "analysis-info-text"
    });
    infoContainer.createEl("p", {
      text: t("vaultAnalysis.privacyNote2"),
      cls: "analysis-info-text"
    });
    const buttonSection = container.createEl("div", {
      cls: "vault-analysis-section"
    });
    const buttonContainer = buttonSection.createEl("div", {
      cls: "modal-button-container"
    });
    const statusIndicator = buttonContainer.createEl("div", {
      cls: "analysis-status-indicator"
    });
    if (this.vaultSemanticAnalysisManager.isAnalysisInProgress()) {
      statusIndicator.addClass("status-outdated");
      statusIndicator.createSpan({ cls: "status-dot" });
      statusIndicator.appendText(" Analysis in progress");
      const disabledButton = buttonContainer.createEl("button", {
        cls: "mod-cta is-disabled",
        text: t("vaultAnalysis.processing")
      });
      disabledButton.disabled = true;
      return;
    }
    statusIndicator.addClass("status-empty");
    statusIndicator.createSpan({ cls: "status-dot" });
    statusIndicator.appendText(" Analysis not generated yet");
    const generateButton = buttonContainer.createEl("button", {
      cls: "mod-cta",
      text: t("vaultAnalysis.generateAnalysis")
    });
    generateButton.setAttribute("title", "Click to generate analysis for this tab");
    generateButton.addEventListener("click", () => {
      const tabDisplayName = this.getTabDisplayName("actions");
      new import_obsidian10.Notice(t("notices.generatingTabAnalysis", { tab: tabDisplayName }));
      this.vaultSemanticAnalysisManager.setAnalysisInProgress("actions");
      this.close();
      void (async () => {
        try {
          await this.masterAnalysisManager.generateRecommendedActionsAnalysis();
          await this.vaultSemanticAnalysisManager.reopenVaultAnalysisToTab("actions");
        } catch (error) {
          new import_obsidian10.Notice(getUserFriendlyMessage(error instanceof Error ? error : new Error(String(error))));
        } finally {
          this.vaultSemanticAnalysisManager.clearAnalysisInProgress();
        }
      })();
    });
  }
  async loadKnowledgeEvolutionView() {
    const evolutionContainer = this.contentContainer.createEl("div", {
      cls: "knowledge-evolution-container"
    });
    evolutionContainer.addClass("vault-analysis-scroll-container");
    if (!this.hasExistingData || !this.analysisData) {
      this.showEvolutionEmptyState(evolutionContainer);
      return;
    }
    try {
      this.evolutionAnalysisData = await this.masterAnalysisManager.loadCachedTabAnalysis("evolution", this.analysisData);
      if (this.evolutionAnalysisData) {
        this.knowledgeEvolutionData = this.evolutionAnalysisData.knowledgeEvolution;
      } else {
        this.knowledgeEvolutionData = null;
      }
    } catch {
      this.evolutionAnalysisData = null;
      this.knowledgeEvolutionData = null;
    }
    if (this.knowledgeEvolutionData) {
      await this.displayCachedAnalysis(evolutionContainer);
      await this.createUpdateAnalysisButtonSection(
        evolutionContainer,
        "evolution",
        this.evolutionAnalysisData?.isOutdated ?? false
      );
    } else {
      await this.createCalendarSection(evolutionContainer);
      this.showEvolutionAnalysisPlaceholders(evolutionContainer);
      await this.createAnalysisButtonSection(evolutionContainer, "evolution");
    }
  }
  showEvolutionAnalysisPlaceholders(container) {
    const sections = [
      {
        title: t("vaultAnalysis.sectionTopicPatterns"),
        message: t("vaultAnalysis.placeholderTopic")
      },
      {
        title: t("vaultAnalysis.sectionFocusShifts"),
        message: t("vaultAnalysis.placeholderFocus")
      }
    ];
    sections.forEach(({ title, message }) => {
      const section = container.createEl("div", { cls: "vault-analysis-section" });
      section.createEl("h3", {
        text: title,
        cls: "vault-analysis-section-title"
      });
      this.createEmptyState(section, message);
    });
  }
  showEvolutionEmptyState(container) {
    const emptyState = container.createEl("div", {
      cls: "vault-analysis-placeholder"
    });
    emptyState.createEl("h3", {
      text: t("vaultAnalysis.evolutionEmptyTitle"),
      cls: "vault-analysis-section-title"
    });
    emptyState.createEl("p", {
      text: t("vaultAnalysis.evolutionEmptyDesc"),
      cls: "analysis-required"
    });
    const featureList = emptyState.createEl("ul");
    const features = [
      t("vaultAnalysis.evolutionFeatureTimeline"),
      t("vaultAnalysis.evolutionFeatureTopic"),
      t("vaultAnalysis.evolutionFeatureFocus")
    ];
    features.forEach((feature) => {
      featureList.createEl("li", { text: feature });
    });
    const actionsSection = container.createEl("div", {
      cls: "vault-analysis-section"
    });
    actionsSection.createEl("h3", {
      text: t("vaultAnalysis.actions"),
      cls: "vault-analysis-section-title"
    });
    const originalContentContainer = this.contentContainer;
    this.contentContainer = actionsSection;
    this.createActionButtons();
    this.contentContainer = originalContentContainer;
  }
  async createCalendarSection(container) {
    const calendarSection = container.createEl("div", {
      cls: "vault-analysis-section"
    });
    calendarSection.createEl("h3", {
      text: t("vaultAnalysis.developmentTimeline"),
      cls: "vault-analysis-section-title"
    });
    const chartContainer = calendarSection.createEl("div", {
      cls: "knowledge-calendar-wrapper"
    });
    const derived = await this.ensureDerivedVisualizations();
    await this.renderCalendarChart(chartContainer, derived);
    this.createEmptyState(calendarSection, t("vaultAnalysis.placeholderTimeline"));
  }
  onClose() {
    this.vaultSemanticAnalysisManager.clearActiveVaultAnalysisModal(this);
    const { contentEl, modalEl } = this;
    modalEl.removeClass("vault-analysis-modal");
    contentEl.removeClass("vault-analysis-modal-content");
    contentEl.empty();
  }
};

// src/utils/NoteContentUtils.ts
function cleanupNoteContent(content) {
  let cleaned = content.replace(/^---[\s\S]*?---\n?/m, "").replace(/\0/g, "");
  cleaned = cleaned.split("").filter((c4) => {
    const code = c4.charCodeAt(0);
    return code > 31 && code !== 127 || code === 9 || code === 10 || code === 13;
  }).join("");
  return cleaned.replace(/^\s*$/gm, "").replace(/\n{3,}/g, "\n\n").trim();
}

// src/ai/VaultSemanticAnalysisManager.ts
var VaultSemanticAnalysisManager = class {
  constructor(app, settings, dataStore) {
    this.subdivisionsList = [];
    this.domainTemplateLoaded = false;
    this.MAX_CHARS_PER_NOTE = 8e3;
    this.MAX_NOTES_PER_BATCH = 30;
    this.DELAY_BETWEEN_BATCHES = 6e3;
    // 6s between batches (Gemini 2.5 Flash Lite RPM 10)
    this._analysisInProgress = null;
    this.activeVaultAnalysisModal = null;
    this.FAILED_BATCHES_EMPTY = { remaining: null, failed: [] };
    // Core analysis function.
    // Core analysis function using structured output API
    this.ZERO_TOKEN_USAGE = { promptTokens: 0, candidatesTokens: 0, totalTokens: 0 };
    this.app = app;
    this.settings = settings;
    this.dataStore = dataStore;
    this.aiService = new AIModelService(app, settings);
    this.graphDataBuilder = new GraphDataBuilder(app);
    this.pluginService = new PluginService(app);
    this.masterAnalysisManager = new MasterAnalysisManager(app, settings, dataStore);
    this.visualizationDerivation = new VisualizationDerivationService(app, dataStore);
  }
  /** Window from app workspace (avoids global for pop-out compatibility) */
  get win() {
    return this.app.workspace.containerEl.ownerDocument.defaultView;
  }
  isAnalysisInProgress() {
    return this._analysisInProgress !== null;
  }
  setAnalysisInProgress(type2) {
    this._analysisInProgress = type2;
  }
  clearAnalysisInProgress() {
    this._analysisInProgress = null;
  }
  clearActiveVaultAnalysisModal(modal) {
    if (this.activeVaultAnalysisModal === modal) {
      this.activeVaultAnalysisModal = null;
    }
  }
  openVaultAnalysisModal(analysisData, hasExistingData, initialView = "semantic") {
    if (this.activeVaultAnalysisModal) {
      this.activeVaultAnalysisModal.close();
    }
    const modal = new VaultAnalysisModal(
      this.app,
      analysisData,
      hasExistingData,
      this,
      this.settings,
      this.dataStore,
      initialView
    );
    this.activeVaultAnalysisModal = modal;
    modal.open();
    return modal;
  }
  getTabDisplayNameForReopen(tabName) {
    switch (tabName) {
      case "structure":
        return t("vaultAnalysis.tabDisplayStructure");
      case "evolution":
        return t("vaultAnalysis.tabDisplayEvolution");
      case "actions":
        return t("vaultAnalysis.tabDisplayActions");
      default:
        return t("vaultAnalysis.tabDisplayDefault");
    }
  }
  async reopenVaultAnalysisToTab(tabName) {
    try {
      const analysisData = await this.dataStore.getVaultAnalysis();
      const hasExistingData = analysisData !== null && analysisData.results && analysisData.results.length > 0;
      new import_obsidian11.Notice(
        t("notices.tabAnalysisComplete", { tab: this.getTabDisplayNameForReopen(tabName) })
      );
      this.openVaultAnalysisModal(analysisData, hasExistingData, tabName);
    } catch (error) {
      new import_obsidian11.Notice(error instanceof Error ? error.message : t("notices.reopenModalFailed"));
    }
  }
  scheduleDerivedVisualizations(analysisData) {
    void this.visualizationDerivation.computeAndPersist(analysisData).catch(() => {
    });
  }
  /**
   * Load knowledge domain template
   */
  async loadDomainTemplate() {
    if (this.domainTemplateLoaded && this.subdivisionsList.length > 0) {
      return true;
    }
    try {
      const domainHelper = KnowledgeDomainHelper.getInstance(this.app);
      const loaded = await domainHelper.ensureDomainTemplateLoaded();
      if (!loaded) {
        return false;
      }
      this.subdivisionsList = domainHelper.getAllSubdivisions();
      this.domainTemplateLoaded = this.subdivisionsList.length > 0;
      return this.domainTemplateLoaded;
    } catch {
      return false;
    }
  }
  createGraphViewButton(container) {
    const button = container.createDiv({ cls: "vault-analysis-icon" });
    (0, import_obsidian11.setIcon)(button, "sun");
    const tooltipEl = button.createDiv({ cls: "vault-analysis-icon-tooltip" });
    tooltipEl.createDiv({
      cls: "tooltip-title",
      text: t("vaultAnalysis.buttonTitle")
    });
    const description = tooltipEl.createDiv({ cls: "tooltip-description" });
    description.setText(t("vaultAnalysis.buttonDesc"));
    button.addEventListener("click", (event) => {
      if (event.shiftKey) {
        void (async () => {
          try {
            const enhanceNotice = new import_obsidian11.Notice(t("notices.enhancingWithMetrics"), 0);
            const enhanced = await this.enhanceWithGraphMetrics();
            enhanceNotice.hide();
            if (enhanced) {
              new import_obsidian11.Notice(t("notices.enhancedWithMetrics"));
            } else {
              new import_obsidian11.Notice(t("notices.noAnalysisForEnhance"));
            }
          } catch (err) {
            new import_obsidian11.Notice(t("notices.enhanceFailed", {
              message: err instanceof Error ? err.message : String(err)
            }));
          }
        })();
      } else {
        void this.viewVaultAnalysisResults();
      }
    });
    return button;
  }
  /**
   * Calculate graph metrics for all nodes in the vault
   * Returns a map from file path to graph metrics
   */
  async calculateGraphMetrics() {
    const metricsMap = /* @__PURE__ */ new Map();
    try {
      const { graphData } = await this.graphDataBuilder.buildGraphData();
      const degreeCentrality = this.pluginService.calculateDegreeCentrality();
      const betweennessCentrality = this.pluginService.calculateBetweennessCentrality();
      const closenessCentrality = this.pluginService.calculateClosenessCentrality();
      const eigenvectorCentrality = this.pluginService.calculateEigenvectorCentrality();
      const degreeMap = /* @__PURE__ */ new Map();
      const betweennessMap = /* @__PURE__ */ new Map();
      const closenessMap = /* @__PURE__ */ new Map();
      const eigenvectorMap = /* @__PURE__ */ new Map();
      degreeCentrality.forEach((node) => {
        if (node.centrality.degree !== void 0) {
          degreeMap.set(node.node_id, node.centrality.degree);
        }
      });
      betweennessCentrality.forEach((node) => {
        if (node.centrality.betweenness !== void 0) {
          betweennessMap.set(node.node_id, node.centrality.betweenness);
        }
      });
      closenessCentrality.forEach((node) => {
        if (node.centrality.closeness !== void 0) {
          closenessMap.set(node.node_id, node.centrality.closeness);
        }
      });
      eigenvectorCentrality.forEach((node) => {
        if (node.centrality.eigenvector !== void 0) {
          eigenvectorMap.set(node.node_id, node.centrality.eigenvector);
        }
      });
      graphData.nodes.forEach((filePath, nodeIndex) => {
        const metrics = {
          degreeCentrality: degreeMap.get(nodeIndex),
          betweennessCentrality: betweennessMap.get(nodeIndex),
          closenessCentrality: closenessMap.get(nodeIndex),
          eigenvectorCentrality: eigenvectorMap.get(nodeIndex)
        };
        metricsMap.set(filePath, metrics);
      });
    } catch {
    }
    return metricsMap;
  }
  /**
   * Calculate centrality rankings for all notes with graph metrics
   */
  calculateCentralityRankings(results) {
    const notesWithMetrics = results.filter((note) => note.graphMetrics);
    if (notesWithMetrics.length === 0) {
      return results;
    }
    const betweennessSorted = [...notesWithMetrics].sort((a2, b) => (b.graphMetrics?.betweennessCentrality || 0) - (a2.graphMetrics?.betweennessCentrality || 0));
    const closenessSorted = [...notesWithMetrics].sort((a2, b) => (b.graphMetrics?.closenessCentrality || 0) - (a2.graphMetrics?.closenessCentrality || 0));
    const eigenvectorSorted = [...notesWithMetrics].sort((a2, b) => (b.graphMetrics?.eigenvectorCentrality || 0) - (a2.graphMetrics?.eigenvectorCentrality || 0));
    const degreeSorted = [...notesWithMetrics].sort((a2, b) => (b.graphMetrics?.degreeCentrality || 0) - (a2.graphMetrics?.degreeCentrality || 0));
    const betweennessRankMap = /* @__PURE__ */ new Map();
    const closenessRankMap = /* @__PURE__ */ new Map();
    const eigenvectorRankMap = /* @__PURE__ */ new Map();
    const degreeRankMap = /* @__PURE__ */ new Map();
    betweennessSorted.forEach((note, index2) => {
      betweennessRankMap.set(note.id, index2 + 1);
    });
    closenessSorted.forEach((note, index2) => {
      closenessRankMap.set(note.id, index2 + 1);
    });
    eigenvectorSorted.forEach((note, index2) => {
      eigenvectorRankMap.set(note.id, index2 + 1);
    });
    degreeSorted.forEach((note, index2) => {
      degreeRankMap.set(note.id, index2 + 1);
    });
    return results.map((result) => {
      if (!result.graphMetrics) {
        return result;
      }
      return {
        ...result,
        centralityRankings: {
          betweennessRank: betweennessRankMap.get(result.id),
          closenessRank: closenessRankMap.get(result.id),
          eigenvectorRank: eigenvectorRankMap.get(result.id),
          degreeRank: degreeRankMap.get(result.id)
        }
      };
    });
  }
  /**
   * Load existing vault analysis data if it exists
   */
  async loadExistingAnalysisData() {
    return this.dataStore.getVaultAnalysis();
  }
  /**
   * Identify which files need to be re-analyzed
   * Compares file modification times with existing analysis results
   * Uses TFile.stat.mtime (synchronous) instead of adapter.stat for performance
   * Returns: { changedFiles, newFiles, deletedFilePaths, unchangedResults }
   */
  identifyChangedFiles(currentFiles, existingAnalysis) {
    const changedFiles = [];
    const newFiles = [];
    const unchangedResults = [];
    const deletedFilePaths = [];
    if (!existingAnalysis || !existingAnalysis.results || existingAnalysis.results.length === 0) {
      return {
        changedFiles: [],
        newFiles: currentFiles,
        deletedFilePaths: [],
        unchangedResults: []
      };
    }
    const existingResultsMap = /* @__PURE__ */ new Map();
    existingAnalysis.results.forEach((result) => {
      existingResultsMap.set(result.path, result);
    });
    for (const file of currentFiles) {
      const existingResult = existingResultsMap.get(file.path);
      if (!existingResult) {
        newFiles.push(file);
      } else {
        const currentMtime = file.stat.mtime;
        const existingMtime = existingResult.modified ? new Date(existingResult.modified).getTime() : 0;
        if (currentMtime > existingMtime) {
          changedFiles.push(file);
        } else {
          unchangedResults.push(existingResult);
        }
      }
    }
    const currentFilePaths = new Set(currentFiles.map((f) => f.path));
    existingAnalysis.results.forEach((result) => {
      if (!currentFilePaths.has(result.path)) {
        deletedFilePaths.push(result.path);
      }
    });
    return {
      changedFiles,
      newFiles,
      deletedFilePaths,
      unchangedResults
    };
  }
  /**
   * Check if there are pending changes (modified or new files) that would require
   * re-running semantic analysis. Used to enable/disable the Update Analysis button.
   * @param preloadedData - Optional vault analysis data to avoid re-reading from disk
   */
  async hasPendingSemanticChanges(preloadedData) {
    const existingAnalysis = preloadedData !== void 0 ? preloadedData : await this.loadExistingAnalysisData();
    const isIncrementalUpdate = existingAnalysis !== null && existingAnalysis.results && existingAnalysis.results.length > 0;
    if (!isIncrementalUpdate) {
      const includedFiles2 = this.getIncludedMarkdownFiles();
      return includedFiles2.length > 0;
    }
    const includedFiles = this.getIncludedMarkdownFiles();
    const changeInfo = this.identifyChangedFiles(includedFiles, existingAnalysis);
    const pendingCount = changeInfo.changedFiles.length + changeInfo.newFiles.length;
    return pendingCount > 0;
  }
  /**
   * Merge new analysis results with existing unchanged results
   * Removes deleted files and sorts by title
   */
  mergeAnalysisResults(unchangedResults, newResults, deletedFilePaths) {
    const mergedResults = [...unchangedResults];
    mergedResults.push(...newResults);
    const deletedPathsSet = new Set(deletedFilePaths);
    const beforeFilterCount = mergedResults.length;
    const filteredResults = mergedResults.filter((result) => {
      const isDeleted = deletedPathsSet.has(result.path);
      if (isDeleted) {
      }
      return !isDeleted;
    });
    const removedCount = beforeFilterCount - filteredResults.length;
    if (removedCount > 0) {
    }
    return filteredResults.sort((a2, b) => a2.title.localeCompare(b.title));
  }
  /**
   * Enhance existing vault analysis results with graph metrics
   * This handles scenario 2: cached vault-analysis.json exists
   */
  async enhanceWithGraphMetrics() {
    try {
      const existingData = await this.dataStore.getVaultAnalysis();
      if (!existingData) {
        return false;
      }
      const graphMetrics = await this.calculateGraphMetrics();
      const enhancedResults = existingData.results.map((result) => {
        const metrics = graphMetrics.get(result.path);
        return {
          ...result,
          graphMetrics: metrics
        };
      });
      const resultsWithRankings = this.calculateCentralityRankings(enhancedResults);
      const existingGeneratedFiles = existingData.generatedFiles ?? existingData.totalFiles;
      const existingUpdatedFiles = existingData.updatedFiles ?? 0;
      const updatedData = {
        ...existingData,
        results: resultsWithRankings,
        // Preserve generation metadata, don't overwrite generatedAt
        generatedFiles: existingGeneratedFiles,
        updatedFiles: existingUpdatedFiles
      };
      await this.dataStore.setVaultAnalysis(updatedData);
      this.scheduleDerivedVisualizations(updatedData);
      return true;
    } catch (error) {
      throw new Error(`Failed to enhance with graph metrics: ${error.message}`);
    }
  }
  async generateVaultAnalysis() {
    this.setAnalysisInProgress("semantic");
    try {
      if (!this.settings.geminiApiKey || this.settings.geminiApiKey.trim() === "") {
        new import_obsidian11.Notice(t("notices.configureApiKey"));
        return false;
      }
      const existingAnalysis = await this.loadExistingAnalysisData();
      const isIncrementalUpdate = existingAnalysis !== null && existingAnalysis.results && existingAnalysis.results.length > 0;
      const includedFiles = this.getIncludedMarkdownFiles();
      if (includedFiles.length === 0) {
        new import_obsidian11.Notice(t("notices.noFilesAfterExclusion"));
        return false;
      }
      const newFilePaths = /* @__PURE__ */ new Set();
      let filesToProcess;
      let unchangedResults = [];
      let deletedFilePaths = [];
      let changedCount = 0;
      let newCount = 0;
      let unchangedCount = 0;
      if (isIncrementalUpdate) {
        const changeInfo = this.identifyChangedFiles(includedFiles, existingAnalysis);
        filesToProcess = [...changeInfo.changedFiles, ...changeInfo.newFiles];
        unchangedResults = changeInfo.unchangedResults;
        deletedFilePaths = changeInfo.deletedFilePaths;
        changedCount = changeInfo.changedFiles.length;
        newCount = changeInfo.newFiles.length;
        unchangedCount = changeInfo.unchangedResults.length;
        changeInfo.newFiles.forEach((file) => newFilePaths.add(file.path));
      } else {
        filesToProcess = [...includedFiles];
        unchangedCount = 0;
        filesToProcess.forEach((file) => newFilePaths.add(file.path));
      }
      const failedPaths = await this.getFailedBatchFilePaths();
      const inFilesToProcess = new Set(filesToProcess.map((f) => f.path));
      for (const path2 of failedPaths) {
        if (inFilesToProcess.has(path2)) continue;
        const file = this.app.vault.getAbstractFileByPath(path2);
        const includedPaths = new Set(this.getIncludedMarkdownFiles().map((f) => f.path));
        if (file instanceof import_obsidian11.TFile && includedPaths.has(path2)) {
          filesToProcess.push(file);
          inFilesToProcess.add(path2);
        }
      }
      if (filesToProcess.length === 0) {
        new import_obsidian11.Notice(t("notices.allFilesUpToDate", { count: unchangedCount }));
        return false;
      }
      const batchCount = Math.ceil(filesToProcess.length / this.MAX_NOTES_PER_BATCH);
      const estimatedMins = Math.max(1, Math.ceil(batchCount / 4));
      const initialMessage = isIncrementalUpdate ? t("notices.vaultAnalysisUpdating", {
        changed: changedCount,
        new: newCount,
        unchanged: unchangedCount,
        processing: filesToProcess.length,
        minutes: estimatedMins
      }) : t("notices.vaultAnalysisStarting", {
        count: filesToProcess.length,
        minutes: estimatedMins
      });
      const progressNotice = new import_obsidian11.Notice(initialMessage, 0);
      const results = [];
      let processed = 0;
      let failed = 0;
      progressNotice.setMessage(t("notices.preparingFiles"));
      const fileDataList = [];
      for (const file of filesToProcess) {
        try {
          const content = await this.app.vault.read(file);
          const rawCharCount = content.trim().length;
          let cleanedContent = cleanupNoteContent(content);
          if (cleanedContent.length > this.MAX_CHARS_PER_NOTE) {
            cleanedContent = cleanedContent.slice(0, this.MAX_CHARS_PER_NOTE) + "...";
          }
          const charCount = cleanedContent.length;
          const isShort = rawCharCount < 50;
          if (isShort) {
          }
          const created = file.stat.ctime ? new Date(file.stat.ctime).toISOString() : "";
          const modified = file.stat.mtime ? new Date(file.stat.mtime).toISOString() : "";
          fileDataList.push({
            file,
            content: cleanedContent,
            charCount,
            created,
            modified,
            isShort
          });
        } catch {
          fileDataList.push({
            file,
            content: "",
            charCount: 0,
            created: "",
            modified: "",
            isShort: true
          });
        }
      }
      const delayBetweenBatches = this.DELAY_BETWEEN_BATCHES;
      const batches = [];
      let currentBatch = [];
      for (const fileData of fileDataList) {
        if (currentBatch.length >= this.MAX_NOTES_PER_BATCH) {
          batches.push(currentBatch);
          currentBatch = [fileData];
        } else {
          currentBatch.push(fileData);
        }
      }
      if (currentBatch.length > 0) {
        batches.push(currentBatch);
      }
      const totalBatches = batches.length;
      let totalTokenUsage = { promptTokens: 0, candidatesTokens: 0, totalTokens: 0 };
      let stoppedDueToQuota = false;
      let firstBatchTimestamp = null;
      let lastBatchIndex = -1;
      for (let batchIndex = 0; batchIndex < totalBatches && !stoppedDueToQuota; batchIndex++) {
        lastBatchIndex = batchIndex;
        const batch = batches[batchIndex];
        const batchFileCount = batch.length;
        const batchCharCount = batch.reduce((sum2, f) => sum2 + f.charCount, 0);
        const modelName = this.aiService.getSemanticModelName();
        const totalToProcess = filesToProcess.length;
        const progressText = isIncrementalUpdate ? `Processing batch ${batchIndex + 1}/${totalBatches} (${batchFileCount} notes, ${batchCharCount} chars)... (${processed}/${totalToProcess} completed, ${failed} failed, ${unchangedCount} unchanged)` : `Processing batch ${batchIndex + 1}/${totalBatches} (${batchFileCount} notes, ${batchCharCount} chars)... (${processed}/${totalToProcess} completed, ${failed} failed)`;
        progressNotice.setMessage(progressText);
        let batchResult = null;
        try {
          batchResult = await this.analyzeBatch(batch, batchIndex);
        } catch (batchError) {
          const err = batchError instanceof SemanticAnalysisError ? batchError : new SemanticAnalysisError(batchError.message, "other", modelName);
          if (err.errorType === "quota_exhausted") {
            await this.appendFailedBatch(batch, batchIndex, modelName, err.message);
            failed += batch.length;
            processed += batch.length;
            progressNotice.hide();
            stoppedDueToQuota = true;
            break;
          }
          if (err.errorType === "rate_limit") {
            progressNotice.setMessage(`Rate limited, waiting 15s before retry...`);
            await new Promise((resolve) => this.win.setTimeout(resolve, 15e3));
            try {
              batchResult = await this.analyzeBatch(batch, batchIndex);
            } catch (retryError) {
              await this.appendFailedBatch(batch, batchIndex, modelName, retryError.message);
              failed += batch.length;
              processed += batch.length;
            }
          } else {
            await this.appendFailedBatch(batch, batchIndex, modelName, err.message);
            failed += batch.length;
            processed += batch.length;
          }
        }
        if (batchResult) {
          totalTokenUsage.promptTokens += batchResult.tokenUsage.promptTokens;
          totalTokenUsage.candidatesTokens += batchResult.tokenUsage.candidatesTokens;
          totalTokenUsage.totalTokens += batchResult.tokenUsage.totalTokens;
          const perNoteFailures = [];
          for (let i = 0; i < batch.length; i++) {
            const fileData = batch[i];
            const result = batchResult.results[i];
            if (result && result.success && result.data) {
              results.push(result.data);
              processed++;
            } else {
              perNoteFailures.push({
                path: fileData.file.path,
                basename: fileData.file.basename,
                charCount: fileData.charCount
              });
              failed++;
              processed++;
            }
          }
          if (perNoteFailures.length > 0) {
            await this.appendFailedNotes(perNoteFailures, batchIndex, "Empty or missing analysis in batch response");
          }
          const mergedSoFar = this.mergeAnalysisResults(unchangedResults, results, deletedFilePaths);
          if (firstBatchTimestamp === null) firstBatchTimestamp = (/* @__PURE__ */ new Date()).toISOString();
          const batchMetadata = isIncrementalUpdate && existingAnalysis ? {
            generatedAt: existingAnalysis.generatedAt,
            totalFiles: mergedSoFar.length,
            generatedFiles: existingAnalysis.generatedFiles ?? existingAnalysis.totalFiles,
            updatedFiles: (existingAnalysis.updatedFiles ?? 0) + results.length
          } : {
            generatedAt: firstBatchTimestamp,
            totalFiles: mergedSoFar.length,
            generatedFiles: results.length,
            updatedFiles: 0
          };
          await this.saveBatchResults(mergedSoFar, isIncrementalUpdate, totalTokenUsage, batchMetadata);
        }
        if (batchIndex < totalBatches - 1) {
          const preparingNextBatchText = isIncrementalUpdate ? `Preparing batch ${batchIndex + 2}/${totalBatches}... (${processed}/${filesToProcess.length} completed, ${failed} failed, ${unchangedCount} unchanged)` : `Preparing batch ${batchIndex + 2}/${totalBatches}... (${processed}/${filesToProcess.length} completed, ${failed} failed)`;
          progressNotice.setMessage(preparingNextBatchText);
          await new Promise((resolve) => this.win.setTimeout(resolve, delayBetweenBatches));
        } else if (totalBatches === 1) {
        }
      }
      if (stoppedDueToQuota && lastBatchIndex + 1 < totalBatches) {
        const remainingBatches = batches.slice(lastBatchIndex + 1);
        await this.saveRemainingNotes(remainingBatches);
      }
      progressNotice.hide();
      let finalResults;
      if (isIncrementalUpdate) {
        finalResults = this.mergeAnalysisResults(unchangedResults, results, deletedFilePaths);
      } else {
        finalResults = results;
      }
      const enhanceNotice = new import_obsidian11.Notice(t("notices.calculatingGraphMetrics"), 0);
      const graphMetrics = await this.calculateGraphMetrics();
      const enhancedResults = finalResults.map((result) => {
        const metrics = graphMetrics.get(result.path);
        return {
          ...result,
          graphMetrics: metrics
        };
      });
      const resultsWithRankings = this.calculateCentralityRankings(enhancedResults);
      await this.saveAnalysisResults(
        resultsWithRankings,
        isIncrementalUpdate,
        newCount,
        changedCount,
        totalTokenUsage
      );
      if (!stoppedDueToQuota && failed === 0) {
        await this.clearFailedBatches();
      }
      enhanceNotice.hide();
      const successCount = processed - failed;
      let completionMessage;
      if (stoppedDueToQuota) {
        const retryTime = new Date(Date.now() + 24 * 60 * 60 * 1e3);
        const retryTimeStr = retryTime.toLocaleString();
        const remainingCount = filesToProcess.length - successCount;
        completionMessage = t("notices.vaultCompleteQuota", {
          success: successCount,
          total: filesToProcess.length,
          remaining: remainingCount,
          retryTime: retryTimeStr
        });
      } else if (isIncrementalUpdate) {
        completionMessage = failed === 0 ? t("notices.vaultCompleteIncrementalOk", {
          success: successCount,
          changed: changedCount,
          new: newCount,
          unchanged: unchangedCount,
          deleted: deletedFilePaths.length
        }) : t("notices.vaultCompleteIncrementalWarn", {
          success: successCount,
          failed,
          unchanged: unchangedCount,
          deleted: deletedFilePaths.length
        });
      } else {
        completionMessage = failed === 0 ? t("notices.vaultCompleteFullOk", { success: successCount }) : t("notices.vaultCompleteFullWarn", { success: successCount, failed });
      }
      new import_obsidian11.Notice(completionMessage);
      return true;
    } catch (error) {
      const err = error instanceof Error ? error : new Error(String(error));
      new import_obsidian11.Notice(t("notices.vaultAnalysisFailed", { message: getUserFriendlyMessage(err) }));
      return false;
    } finally {
      this.clearAnalysisInProgress();
    }
  }
  async analyzeBatch(fileDataList, batchIndex, modelOverride) {
    try {
      const fileData = fileDataList;
      const shortFiles = fileData.filter((data) => data.isShort);
      const apiFiles = fileData.filter((data) => !data.isShort);
      let batchTokenUsage = this.ZERO_TOKEN_USAGE;
      const results = [];
      shortFiles.forEach((data) => {
        results.push({
          success: true,
          data: {
            id: this.generateFileId(data.file),
            title: data.file.basename,
            summary: `Note is empty or too short for semantic analysis (${data.charCount} chars)`,
            keywords: "",
            knowledgeDomains: [],
            // Empty array instead of empty string
            created: data.created,
            modified: data.modified,
            path: data.file.path,
            charCount: data.charCount
          }
        });
      });
      if (apiFiles.length > 0) {
        try {
          const model = modelOverride ?? this.aiService.getSemanticModelName();
          const batchAnalysisResult = await this.generateStructuredBatchAnalysis(apiFiles, model);
          batchTokenUsage = batchAnalysisResult.tokenUsage;
          for (let i = 0; i < apiFiles.length; i++) {
            const data = apiFiles[i];
            const analysis = batchAnalysisResult.results[i];
            if (analysis && analysis.summary) {
              const domainArray = analysis.knowledgeDomain ? analysis.knowledgeDomain.split(",").map((domain) => domain.trim()).filter((domain) => domain.length > 0) : [];
              results.push({
                success: true,
                data: {
                  id: this.generateFileId(data.file),
                  title: data.file.basename,
                  summary: analysis.summary,
                  keywords: analysis.keywords,
                  knowledgeDomains: domainArray,
                  // Use array instead of string
                  created: data.created,
                  modified: data.modified,
                  path: data.file.path,
                  charCount: data.charCount
                }
              });
            } else {
              results.push({ success: false, error: "Failed to generate analysis" });
            }
          }
        } catch (apiError) {
          if (apiError instanceof SemanticAnalysisError) {
            throw apiError;
          }
          throw apiError;
        }
      }
      const sortedResults = [];
      for (const originalData of fileData) {
        const result = results.find(
          (r) => r.data && r.data.path === originalData.file.path
        ) || results.find((r) => !r.success);
        if (result) {
          sortedResults.push(result);
          const index2 = results.indexOf(result);
          if (index2 > -1) {
            results.splice(index2, 1);
          }
        } else {
          sortedResults.push({ success: false, error: "Result not found" });
        }
      }
      return { results: sortedResults, tokenUsage: batchTokenUsage };
    } catch (error) {
      if (error instanceof SemanticAnalysisError) {
        throw error;
      }
      return {
        results: fileDataList.map(() => ({ success: false, error: error.message })),
        tokenUsage: this.ZERO_TOKEN_USAGE
      };
    }
  }
  generateFileId(file) {
    return file.path.replace(/[^a-zA-Z0-9]/g, "_").toLowerCase();
  }
  async getFailedBatchFilePaths() {
    try {
      const data = await this.readFailedBatchesData();
      const paths = /* @__PURE__ */ new Set();
      if ("remaining" in data && data.remaining?.notes) {
        for (const note of data.remaining.notes) {
          if (note.path) paths.add(note.path);
        }
      }
      for (const fb of data.failed) {
        for (const note of fb.notes) {
          if (note.path) paths.add(note.path);
        }
      }
      return [...paths];
    } catch {
      return [];
    }
  }
  async clearFailedBatches() {
    await this.dataStore.setFailedBatches(this.FAILED_BATCHES_EMPTY);
  }
  async readFailedBatchesData() {
    const raw = await this.dataStore.getFailedBatches();
    if (!raw) {
      return this.FAILED_BATCHES_EMPTY;
    }
    if (raw.remaining != null || Array.isArray(raw.failed)) {
      return { remaining: raw.remaining ?? null, failed: raw.failed ?? [] };
    }
    const legacy = raw;
    const migrated = { remaining: null, failed: [] };
    for (const fb of legacy.failedBatches ?? []) {
      migrated.failed.push({
        timestamp: fb.timestamp ?? (/* @__PURE__ */ new Date()).toISOString(),
        batchIndex: fb.batchIndex ?? -1,
        primaryModel: fb.primaryModel ?? "",
        retryModel: fb.retryModel ?? "",
        error: fb.error ?? "Unknown",
        notes: fb.notes ?? []
      });
    }
    return migrated;
  }
  async appendFailedBatch(batch, batchIndex, modelName, error) {
    const data = await this.readFailedBatchesData();
    data.failed.push({
      timestamp: (/* @__PURE__ */ new Date()).toISOString(),
      batchIndex,
      primaryModel: modelName,
      retryModel: modelName,
      error,
      notes: batch.map((b) => ({ path: b.file.path, basename: b.file.basename, charCount: b.charCount }))
    });
    await this.dataStore.setFailedBatches(data);
  }
  async appendFailedNotes(notes, batchIndex, error) {
    if (notes.length === 0) return;
    const data = await this.readFailedBatchesData();
    data.failed.push({
      timestamp: (/* @__PURE__ */ new Date()).toISOString(),
      batchIndex,
      primaryModel: "",
      retryModel: "",
      error,
      notes
    });
    await this.dataStore.setFailedBatches(data);
  }
  async saveRemainingNotes(batches) {
    const notes = batches.flatMap(
      (batch) => batch.map((b) => ({ path: b.file.path, basename: b.file.basename, charCount: b.charCount }))
    );
    if (notes.length === 0) return;
    const data = await this.readFailedBatchesData();
    const now2 = /* @__PURE__ */ new Date();
    const retryAfter = new Date(now2.getTime() + 24 * 60 * 60 * 1e3);
    data.remaining = {
      savedAt: now2.toISOString(),
      retryAfter: retryAfter.toISOString(),
      reason: "quota_exhausted",
      notes
    };
    await this.dataStore.setFailedBatches(data);
  }
  async ensureVaultAnalysisFileExists() {
    const existing = await this.dataStore.getVaultAnalysis();
    if (existing) {
      return;
    }
    const initialData = {
      generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
      totalFiles: 0,
      generatedFiles: 0,
      updatedFiles: 0,
      apiProvider: "Google Gemini",
      results: []
    };
    await this.dataStore.setVaultAnalysis(initialData);
  }
  async viewVaultAnalysisResults() {
    if (this.isAnalysisInProgress()) {
      new import_obsidian11.Notice(t("notices.vaultAnalysisInProgress"));
      return;
    }
    try {
      let analysisData = await this.dataStore.getVaultAnalysis();
      let hasExistingData = false;
      if (analysisData && Array.isArray(analysisData.results)) {
        hasExistingData = analysisData.results.length > 0;
      } else {
        const initialData = {
          generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
          totalFiles: 0,
          generatedFiles: 0,
          updatedFiles: 0,
          apiProvider: "Google Gemini",
          results: []
        };
        await this.dataStore.setVaultAnalysis(initialData);
        analysisData = initialData;
        hasExistingData = false;
      }
      this.openVaultAnalysisModal(analysisData, hasExistingData);
      if (hasExistingData && analysisData) {
        const hasGraphMetrics = analysisData.results.some(
          (result) => result.graphMetrics && Object.keys(result.graphMetrics).length > 0
        );
        if (!hasGraphMetrics) {
          const notice = new import_obsidian11.Notice(t("notices.enhanceMetricsPrompt"), 0);
          const noticeContainer = notice.messageEl;
          const enhanceBtn = noticeContainer.createEl("button", {
            text: t("notices.enhanceMetricsButton"),
            cls: "graph-enhance-btn"
          });
          enhanceBtn.onclick = () => {
            notice.hide();
            void (async () => {
              const enhanceNotice = new import_obsidian11.Notice(t("notices.enhancingWithMetrics"), 0);
              try {
                await this.enhanceWithGraphMetrics();
                enhanceNotice.hide();
                new import_obsidian11.Notice(t("notices.enhancedWithMetrics"));
                await this.viewVaultAnalysisResults();
              } catch (err) {
                enhanceNotice.hide();
                new import_obsidian11.Notice(t("notices.enhanceAnalysisFailed", {
                  message: err instanceof Error ? err.message : String(err)
                }));
              }
            })();
          };
          this.win.setTimeout(() => notice.hide(), 8e3);
        }
      }
    } catch (error) {
      new import_obsidian11.Notice(error instanceof Error ? error.message : t("notices.loadVaultAnalysisFailed"));
    }
  }
  getIncludedMarkdownFiles() {
    return this.pluginService.getPlugin().getIncludedMarkdownFiles();
  }
  updateSettings(settings) {
    this.settings = settings;
    this.aiService.updateSettings(settings);
    this.masterAnalysisManager.updateSettings(settings);
  }
  destroy() {
  }
  /**
   * Build enhanced results (domain code-to-name conversion) and output data for vault-analysis.json.
   * Shared by saveBatchResults and saveAnalysisResults.
   */
  async buildEnhancedResultsAndOutputData(results, isIncrementalUpdate, metadata) {
    const sortedResults = [...results].sort((a2, b) => a2.title.localeCompare(b.title));
    const domainHelper = KnowledgeDomainHelper.getInstance(this.app);
    await domainHelper.loadDomainTemplate();
    const ddcCodeToNameMap = domainHelper.getDomainCodeToNameMap();
    const enhancedResults = sortedResults.map((result) => {
      let domainCodes = [];
      const legacy = result;
      if (legacy.knowledgeDomain && typeof legacy.knowledgeDomain === "string") {
        domainCodes = legacy.knowledgeDomain.split(",").map((code) => code.trim()).filter((code) => code.length > 0);
      } else if (result.knowledgeDomains && Array.isArray(result.knowledgeDomains)) {
        domainCodes = result.knowledgeDomains;
      }
      const domainNames = domainCodes.map((code) => ddcCodeToNameMap.get(code) || code);
      const cleanResult = {
        id: result.id,
        title: result.title,
        summary: result.summary,
        keywords: result.keywords,
        knowledgeDomains: domainNames,
        created: result.created,
        modified: result.modified,
        path: result.path,
        charCount: result.charCount ?? result.wordCount ?? 0
      };
      if (result.graphMetrics) cleanResult.graphMetrics = result.graphMetrics;
      if (result.centralityRankings) cleanResult.centralityRankings = result.centralityRankings;
      return cleanResult;
    });
    const outputData = {
      generatedAt: metadata.generatedAt,
      ...isIncrementalUpdate && { updatedAt: (/* @__PURE__ */ new Date()).toISOString() },
      totalFiles: metadata.totalFiles,
      generatedFiles: metadata.generatedFiles,
      updatedFiles: metadata.updatedFiles,
      apiProvider: "Google Gemini",
      ...metadata.tokenUsage && { tokenUsage: metadata.tokenUsage },
      results: enhancedResults
    };
    return { enhancedResults, outputData };
  }
  /**
   * Save batch results to disk (no graph metrics). Called after each successful batch.
   */
  async saveBatchResults(mergedResults, isIncrementalUpdate, totalTokenUsage, metadata) {
    await this.ensureVaultAnalysisFileExists();
    const { outputData } = await this.buildEnhancedResultsAndOutputData(mergedResults, isIncrementalUpdate, {
      ...metadata,
      tokenUsage: totalTokenUsage
    });
    await this.dataStore.setVaultAnalysis(outputData);
  }
  async saveAnalysisResults(results, isIncrementalUpdate, newCount, changedCount, batchTokenUsage) {
    try {
      await this.ensureVaultAnalysisFileExists();
      const existingData = await this.dataStore.getVaultAnalysis();
      let metadata;
      if (!isIncrementalUpdate) {
        metadata = {
          generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
          totalFiles: results.length,
          generatedFiles: results.length,
          updatedFiles: 0,
          ...batchTokenUsage && { tokenUsage: batchTokenUsage }
        };
      } else if (existingData) {
        const existingGeneratedFiles = existingData.generatedFiles ?? existingData.totalFiles;
        const existingUpdatedFiles = existingData.updatedFiles ?? 0;
        const existingTokens = existingData.tokenUsage ?? { promptTokens: 0, candidatesTokens: 0, totalTokens: 0 };
        metadata = {
          generatedAt: existingData.generatedAt,
          totalFiles: results.length,
          generatedFiles: existingGeneratedFiles,
          updatedFiles: existingUpdatedFiles + newCount + changedCount,
          tokenUsage: batchTokenUsage ? {
            promptTokens: existingTokens.promptTokens + batchTokenUsage.promptTokens,
            candidatesTokens: existingTokens.candidatesTokens + batchTokenUsage.candidatesTokens,
            totalTokens: existingTokens.totalTokens + batchTokenUsage.totalTokens
          } : existingData.tokenUsage
        };
      } else {
        metadata = {
          generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
          totalFiles: results.length,
          generatedFiles: results.length,
          updatedFiles: 0,
          ...batchTokenUsage && { tokenUsage: batchTokenUsage }
        };
      }
      const { outputData } = await this.buildEnhancedResultsAndOutputData(results, isIncrementalUpdate, metadata);
      await this.dataStore.setVaultAnalysis(outputData);
      this.scheduleDerivedVisualizations(outputData);
    } catch (error) {
      throw new Error(`Failed to save results: ${error.message}`);
    }
  }
  async generateStructuredBatchAnalysis(fileData, modelOverride) {
    const meaningfulFiles = fileData.filter((data) => !data.isShort && data.content.trim().length > 0);
    if (meaningfulFiles.length === 0) {
      return {
        results: [],
        tokenUsage: this.ZERO_TOKEN_USAGE
      };
    }
    await this.loadDomainTemplate();
    const sectionsJson = JSON.stringify(
      this.subdivisionsList.map((subdivision) => ({
        id: subdivision.id,
        name: subdivision.name
      }))
    );
    const systemPrompt = `You are an expert knowledge analyst specializing in semantic analysis and knowledge classification. Your role is to analyze notes and extract meaningful insights using the Modern Knowledge Taxonomy system.`;
    const contextPrompt = `## Knowledge Domain Classification Reference
Use the following knowledge domain subdivisions for classification. Each subdivision has an ID and name:

\`\`\`json
${sectionsJson}
\`\`\`

## Classification Guidelines:
- Be specific: use the most detailed subdivision that applies
- Multi-domain notes: a note can belong to multiple subdivisions if it spans different domains
- Valid codes only: only use knowledge domain codes from the provided reference list
- Format: comma-separated knowledge domain codes (e.g., "1-1,3-2")`;
    const instructionPrompt = `## Analysis Instructions
For each note, provide:
1. **Summary**: A two to three sentence summary of the main concept or purpose (be detailed and insightful)
2. **Keywords**: 3-6 key terms or phrases (comma-separated)
3. **Knowledge Domain**: Knowledge domain subdivision codes that best match the content (comma-separated)

## Notes to Analyze:`;
    const contextSample = buildContextSampleFromNoteContents(
      meaningfulFiles.map((data) => ({ content: data.content }))
    );
    const languageSection = buildLanguagePromptSection(this.settings, contextSample);
    let fullPrompt = `${systemPrompt}

${contextPrompt}

${instructionPrompt}

${languageSection}

`;
    meaningfulFiles.forEach((data, index2) => {
      fullPrompt += `--- Note ${index2 + 1}: "${data.file.basename}" (${data.charCount} chars) ---
${data.content}

`;
    });
    try {
      const responseSchema = this.aiService.createVaultSemanticAnalysisSchema(meaningfulFiles.length);
      const maxOutputTokens = meaningfulFiles.length * 1024 + 4e3;
      const response = await this.aiService.generateSemanticAnalysis(
        fullPrompt,
        responseSchema,
        maxOutputTokens,
        0.3,
        // Low temperature for consistent results
        0.72,
        // Default topP
        modelOverride
      );
      return {
        results: response.result.map((item) => ({
          summary: item.summary || "",
          keywords: item.keywords || "",
          knowledgeDomain: item.knowledgeDomain || ""
        })),
        tokenUsage: response.tokenUsage
      };
    } catch (structuredError) {
      if (!(structuredError instanceof SemanticAnalysisError)) {
      }
      throw structuredError;
    }
  }
};

// src/views/CentralityResultsView.ts
var import_obsidian12 = require("obsidian");
var CENTRALITY_RESULTS_VIEW_TYPE = "centrality-results-view";
var CentralityResultsView = class extends import_obsidian12.ItemView {
  constructor(leaf) {
    super(leaf);
    this.results = [];
    this.algorithm = "";
    this.currentPage = 1;
    this.itemsPerPage = 30;
    // Will be calculated dynamically
    this.paginationContainer = null;
  }
  getViewType() {
    return CENTRALITY_RESULTS_VIEW_TYPE;
  }
  getDisplayText() {
    return t("centralityView.title", { algorithm: "Centrality" });
  }
  getIcon() {
    return "waypoints";
  }
  onOpen() {
    this.updateStatusBarForGraphViews();
    return Promise.resolve();
  }
  async setResults(results, algorithm) {
    this.results = results;
    this.algorithm = algorithm;
    this.currentPage = 1;
    await this.updateView();
  }
  updateView() {
    const container = this.containerEl.children[1];
    container.empty();
    container.addClass("centrality-results-container");
    if (container.clientHeight > 0) {
      this.itemsPerPage = this.calculateItemsPerPage(container);
    }
    const header = container.createEl("div", { cls: "centrality-results-header" });
    header.createEl("h2", { text: t("centralityView.title", { algorithm: this.algorithm }) });
    const resultsSection = container.createEl("div", { cls: "centrality-results-section" });
    const resultsList = resultsSection.createEl("div", { cls: "centrality-results-list" });
    this.renderCurrentPage(resultsList);
    const totalPages = Math.ceil(this.results.length / this.itemsPerPage);
    if (totalPages > 1) {
      this.createPaginationControls(resultsSection, totalPages, this.results.length);
    }
    return Promise.resolve();
  }
  calculateItemsPerPage(container) {
    const containerHeight = container.clientHeight;
    const headerHeight = 45;
    const paginationHeight = 42;
    const itemHeight = 26;
    const availableHeight = containerHeight - headerHeight - paginationHeight;
    const calculatedItems = Math.floor(availableHeight / itemHeight);
    return Math.max(10, Math.min(calculatedItems, 50));
  }
  renderCurrentPage(resultsList) {
    const startIndex = (this.currentPage - 1) * this.itemsPerPage;
    const endIndex = startIndex + this.itemsPerPage;
    const paginatedResults = this.results.slice(startIndex, endIndex);
    resultsList.empty();
    paginatedResults.forEach((result, index2) => {
      const resultItem = resultsList.createEl("div", { cls: "centrality-result-item" });
      const itemNumber = startIndex + index2 + 1;
      resultItem.createEl("span", {
        cls: "result-item-number",
        text: `${itemNumber}.`
      });
      const noteInfo = resultItem.createEl("div", { cls: "result-note-info" });
      const noteLink = noteInfo.createEl("a", {
        cls: "result-note-link",
        text: result.node_name
      });
      noteLink.addEventListener("click", (e) => {
        e.preventDefault();
        const file = this.app.vault.getAbstractFileByPath(result.node_name);
        if (file instanceof import_obsidian12.TFile) {
          void this.app.workspace.getLeaf().openFile(file);
        }
      });
      const score2 = this.getScoreForAlgorithm(result);
      resultItem.createEl("div", {
        cls: "result-score",
        text: score2.toFixed(3)
      });
    });
  }
  createPaginationControls(parentContainer, totalPages, totalResults) {
    if (this.paginationContainer) {
      this.paginationContainer.remove();
      this.paginationContainer = null;
    }
    if (totalPages <= 1 || totalResults === 0) {
      return;
    }
    this.paginationContainer = parentContainer.createEl("div", {
      cls: "centrality-pagination"
    });
    const prevButton = this.paginationContainer.createEl("button", {
      cls: "centrality-pagination-button"
    });
    const prevIcon = prevButton.createEl("span");
    (0, import_obsidian12.setIcon)(prevIcon, "chevron-left");
    prevButton.disabled = this.currentPage === 1;
    prevButton.addEventListener("click", () => {
      if (this.currentPage > 1) {
        this.updatePage(this.currentPage - 1);
      }
    });
    const startIndex = (this.currentPage - 1) * this.itemsPerPage + 1;
    const endIndex = Math.min(this.currentPage * this.itemsPerPage, totalResults);
    this.paginationContainer.createEl("div", {
      text: `Showing ${startIndex}-${endIndex} of ${totalResults}`,
      cls: "centrality-pagination-info"
    });
    const nextButton = this.paginationContainer.createEl("button", {
      cls: "centrality-pagination-button"
    });
    const nextIcon = nextButton.createEl("span");
    (0, import_obsidian12.setIcon)(nextIcon, "chevron-right");
    nextButton.disabled = this.currentPage === totalPages;
    nextButton.addEventListener("click", () => {
      if (this.currentPage < totalPages) {
        this.updatePage(this.currentPage + 1);
      }
    });
  }
  updatePage(newPage) {
    const container = this.containerEl.children[1];
    if (!container) return;
    this.currentPage = newPage;
    const resultsSection = container.querySelector(".centrality-results-section");
    const resultsList = container.querySelector(".centrality-results-list");
    if (!resultsSection || !resultsList) return;
    this.renderCurrentPage(resultsList);
    const totalPages = Math.ceil(this.results.length / this.itemsPerPage);
    const totalResults = this.results.length;
    if (this.paginationContainer) {
      this.paginationContainer.remove();
      this.paginationContainer = null;
    }
    this.createPaginationControls(resultsSection, totalPages, totalResults);
  }
  getScoreForAlgorithm(node) {
    if (!node?.centrality) {
      return 0;
    }
    const algorithmLower = this.algorithm.toLowerCase();
    if (algorithmLower.includes("degree")) {
      return typeof node.centrality.degree === "number" ? node.centrality.degree : 0;
    } else if (algorithmLower.includes("eigenvector")) {
      return typeof node.centrality.eigenvector === "number" ? node.centrality.eigenvector : 0;
    } else if (algorithmLower.includes("betweenness")) {
      return typeof node.centrality.betweenness === "number" ? node.centrality.betweenness : 0;
    } else if (algorithmLower.includes("closeness")) {
      return typeof node.centrality.closeness === "number" ? node.centrality.closeness : 0;
    }
    return 0;
  }
  onClose() {
    this.contentEl.empty();
    this.contentEl.ownerDocument.defaultView.setTimeout(() => {
      this.updateStatusBarForGraphViews();
    }, 10);
    return Promise.resolve();
  }
  /**
   * Helper method to manage status bar visibility for graph-related views
   * Hides status bar if any graph analysis or centrality view is active
   */
  updateStatusBarForGraphViews() {
    const activeView = this.app.workspace.getActiveViewOfType(import_obsidian12.ItemView);
    const activeViewType = activeView?.getViewType();
    const shouldHideStatusBar = activeViewType === CENTRALITY_RESULTS_VIEW_TYPE || activeViewType === GRAPH_ANALYSIS_VIEW_TYPE;
    const doc = this.contentEl.ownerDocument;
    if (shouldHideStatusBar) {
      doc.body.addClass("graph-analysis-hide-status-bar");
    } else {
      doc.body.removeClass("graph-analysis-hide-status-bar");
    }
  }
};

// node_modules/chroma-js/src/utils/limit.js
var { min: min3, max: max3 } = Math;
var limit_default = (x3, low = 0, high = 1) => {
  return min3(max3(low, x3), high);
};

// node_modules/chroma-js/src/utils/clip_rgb.js
var clip_rgb_default = (rgb4) => {
  rgb4._clipped = false;
  rgb4._unclipped = rgb4.slice(0);
  for (let i = 0; i <= 3; i++) {
    if (i < 3) {
      if (rgb4[i] < 0 || rgb4[i] > 255) rgb4._clipped = true;
      rgb4[i] = limit_default(rgb4[i], 0, 255);
    } else if (i === 3) {
      rgb4[i] = limit_default(rgb4[i], 0, 1);
    }
  }
  return rgb4;
};

// node_modules/chroma-js/src/utils/type.js
var classToType = {};
for (let name of [
  "Boolean",
  "Number",
  "String",
  "Function",
  "Array",
  "Date",
  "RegExp",
  "Undefined",
  "Null"
]) {
  classToType[`[object ${name}]`] = name.toLowerCase();
}
function type_default(obj) {
  return classToType[Object.prototype.toString.call(obj)] || "object";
}

// node_modules/chroma-js/src/utils/unpack.js
var unpack_default = (args, keyOrder = null) => {
  if (args.length >= 3) return Array.prototype.slice.call(args);
  if (type_default(args[0]) == "object" && keyOrder) {
    return keyOrder.split("").filter((k) => args[0][k] !== void 0).map((k) => args[0][k]);
  }
  return args[0].slice(0);
};

// node_modules/chroma-js/src/utils/last.js
var last_default = (args) => {
  if (args.length < 2) return null;
  const l = args.length - 1;
  if (type_default(args[l]) == "string") return args[l].toLowerCase();
  return null;
};

// node_modules/chroma-js/src/utils/index.js
var { PI, min: min4, max: max4 } = Math;
var rnd2 = (a2) => Math.round(a2 * 100) / 100;
var rnd3 = (a2) => Math.round(a2 * 100) / 100;
var TWOPI = PI * 2;
var PITHIRD = PI / 3;
var DEG2RAD = PI / 180;
var RAD2DEG = 180 / PI;
function reverse3(arr) {
  return [...arr.slice(0, 3).reverse(), ...arr.slice(3)];
}

// node_modules/chroma-js/src/io/input.js
var input_default = {
  format: {},
  autodetect: []
};

// node_modules/chroma-js/src/Color.js
var Color2 = class {
  constructor(...args) {
    const me = this;
    if (type_default(args[0]) === "object" && args[0].constructor && args[0].constructor === this.constructor) {
      return args[0];
    }
    let mode = last_default(args);
    let autodetect = false;
    if (!mode) {
      autodetect = true;
      if (!input_default.sorted) {
        input_default.autodetect = input_default.autodetect.sort((a2, b) => b.p - a2.p);
        input_default.sorted = true;
      }
      for (let chk of input_default.autodetect) {
        mode = chk.test(...args);
        if (mode) break;
      }
    }
    if (input_default.format[mode]) {
      const rgb4 = input_default.format[mode].apply(
        null,
        autodetect ? args : args.slice(0, -1)
      );
      me._rgb = clip_rgb_default(rgb4);
    } else {
      throw new Error("unknown format: " + args);
    }
    if (me._rgb.length === 3) me._rgb.push(1);
  }
  toString() {
    if (type_default(this.hex) == "function") return this.hex();
    return `[${this._rgb.join(",")}]`;
  }
};
var Color_default = Color2;

// node_modules/chroma-js/src/version.js
var version = "3.2.0";

// node_modules/chroma-js/src/chroma.js
var chroma = (...args) => {
  return new Color_default(...args);
};
chroma.version = version;
var chroma_default = chroma;

// node_modules/chroma-js/src/colors/w3cx11.js
var w3cx11 = {
  aliceblue: "#f0f8ff",
  antiquewhite: "#faebd7",
  aqua: "#00ffff",
  aquamarine: "#7fffd4",
  azure: "#f0ffff",
  beige: "#f5f5dc",
  bisque: "#ffe4c4",
  black: "#000000",
  blanchedalmond: "#ffebcd",
  blue: "#0000ff",
  blueviolet: "#8a2be2",
  brown: "#a52a2a",
  burlywood: "#deb887",
  cadetblue: "#5f9ea0",
  chartreuse: "#7fff00",
  chocolate: "#d2691e",
  coral: "#ff7f50",
  cornflowerblue: "#6495ed",
  cornsilk: "#fff8dc",
  crimson: "#dc143c",
  cyan: "#00ffff",
  darkblue: "#00008b",
  darkcyan: "#008b8b",
  darkgoldenrod: "#b8860b",
  darkgray: "#a9a9a9",
  darkgreen: "#006400",
  darkgrey: "#a9a9a9",
  darkkhaki: "#bdb76b",
  darkmagenta: "#8b008b",
  darkolivegreen: "#556b2f",
  darkorange: "#ff8c00",
  darkorchid: "#9932cc",
  darkred: "#8b0000",
  darksalmon: "#e9967a",
  darkseagreen: "#8fbc8f",
  darkslateblue: "#483d8b",
  darkslategray: "#2f4f4f",
  darkslategrey: "#2f4f4f",
  darkturquoise: "#00ced1",
  darkviolet: "#9400d3",
  deeppink: "#ff1493",
  deepskyblue: "#00bfff",
  dimgray: "#696969",
  dimgrey: "#696969",
  dodgerblue: "#1e90ff",
  firebrick: "#b22222",
  floralwhite: "#fffaf0",
  forestgreen: "#228b22",
  fuchsia: "#ff00ff",
  gainsboro: "#dcdcdc",
  ghostwhite: "#f8f8ff",
  gold: "#ffd700",
  goldenrod: "#daa520",
  gray: "#808080",
  green: "#008000",
  greenyellow: "#adff2f",
  grey: "#808080",
  honeydew: "#f0fff0",
  hotpink: "#ff69b4",
  indianred: "#cd5c5c",
  indigo: "#4b0082",
  ivory: "#fffff0",
  khaki: "#f0e68c",
  laserlemon: "#ffff54",
  lavender: "#e6e6fa",
  lavenderblush: "#fff0f5",
  lawngreen: "#7cfc00",
  lemonchiffon: "#fffacd",
  lightblue: "#add8e6",
  lightcoral: "#f08080",
  lightcyan: "#e0ffff",
  lightgoldenrod: "#fafad2",
  lightgoldenrodyellow: "#fafad2",
  lightgray: "#d3d3d3",
  lightgreen: "#90ee90",
  lightgrey: "#d3d3d3",
  lightpink: "#ffb6c1",
  lightsalmon: "#ffa07a",
  lightseagreen: "#20b2aa",
  lightskyblue: "#87cefa",
  lightslategray: "#778899",
  lightslategrey: "#778899",
  lightsteelblue: "#b0c4de",
  lightyellow: "#ffffe0",
  lime: "#00ff00",
  limegreen: "#32cd32",
  linen: "#faf0e6",
  magenta: "#ff00ff",
  maroon: "#800000",
  maroon2: "#7f0000",
  maroon3: "#b03060",
  mediumaquamarine: "#66cdaa",
  mediumblue: "#0000cd",
  mediumorchid: "#ba55d3",
  mediumpurple: "#9370db",
  mediumseagreen: "#3cb371",
  mediumslateblue: "#7b68ee",
  mediumspringgreen: "#00fa9a",
  mediumturquoise: "#48d1cc",
  mediumvioletred: "#c71585",
  midnightblue: "#191970",
  mintcream: "#f5fffa",
  mistyrose: "#ffe4e1",
  moccasin: "#ffe4b5",
  navajowhite: "#ffdead",
  navy: "#000080",
  oldlace: "#fdf5e6",
  olive: "#808000",
  olivedrab: "#6b8e23",
  orange: "#ffa500",
  orangered: "#ff4500",
  orchid: "#da70d6",
  palegoldenrod: "#eee8aa",
  palegreen: "#98fb98",
  paleturquoise: "#afeeee",
  palevioletred: "#db7093",
  papayawhip: "#ffefd5",
  peachpuff: "#ffdab9",
  peru: "#cd853f",
  pink: "#ffc0cb",
  plum: "#dda0dd",
  powderblue: "#b0e0e6",
  purple: "#800080",
  purple2: "#7f007f",
  purple3: "#a020f0",
  rebeccapurple: "#663399",
  red: "#ff0000",
  rosybrown: "#bc8f8f",
  royalblue: "#4169e1",
  saddlebrown: "#8b4513",
  salmon: "#fa8072",
  sandybrown: "#f4a460",
  seagreen: "#2e8b57",
  seashell: "#fff5ee",
  sienna: "#a0522d",
  silver: "#c0c0c0",
  skyblue: "#87ceeb",
  slateblue: "#6a5acd",
  slategray: "#708090",
  slategrey: "#708090",
  snow: "#fffafa",
  springgreen: "#00ff7f",
  steelblue: "#4682b4",
  tan: "#d2b48c",
  teal: "#008080",
  thistle: "#d8bfd8",
  tomato: "#ff6347",
  turquoise: "#40e0d0",
  violet: "#ee82ee",
  wheat: "#f5deb3",
  white: "#ffffff",
  whitesmoke: "#f5f5f5",
  yellow: "#ffff00",
  yellowgreen: "#9acd32"
};
var w3cx11_default = w3cx11;

// node_modules/chroma-js/src/io/hex/hex2rgb.js
var RE_HEX = /^#?([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/;
var RE_HEXA = /^#?([A-Fa-f0-9]{8}|[A-Fa-f0-9]{4})$/;
var hex2rgb = (hex3) => {
  if (hex3.match(RE_HEX)) {
    if (hex3.length === 4 || hex3.length === 7) {
      hex3 = hex3.substr(1);
    }
    if (hex3.length === 3) {
      hex3 = hex3.split("");
      hex3 = hex3[0] + hex3[0] + hex3[1] + hex3[1] + hex3[2] + hex3[2];
    }
    const u = parseInt(hex3, 16);
    const r = u >> 16;
    const g2 = u >> 8 & 255;
    const b = u & 255;
    return [r, g2, b, 1];
  }
  if (hex3.match(RE_HEXA)) {
    if (hex3.length === 5 || hex3.length === 9) {
      hex3 = hex3.substr(1);
    }
    if (hex3.length === 4) {
      hex3 = hex3.split("");
      hex3 = hex3[0] + hex3[0] + hex3[1] + hex3[1] + hex3[2] + hex3[2] + hex3[3] + hex3[3];
    }
    const u = parseInt(hex3, 16);
    const r = u >> 24 & 255;
    const g2 = u >> 16 & 255;
    const b = u >> 8 & 255;
    const a2 = Math.round((u & 255) / 255 * 100) / 100;
    return [r, g2, b, a2];
  }
  throw new Error(`unknown hex color: ${hex3}`);
};
var hex2rgb_default = hex2rgb;

// node_modules/chroma-js/src/io/hex/rgb2hex.js
var { round } = Math;
var rgb2hex = (...args) => {
  let [r, g2, b, a2] = unpack_default(args, "rgba");
  let mode = last_default(args) || "auto";
  if (a2 === void 0) a2 = 1;
  if (mode === "auto") {
    mode = a2 < 1 ? "rgba" : "rgb";
  }
  r = round(r);
  g2 = round(g2);
  b = round(b);
  const u = r << 16 | g2 << 8 | b;
  let str = "000000" + u.toString(16);
  str = str.substr(str.length - 6);
  let hxa = "0" + round(a2 * 255).toString(16);
  hxa = hxa.substr(hxa.length - 2);
  switch (mode.toLowerCase()) {
    case "rgba":
      return `#${str}${hxa}`;
    case "argb":
      return `#${hxa}${str}`;
    default:
      return `#${str}`;
  }
};
var rgb2hex_default = rgb2hex;

// node_modules/chroma-js/src/io/named/index.js
Color_default.prototype.name = function() {
  const hex3 = rgb2hex_default(this._rgb, "rgb");
  for (let n of Object.keys(w3cx11_default)) {
    if (w3cx11_default[n] === hex3) return n.toLowerCase();
  }
  return hex3;
};
input_default.format.named = (name) => {
  name = name.toLowerCase();
  if (w3cx11_default[name]) return hex2rgb_default(w3cx11_default[name]);
  throw new Error("unknown color name: " + name);
};
input_default.autodetect.push({
  p: 5,
  test: (h, ...rest) => {
    if (!rest.length && type_default(h) === "string" && w3cx11_default[h.toLowerCase()]) {
      return "named";
    }
  }
});

// node_modules/chroma-js/src/ops/alpha.js
Color_default.prototype.alpha = function(a2, mutate = false) {
  if (a2 !== void 0 && type_default(a2) === "number") {
    if (mutate) {
      this._rgb[3] = a2;
      return this;
    }
    return new Color_default([this._rgb[0], this._rgb[1], this._rgb[2], a2], "rgb");
  }
  return this._rgb[3];
};

// node_modules/chroma-js/src/ops/clipped.js
Color_default.prototype.clipped = function() {
  return this._rgb._clipped || false;
};

// node_modules/chroma-js/src/io/lab/lab-constants.js
var labConstants = {
  // Corresponds roughly to RGB brighter/darker
  Kn: 18,
  // D65 standard referent
  labWhitePoint: "d65",
  Xn: 0.95047,
  Yn: 1,
  Zn: 1.08883,
  t0: 0.137931034,
  // 4 / 29
  t1: 0.206896552,
  // 6 / 29
  t2: 0.12841855,
  // 3 * t1 * t1
  t3: 8856452e-9,
  // t1 * t1 * t1,
  kE: 216 / 24389,
  kKE: 8,
  kK: 24389 / 27,
  RefWhiteRGB: {
    // sRGB
    X: 0.95047,
    Y: 1,
    Z: 1.08883
  },
  MtxRGB2XYZ: {
    m00: 0.4124564390896922,
    m01: 0.21267285140562253,
    m02: 0.0193338955823293,
    m10: 0.357576077643909,
    m11: 0.715152155287818,
    m12: 0.11919202588130297,
    m20: 0.18043748326639894,
    m21: 0.07217499330655958,
    m22: 0.9503040785363679
  },
  MtxXYZ2RGB: {
    m00: 3.2404541621141045,
    m01: -0.9692660305051868,
    m02: 0.055643430959114726,
    m10: -1.5371385127977166,
    m11: 1.8760108454466942,
    m12: -0.2040259135167538,
    m20: -0.498531409556016,
    m21: 0.041556017530349834,
    m22: 1.0572251882231791
  },
  // used in rgb2xyz
  As: 0.9414285350000001,
  Bs: 1.040417467,
  Cs: 1.089532651,
  MtxAdaptMa: {
    m00: 0.8951,
    m01: -0.7502,
    m02: 0.0389,
    m10: 0.2664,
    m11: 1.7135,
    m12: -0.0685,
    m20: -0.1614,
    m21: 0.0367,
    m22: 1.0296
  },
  MtxAdaptMaI: {
    m00: 0.9869929054667123,
    m01: 0.43230526972339456,
    m02: -0.008528664575177328,
    m10: -0.14705425642099013,
    m11: 0.5183602715367776,
    m12: 0.04004282165408487,
    m20: 0.15996265166373125,
    m21: 0.0492912282128556,
    m22: 0.9684866957875502
  }
};
var lab_constants_default = labConstants;
var ILLUMINANTS = /* @__PURE__ */ new Map([
  // ASTM E308-01
  ["a", [1.0985, 0.35585]],
  // Wyszecki & Stiles, p. 769
  ["b", [1.0985, 0.35585]],
  // C ASTM E308-01
  ["c", [0.98074, 1.18232]],
  // D50 (ASTM E308-01)
  ["d50", [0.96422, 0.82521]],
  // D55 (ASTM E308-01)
  ["d55", [0.95682, 0.92149]],
  // D65 (ASTM E308-01)
  ["d65", [0.95047, 1.08883]],
  // E (ASTM E308-01)
  ["e", [1, 1, 1]],
  // F2 (ASTM E308-01)
  ["f2", [0.99186, 0.67393]],
  // F7 (ASTM E308-01)
  ["f7", [0.95041, 1.08747]],
  // F11 (ASTM E308-01)
  ["f11", [1.00962, 0.6435]],
  ["icc", [0.96422, 0.82521]]
]);
function setLabWhitePoint(name) {
  const ill = ILLUMINANTS.get(String(name).toLowerCase());
  if (!ill) {
    throw new Error("unknown Lab illuminant " + name);
  }
  labConstants.labWhitePoint = name;
  labConstants.Xn = ill[0];
  labConstants.Zn = ill[1];
}
function getLabWhitePoint() {
  return labConstants.labWhitePoint;
}

// node_modules/chroma-js/src/io/lab/lab2rgb.js
var lab2rgb = (...args) => {
  args = unpack_default(args, "lab");
  const [L, a2, b] = args;
  const [x3, y3, z] = lab2xyz(L, a2, b);
  const [r, g2, b_] = xyz2rgb(x3, y3, z);
  return [r, g2, b_, args.length > 3 ? args[3] : 1];
};
var lab2xyz = (L, a2, b) => {
  const { kE, kK, kKE, Xn, Yn, Zn } = lab_constants_default;
  const fy = (L + 16) / 116;
  const fx = 2e-3 * a2 + fy;
  const fz = fy - 5e-3 * b;
  const fx3 = fx * fx * fx;
  const fz3 = fz * fz * fz;
  const xr = fx3 > kE ? fx3 : (116 * fx - 16) / kK;
  const yr = L > kKE ? Math.pow((L + 16) / 116, 3) : L / kK;
  const zr = fz3 > kE ? fz3 : (116 * fz - 16) / kK;
  const x3 = xr * Xn;
  const y3 = yr * Yn;
  const z = zr * Zn;
  return [x3, y3, z];
};
var compand = (linear3) => {
  const sign = Math.sign(linear3);
  linear3 = Math.abs(linear3);
  return (linear3 <= 31308e-7 ? linear3 * 12.92 : 1.055 * Math.pow(linear3, 1 / 2.4) - 0.055) * sign;
};
var xyz2rgb = (x3, y3, z) => {
  const { MtxAdaptMa, MtxAdaptMaI, MtxXYZ2RGB, RefWhiteRGB, Xn, Yn, Zn } = lab_constants_default;
  const As = Xn * MtxAdaptMa.m00 + Yn * MtxAdaptMa.m10 + Zn * MtxAdaptMa.m20;
  const Bs = Xn * MtxAdaptMa.m01 + Yn * MtxAdaptMa.m11 + Zn * MtxAdaptMa.m21;
  const Cs = Xn * MtxAdaptMa.m02 + Yn * MtxAdaptMa.m12 + Zn * MtxAdaptMa.m22;
  const Ad = RefWhiteRGB.X * MtxAdaptMa.m00 + RefWhiteRGB.Y * MtxAdaptMa.m10 + RefWhiteRGB.Z * MtxAdaptMa.m20;
  const Bd = RefWhiteRGB.X * MtxAdaptMa.m01 + RefWhiteRGB.Y * MtxAdaptMa.m11 + RefWhiteRGB.Z * MtxAdaptMa.m21;
  const Cd = RefWhiteRGB.X * MtxAdaptMa.m02 + RefWhiteRGB.Y * MtxAdaptMa.m12 + RefWhiteRGB.Z * MtxAdaptMa.m22;
  const X1 = (x3 * MtxAdaptMa.m00 + y3 * MtxAdaptMa.m10 + z * MtxAdaptMa.m20) * (Ad / As);
  const Y1 = (x3 * MtxAdaptMa.m01 + y3 * MtxAdaptMa.m11 + z * MtxAdaptMa.m21) * (Bd / Bs);
  const Z1 = (x3 * MtxAdaptMa.m02 + y3 * MtxAdaptMa.m12 + z * MtxAdaptMa.m22) * (Cd / Cs);
  const X2 = X1 * MtxAdaptMaI.m00 + Y1 * MtxAdaptMaI.m10 + Z1 * MtxAdaptMaI.m20;
  const Y2 = X1 * MtxAdaptMaI.m01 + Y1 * MtxAdaptMaI.m11 + Z1 * MtxAdaptMaI.m21;
  const Z2 = X1 * MtxAdaptMaI.m02 + Y1 * MtxAdaptMaI.m12 + Z1 * MtxAdaptMaI.m22;
  const r = compand(
    X2 * MtxXYZ2RGB.m00 + Y2 * MtxXYZ2RGB.m10 + Z2 * MtxXYZ2RGB.m20
  );
  const g2 = compand(
    X2 * MtxXYZ2RGB.m01 + Y2 * MtxXYZ2RGB.m11 + Z2 * MtxXYZ2RGB.m21
  );
  const b = compand(
    X2 * MtxXYZ2RGB.m02 + Y2 * MtxXYZ2RGB.m12 + Z2 * MtxXYZ2RGB.m22
  );
  return [r * 255, g2 * 255, b * 255];
};
var lab2rgb_default = lab2rgb;

// node_modules/chroma-js/src/io/lab/rgb2lab.js
var rgb2lab = (...args) => {
  const [r, g2, b, ...rest] = unpack_default(args, "rgb");
  const [x3, y3, z] = rgb2xyz(r, g2, b);
  const [L, a2, b_] = xyz2lab(x3, y3, z);
  return [L, a2, b_, ...rest.length > 0 && rest[0] < 1 ? [rest[0]] : []];
};
function xyz2lab(x3, y3, z) {
  const { Xn, Yn, Zn, kE, kK } = lab_constants_default;
  const xr = x3 / Xn;
  const yr = y3 / Yn;
  const zr = z / Zn;
  const fx = xr > kE ? Math.pow(xr, 1 / 3) : (kK * xr + 16) / 116;
  const fy = yr > kE ? Math.pow(yr, 1 / 3) : (kK * yr + 16) / 116;
  const fz = zr > kE ? Math.pow(zr, 1 / 3) : (kK * zr + 16) / 116;
  return [116 * fy - 16, 500 * (fx - fy), 200 * (fy - fz)];
}
function gammaAdjustSRGB(companded) {
  const sign = Math.sign(companded);
  companded = Math.abs(companded);
  const linear3 = companded <= 0.04045 ? companded / 12.92 : Math.pow((companded + 0.055) / 1.055, 2.4);
  return linear3 * sign;
}
var rgb2xyz = (r, g2, b) => {
  r = gammaAdjustSRGB(r / 255);
  g2 = gammaAdjustSRGB(g2 / 255);
  b = gammaAdjustSRGB(b / 255);
  const { MtxRGB2XYZ, MtxAdaptMa, MtxAdaptMaI, Xn, Yn, Zn, As, Bs, Cs } = lab_constants_default;
  let x3 = r * MtxRGB2XYZ.m00 + g2 * MtxRGB2XYZ.m10 + b * MtxRGB2XYZ.m20;
  let y3 = r * MtxRGB2XYZ.m01 + g2 * MtxRGB2XYZ.m11 + b * MtxRGB2XYZ.m21;
  let z = r * MtxRGB2XYZ.m02 + g2 * MtxRGB2XYZ.m12 + b * MtxRGB2XYZ.m22;
  const Ad = Xn * MtxAdaptMa.m00 + Yn * MtxAdaptMa.m10 + Zn * MtxAdaptMa.m20;
  const Bd = Xn * MtxAdaptMa.m01 + Yn * MtxAdaptMa.m11 + Zn * MtxAdaptMa.m21;
  const Cd = Xn * MtxAdaptMa.m02 + Yn * MtxAdaptMa.m12 + Zn * MtxAdaptMa.m22;
  let X2 = x3 * MtxAdaptMa.m00 + y3 * MtxAdaptMa.m10 + z * MtxAdaptMa.m20;
  let Y2 = x3 * MtxAdaptMa.m01 + y3 * MtxAdaptMa.m11 + z * MtxAdaptMa.m21;
  let Z = x3 * MtxAdaptMa.m02 + y3 * MtxAdaptMa.m12 + z * MtxAdaptMa.m22;
  X2 *= Ad / As;
  Y2 *= Bd / Bs;
  Z *= Cd / Cs;
  x3 = X2 * MtxAdaptMaI.m00 + Y2 * MtxAdaptMaI.m10 + Z * MtxAdaptMaI.m20;
  y3 = X2 * MtxAdaptMaI.m01 + Y2 * MtxAdaptMaI.m11 + Z * MtxAdaptMaI.m21;
  z = X2 * MtxAdaptMaI.m02 + Y2 * MtxAdaptMaI.m12 + Z * MtxAdaptMaI.m22;
  return [x3, y3, z];
};
var rgb2lab_default = rgb2lab;

// node_modules/chroma-js/src/io/lab/index.js
Color_default.prototype.lab = function() {
  return rgb2lab_default(this._rgb);
};
var lab = (...args) => new Color_default(...args, "lab");
Object.assign(chroma_default, { lab, getLabWhitePoint, setLabWhitePoint });
input_default.format.lab = lab2rgb_default;
input_default.autodetect.push({
  p: 2,
  test: (...args) => {
    args = unpack_default(args, "lab");
    if (type_default(args) === "array" && args.length === 3) {
      return "lab";
    }
  }
});

// node_modules/chroma-js/src/ops/darken.js
Color_default.prototype.darken = function(amount = 1) {
  const me = this;
  const lab3 = me.lab();
  lab3[0] -= lab_constants_default.Kn * amount;
  return new Color_default(lab3, "lab").alpha(me.alpha(), true);
};
Color_default.prototype.brighten = function(amount = 1) {
  return this.darken(-amount);
};
Color_default.prototype.darker = Color_default.prototype.darken;
Color_default.prototype.brighter = Color_default.prototype.brighten;

// node_modules/chroma-js/src/ops/get.js
Color_default.prototype.get = function(mc) {
  const [mode, channel] = mc.split(".");
  const src = this[mode]();
  if (channel) {
    const i = mode.indexOf(channel) - (mode.substr(0, 2) === "ok" ? 2 : 0);
    if (i > -1) return src[i];
    throw new Error(`unknown channel ${channel} in mode ${mode}`);
  } else {
    return src;
  }
};

// node_modules/chroma-js/src/ops/luminance.js
var { pow } = Math;
var EPS = 1e-7;
var MAX_ITER = 20;
Color_default.prototype.luminance = function(lum2, mode = "rgb") {
  if (lum2 !== void 0 && type_default(lum2) === "number") {
    if (lum2 === 0) {
      return new Color_default([0, 0, 0, this._rgb[3]], "rgb");
    }
    if (lum2 === 1) {
      return new Color_default([255, 255, 255, this._rgb[3]], "rgb");
    }
    let cur_lum = this.luminance();
    let max_iter = MAX_ITER;
    const test = (low, high) => {
      const mid = low.interpolate(high, 0.5, mode);
      const lm = mid.luminance();
      if (Math.abs(lum2 - lm) < EPS || !max_iter--) {
        return mid;
      }
      return lm > lum2 ? test(low, mid) : test(mid, high);
    };
    const rgb4 = (cur_lum > lum2 ? test(new Color_default([0, 0, 0]), this) : test(this, new Color_default([255, 255, 255]))).rgb();
    return new Color_default([...rgb4, this._rgb[3]]);
  }
  return rgb2luminance(...this._rgb.slice(0, 3));
};
var rgb2luminance = (r, g2, b) => {
  r = luminance_x(r);
  g2 = luminance_x(g2);
  b = luminance_x(b);
  return 0.2126 * r + 0.7152 * g2 + 0.0722 * b;
};
var luminance_x = (x3) => {
  x3 /= 255;
  return x3 <= 0.03928 ? x3 / 12.92 : pow((x3 + 0.055) / 1.055, 2.4);
};

// node_modules/chroma-js/src/interpolator/index.js
var interpolator_default = {};

// node_modules/chroma-js/src/generator/mix.js
var mix_default = (col1, col2, f = 0.5, ...rest) => {
  let mode = rest[0] || "lrgb";
  if (!interpolator_default[mode] && !rest.length) {
    mode = Object.keys(interpolator_default)[0];
  }
  if (!interpolator_default[mode]) {
    throw new Error(`interpolation mode ${mode} is not defined`);
  }
  if (type_default(col1) !== "object") col1 = new Color_default(col1);
  if (type_default(col2) !== "object") col2 = new Color_default(col2);
  return interpolator_default[mode](col1, col2, f).alpha(
    col1.alpha() + f * (col2.alpha() - col1.alpha())
  );
};

// node_modules/chroma-js/src/ops/mix.js
Color_default.prototype.mix = Color_default.prototype.interpolate = function(col2, f = 0.5, ...rest) {
  return mix_default(this, col2, f, ...rest);
};

// node_modules/chroma-js/src/ops/premultiply.js
Color_default.prototype.premultiply = function(mutate = false) {
  const rgb4 = this._rgb;
  const a2 = rgb4[3];
  if (mutate) {
    this._rgb = [rgb4[0] * a2, rgb4[1] * a2, rgb4[2] * a2, a2];
    return this;
  } else {
    return new Color_default([rgb4[0] * a2, rgb4[1] * a2, rgb4[2] * a2, a2], "rgb");
  }
};

// node_modules/chroma-js/src/io/lch/lch2lab.js
var { sin: sin2, cos: cos2 } = Math;
var lch2lab = (...args) => {
  let [l, c4, h] = unpack_default(args, "lch");
  if (isNaN(h)) h = 0;
  h = h * DEG2RAD;
  return [l, cos2(h) * c4, sin2(h) * c4];
};
var lch2lab_default = lch2lab;

// node_modules/chroma-js/src/io/lch/lch2rgb.js
var lch2rgb = (...args) => {
  args = unpack_default(args, "lch");
  const [l, c4, h] = args;
  const [L, a2, b_] = lch2lab_default(l, c4, h);
  const [r, g2, b] = lab2rgb_default(L, a2, b_);
  return [r, g2, b, args.length > 3 ? args[3] : 1];
};
var lch2rgb_default = lch2rgb;

// node_modules/chroma-js/src/io/lch/hcl2rgb.js
var hcl2rgb = (...args) => {
  const hcl2 = reverse3(unpack_default(args, "hcl"));
  return lch2rgb_default(...hcl2);
};
var hcl2rgb_default = hcl2rgb;

// node_modules/chroma-js/src/io/lch/lab2lch.js
var { sqrt: sqrt2, atan2: atan22, round: round2 } = Math;
var lab2lch = (...args) => {
  const [l, a2, b] = unpack_default(args, "lab");
  const c4 = sqrt2(a2 * a2 + b * b);
  let h = (atan22(b, a2) * RAD2DEG + 360) % 360;
  if (round2(c4 * 1e4) === 0) h = Number.NaN;
  return [l, c4, h];
};
var lab2lch_default = lab2lch;

// node_modules/chroma-js/src/io/lch/rgb2lch.js
var rgb2lch = (...args) => {
  const [r, g2, b, ...rest] = unpack_default(args, "rgb");
  const [l, a2, b_] = rgb2lab_default(r, g2, b);
  const [L, c4, h] = lab2lch_default(l, a2, b_);
  return [L, c4, h, ...rest.length > 0 && rest[0] < 1 ? [rest[0]] : []];
};
var rgb2lch_default = rgb2lch;

// node_modules/chroma-js/src/io/lch/index.js
Color_default.prototype.lch = function() {
  return rgb2lch_default(this._rgb);
};
Color_default.prototype.hcl = function() {
  return reverse3(rgb2lch_default(this._rgb));
};
var lch = (...args) => new Color_default(...args, "lch");
var hcl = (...args) => new Color_default(...args, "hcl");
Object.assign(chroma_default, { lch, hcl });
input_default.format.lch = lch2rgb_default;
input_default.format.hcl = hcl2rgb_default;
["lch", "hcl"].forEach(
  (m2) => input_default.autodetect.push({
    p: 2,
    test: (...args) => {
      args = unpack_default(args, m2);
      if (type_default(args) === "array" && args.length === 3) {
        return m2;
      }
    }
  })
);

// node_modules/chroma-js/src/ops/saturate.js
Color_default.prototype.saturate = function(amount = 1) {
  const me = this;
  const lch3 = me.lch();
  lch3[1] += lab_constants_default.Kn * amount;
  if (lch3[1] < 0) lch3[1] = 0;
  return new Color_default(lch3, "lch").alpha(me.alpha(), true);
};
Color_default.prototype.desaturate = function(amount = 1) {
  return this.saturate(-amount);
};

// node_modules/chroma-js/src/ops/set.js
Color_default.prototype.set = function(mc, value, mutate = false) {
  const [mode, channel] = mc.split(".");
  const src = this[mode]();
  if (channel) {
    const i = mode.indexOf(channel) - (mode.substr(0, 2) === "ok" ? 2 : 0);
    if (i > -1) {
      if (type_default(value) == "string") {
        switch (value.charAt(0)) {
          case "+":
            src[i] += +value;
            break;
          case "-":
            src[i] += +value;
            break;
          case "*":
            src[i] *= +value.substr(1);
            break;
          case "/":
            src[i] /= +value.substr(1);
            break;
          default:
            src[i] = +value;
        }
      } else if (type_default(value) === "number") {
        src[i] = value;
      } else {
        throw new Error(`unsupported value for Color.set`);
      }
      const out = new Color_default(src, mode);
      if (mutate) {
        this._rgb = out._rgb;
        return this;
      }
      return out;
    }
    throw new Error(`unknown channel ${channel} in mode ${mode}`);
  } else {
    return src;
  }
};

// node_modules/chroma-js/src/ops/shade.js
Color_default.prototype.tint = function(f = 0.5, ...rest) {
  return mix_default(this, "white", f, ...rest);
};
Color_default.prototype.shade = function(f = 0.5, ...rest) {
  return mix_default(this, "black", f, ...rest);
};

// node_modules/chroma-js/src/interpolator/rgb.js
var rgb2 = (col1, col2, f) => {
  const xyz0 = col1._rgb;
  const xyz1 = col2._rgb;
  return new Color_default(
    xyz0[0] + f * (xyz1[0] - xyz0[0]),
    xyz0[1] + f * (xyz1[1] - xyz0[1]),
    xyz0[2] + f * (xyz1[2] - xyz0[2]),
    "rgb"
  );
};
interpolator_default.rgb = rgb2;

// node_modules/chroma-js/src/interpolator/lrgb.js
var { sqrt: sqrt3, pow: pow2 } = Math;
var lrgb = (col1, col2, f) => {
  const [x1, y1, z1] = col1._rgb;
  const [x22, y22, z2] = col2._rgb;
  return new Color_default(
    sqrt3(pow2(x1, 2) * (1 - f) + pow2(x22, 2) * f),
    sqrt3(pow2(y1, 2) * (1 - f) + pow2(y22, 2) * f),
    sqrt3(pow2(z1, 2) * (1 - f) + pow2(z2, 2) * f),
    "rgb"
  );
};
interpolator_default.lrgb = lrgb;

// node_modules/chroma-js/src/interpolator/lab.js
var lab2 = (col1, col2, f) => {
  const xyz0 = col1.lab();
  const xyz1 = col2.lab();
  return new Color_default(
    xyz0[0] + f * (xyz1[0] - xyz0[0]),
    xyz0[1] + f * (xyz1[1] - xyz0[1]),
    xyz0[2] + f * (xyz1[2] - xyz0[2]),
    "lab"
  );
};
interpolator_default.lab = lab2;

// node_modules/chroma-js/src/interpolator/_hsx.js
var hsx_default = (col1, col2, f, m2) => {
  let xyz0, xyz1;
  if (m2 === "hsl") {
    xyz0 = col1.hsl();
    xyz1 = col2.hsl();
  } else if (m2 === "hsv") {
    xyz0 = col1.hsv();
    xyz1 = col2.hsv();
  } else if (m2 === "hcg") {
    xyz0 = col1.hcg();
    xyz1 = col2.hcg();
  } else if (m2 === "hsi") {
    xyz0 = col1.hsi();
    xyz1 = col2.hsi();
  } else if (m2 === "lch" || m2 === "hcl") {
    m2 = "hcl";
    xyz0 = col1.hcl();
    xyz1 = col2.hcl();
  } else if (m2 === "oklch") {
    xyz0 = col1.oklch().reverse();
    xyz1 = col2.oklch().reverse();
  }
  let hue0, hue1, sat0, sat1, lbv0, lbv1;
  if (m2.substr(0, 1) === "h" || m2 === "oklch") {
    [hue0, sat0, lbv0] = xyz0;
    [hue1, sat1, lbv1] = xyz1;
  }
  let sat, hue2, lbv, dh;
  if (!isNaN(hue0) && !isNaN(hue1)) {
    if (hue1 > hue0 && hue1 - hue0 > 180) {
      dh = hue1 - (hue0 + 360);
    } else if (hue1 < hue0 && hue0 - hue1 > 180) {
      dh = hue1 + 360 - hue0;
    } else {
      dh = hue1 - hue0;
    }
    hue2 = hue0 + f * dh;
  } else if (!isNaN(hue0)) {
    hue2 = hue0;
    if ((lbv1 == 1 || lbv1 == 0) && m2 != "hsv") sat = sat0;
  } else if (!isNaN(hue1)) {
    hue2 = hue1;
    if ((lbv0 == 1 || lbv0 == 0) && m2 != "hsv") sat = sat1;
  } else {
    hue2 = Number.NaN;
  }
  if (sat === void 0) sat = sat0 + f * (sat1 - sat0);
  lbv = lbv0 + f * (lbv1 - lbv0);
  return m2 === "oklch" ? new Color_default([lbv, sat, hue2], m2) : new Color_default([hue2, sat, lbv], m2);
};

// node_modules/chroma-js/src/interpolator/lch.js
var lch2 = (col1, col2, f) => {
  return hsx_default(col1, col2, f, "lch");
};
interpolator_default.lch = lch2;
interpolator_default.hcl = lch2;

// node_modules/chroma-js/src/io/num/num2rgb.js
var num2rgb = (num3) => {
  if (type_default(num3) == "number" && num3 >= 0 && num3 <= 16777215) {
    const r = num3 >> 16;
    const g2 = num3 >> 8 & 255;
    const b = num3 & 255;
    return [r, g2, b, 1];
  }
  throw new Error("unknown num color: " + num3);
};
var num2rgb_default = num2rgb;

// node_modules/chroma-js/src/io/num/rgb2num.js
var rgb2num = (...args) => {
  const [r, g2, b] = unpack_default(args, "rgb");
  return (r << 16) + (g2 << 8) + b;
};
var rgb2num_default = rgb2num;

// node_modules/chroma-js/src/io/num/index.js
Color_default.prototype.num = function() {
  return rgb2num_default(this._rgb);
};
var num = (...args) => new Color_default(...args, "num");
Object.assign(chroma_default, { num });
input_default.format.num = num2rgb_default;
input_default.autodetect.push({
  p: 5,
  test: (...args) => {
    if (args.length === 1 && type_default(args[0]) === "number" && args[0] >= 0 && args[0] <= 16777215) {
      return "num";
    }
  }
});

// node_modules/chroma-js/src/interpolator/num.js
var num2 = (col1, col2, f) => {
  const c1 = col1.num();
  const c22 = col2.num();
  return new Color_default(c1 + f * (c22 - c1), "num");
};
interpolator_default.num = num2;

// node_modules/chroma-js/src/io/hcg/hcg2rgb.js
var { floor } = Math;
var hcg2rgb = (...args) => {
  args = unpack_default(args, "hcg");
  let [h, c4, _g] = args;
  let r, g2, b;
  _g = _g * 255;
  const _c = c4 * 255;
  if (c4 === 0) {
    r = g2 = b = _g;
  } else {
    if (h === 360) h = 0;
    if (h > 360) h -= 360;
    if (h < 0) h += 360;
    h /= 60;
    const i = floor(h);
    const f = h - i;
    const p = _g * (1 - c4);
    const q = p + _c * (1 - f);
    const t2 = p + _c * f;
    const v = p + _c;
    switch (i) {
      case 0:
        [r, g2, b] = [v, t2, p];
        break;
      case 1:
        [r, g2, b] = [q, v, p];
        break;
      case 2:
        [r, g2, b] = [p, v, t2];
        break;
      case 3:
        [r, g2, b] = [p, q, v];
        break;
      case 4:
        [r, g2, b] = [t2, p, v];
        break;
      case 5:
        [r, g2, b] = [v, p, q];
        break;
    }
  }
  return [r, g2, b, args.length > 3 ? args[3] : 1];
};
var hcg2rgb_default = hcg2rgb;

// node_modules/chroma-js/src/io/hcg/rgb2hcg.js
var rgb2hcg = (...args) => {
  const [r, g2, b] = unpack_default(args, "rgb");
  const minRgb = min4(r, g2, b);
  const maxRgb = max4(r, g2, b);
  const delta = maxRgb - minRgb;
  const c4 = delta * 100 / 255;
  const _g = minRgb / (255 - delta) * 100;
  let h;
  if (delta === 0) {
    h = Number.NaN;
  } else {
    if (r === maxRgb) h = (g2 - b) / delta;
    if (g2 === maxRgb) h = 2 + (b - r) / delta;
    if (b === maxRgb) h = 4 + (r - g2) / delta;
    h *= 60;
    if (h < 0) h += 360;
  }
  return [h, c4, _g];
};
var rgb2hcg_default = rgb2hcg;

// node_modules/chroma-js/src/io/hcg/index.js
Color_default.prototype.hcg = function() {
  return rgb2hcg_default(this._rgb);
};
var hcg = (...args) => new Color_default(...args, "hcg");
chroma_default.hcg = hcg;
input_default.format.hcg = hcg2rgb_default;
input_default.autodetect.push({
  p: 1,
  test: (...args) => {
    args = unpack_default(args, "hcg");
    if (type_default(args) === "array" && args.length === 3) {
      return "hcg";
    }
  }
});

// node_modules/chroma-js/src/interpolator/hcg.js
var hcg2 = (col1, col2, f) => {
  return hsx_default(col1, col2, f, "hcg");
};
interpolator_default.hcg = hcg2;

// node_modules/chroma-js/src/io/hsi/hsi2rgb.js
var { cos: cos3 } = Math;
var hsi2rgb = (...args) => {
  args = unpack_default(args, "hsi");
  let [h, s, i] = args;
  let r, g2, b;
  if (isNaN(h)) h = 0;
  if (isNaN(s)) s = 0;
  if (h > 360) h -= 360;
  if (h < 0) h += 360;
  h /= 360;
  if (h < 1 / 3) {
    b = (1 - s) / 3;
    r = (1 + s * cos3(TWOPI * h) / cos3(PITHIRD - TWOPI * h)) / 3;
    g2 = 1 - (b + r);
  } else if (h < 2 / 3) {
    h -= 1 / 3;
    r = (1 - s) / 3;
    g2 = (1 + s * cos3(TWOPI * h) / cos3(PITHIRD - TWOPI * h)) / 3;
    b = 1 - (r + g2);
  } else {
    h -= 2 / 3;
    g2 = (1 - s) / 3;
    b = (1 + s * cos3(TWOPI * h) / cos3(PITHIRD - TWOPI * h)) / 3;
    r = 1 - (g2 + b);
  }
  r = limit_default(i * r * 3);
  g2 = limit_default(i * g2 * 3);
  b = limit_default(i * b * 3);
  return [r * 255, g2 * 255, b * 255, args.length > 3 ? args[3] : 1];
};
var hsi2rgb_default = hsi2rgb;

// node_modules/chroma-js/src/io/hsi/rgb2hsi.js
var { min: min5, sqrt: sqrt4, acos: acos2 } = Math;
var rgb2hsi = (...args) => {
  let [r, g2, b] = unpack_default(args, "rgb");
  r /= 255;
  g2 /= 255;
  b /= 255;
  let h;
  const min_ = min5(r, g2, b);
  const i = (r + g2 + b) / 3;
  const s = i > 0 ? 1 - min_ / i : 0;
  if (s === 0) {
    h = NaN;
  } else {
    h = (r - g2 + (r - b)) / 2;
    h /= sqrt4((r - g2) * (r - g2) + (r - b) * (g2 - b));
    h = acos2(h);
    if (b > g2) {
      h = TWOPI - h;
    }
    h /= TWOPI;
  }
  return [h * 360, s, i];
};
var rgb2hsi_default = rgb2hsi;

// node_modules/chroma-js/src/io/hsi/index.js
Color_default.prototype.hsi = function() {
  return rgb2hsi_default(this._rgb);
};
var hsi = (...args) => new Color_default(...args, "hsi");
chroma_default.hsi = hsi;
input_default.format.hsi = hsi2rgb_default;
input_default.autodetect.push({
  p: 2,
  test: (...args) => {
    args = unpack_default(args, "hsi");
    if (type_default(args) === "array" && args.length === 3) {
      return "hsi";
    }
  }
});

// node_modules/chroma-js/src/interpolator/hsi.js
var hsi2 = (col1, col2, f) => {
  return hsx_default(col1, col2, f, "hsi");
};
interpolator_default.hsi = hsi2;

// node_modules/chroma-js/src/io/hsl/hsl2rgb.js
var hsl2rgb2 = (...args) => {
  args = unpack_default(args, "hsl");
  const [h, s, l] = args;
  let r, g2, b;
  if (s === 0) {
    r = g2 = b = l * 255;
  } else {
    const t3 = [0, 0, 0];
    const c4 = [0, 0, 0];
    const t2 = l < 0.5 ? l * (1 + s) : l + s - l * s;
    const t1 = 2 * l - t2;
    const h_ = h / 360;
    t3[0] = h_ + 1 / 3;
    t3[1] = h_;
    t3[2] = h_ - 1 / 3;
    for (let i = 0; i < 3; i++) {
      if (t3[i] < 0) t3[i] += 1;
      if (t3[i] > 1) t3[i] -= 1;
      if (6 * t3[i] < 1) c4[i] = t1 + (t2 - t1) * 6 * t3[i];
      else if (2 * t3[i] < 1) c4[i] = t2;
      else if (3 * t3[i] < 2) c4[i] = t1 + (t2 - t1) * (2 / 3 - t3[i]) * 6;
      else c4[i] = t1;
    }
    [r, g2, b] = [c4[0] * 255, c4[1] * 255, c4[2] * 255];
  }
  if (args.length > 3) {
    return [r, g2, b, args[3]];
  }
  return [r, g2, b, 1];
};
var hsl2rgb_default = hsl2rgb2;

// node_modules/chroma-js/src/io/hsl/rgb2hsl.js
var rgb2hsl = (...args) => {
  args = unpack_default(args, "rgba");
  let [r, g2, b] = args;
  r /= 255;
  g2 /= 255;
  b /= 255;
  const minRgb = min4(r, g2, b);
  const maxRgb = max4(r, g2, b);
  const l = (maxRgb + minRgb) / 2;
  let s, h;
  if (maxRgb === minRgb) {
    s = 0;
    h = Number.NaN;
  } else {
    s = l < 0.5 ? (maxRgb - minRgb) / (maxRgb + minRgb) : (maxRgb - minRgb) / (2 - maxRgb - minRgb);
  }
  if (r == maxRgb) h = (g2 - b) / (maxRgb - minRgb);
  else if (g2 == maxRgb) h = 2 + (b - r) / (maxRgb - minRgb);
  else if (b == maxRgb) h = 4 + (r - g2) / (maxRgb - minRgb);
  h *= 60;
  if (h < 0) h += 360;
  if (args.length > 3 && args[3] !== void 0) return [h, s, l, args[3]];
  return [h, s, l];
};
var rgb2hsl_default = rgb2hsl;

// node_modules/chroma-js/src/io/hsl/index.js
Color_default.prototype.hsl = function() {
  return rgb2hsl_default(this._rgb);
};
var hsl2 = (...args) => new Color_default(...args, "hsl");
chroma_default.hsl = hsl2;
input_default.format.hsl = hsl2rgb_default;
input_default.autodetect.push({
  p: 2,
  test: (...args) => {
    args = unpack_default(args, "hsl");
    if (type_default(args) === "array" && args.length === 3) {
      return "hsl";
    }
  }
});

// node_modules/chroma-js/src/interpolator/hsl.js
var hsl3 = (col1, col2, f) => {
  return hsx_default(col1, col2, f, "hsl");
};
interpolator_default.hsl = hsl3;

// node_modules/chroma-js/src/io/hsv/hsv2rgb.js
var { floor: floor2 } = Math;
var hsv2rgb = (...args) => {
  args = unpack_default(args, "hsv");
  let [h, s, v] = args;
  let r, g2, b;
  v *= 255;
  if (s === 0) {
    r = g2 = b = v;
  } else {
    if (h === 360) h = 0;
    if (h > 360) h -= 360;
    if (h < 0) h += 360;
    h /= 60;
    const i = floor2(h);
    const f = h - i;
    const p = v * (1 - s);
    const q = v * (1 - s * f);
    const t2 = v * (1 - s * (1 - f));
    switch (i) {
      case 0:
        [r, g2, b] = [v, t2, p];
        break;
      case 1:
        [r, g2, b] = [q, v, p];
        break;
      case 2:
        [r, g2, b] = [p, v, t2];
        break;
      case 3:
        [r, g2, b] = [p, q, v];
        break;
      case 4:
        [r, g2, b] = [t2, p, v];
        break;
      case 5:
        [r, g2, b] = [v, p, q];
        break;
    }
  }
  return [r, g2, b, args.length > 3 ? args[3] : 1];
};
var hsv2rgb_default = hsv2rgb;

// node_modules/chroma-js/src/io/hsv/rgb2hsv.js
var { min: min6, max: max5 } = Math;
var rgb2hsl2 = (...args) => {
  args = unpack_default(args, "rgb");
  let [r, g2, b] = args;
  const min_ = min6(r, g2, b);
  const max_ = max5(r, g2, b);
  const delta = max_ - min_;
  let h, s, v;
  v = max_ / 255;
  if (max_ === 0) {
    h = Number.NaN;
    s = 0;
  } else {
    s = delta / max_;
    if (r === max_) h = (g2 - b) / delta;
    if (g2 === max_) h = 2 + (b - r) / delta;
    if (b === max_) h = 4 + (r - g2) / delta;
    h *= 60;
    if (h < 0) h += 360;
  }
  return [h, s, v];
};
var rgb2hsv_default = rgb2hsl2;

// node_modules/chroma-js/src/io/hsv/index.js
Color_default.prototype.hsv = function() {
  return rgb2hsv_default(this._rgb);
};
var hsv = (...args) => new Color_default(...args, "hsv");
chroma_default.hsv = hsv;
input_default.format.hsv = hsv2rgb_default;
input_default.autodetect.push({
  p: 2,
  test: (...args) => {
    args = unpack_default(args, "hsv");
    if (type_default(args) === "array" && args.length === 3) {
      return "hsv";
    }
  }
});

// node_modules/chroma-js/src/interpolator/hsv.js
var hsv2 = (col1, col2, f) => {
  return hsx_default(col1, col2, f, "hsv");
};
interpolator_default.hsv = hsv2;

// node_modules/chroma-js/src/utils/multiply-matrices.js
function multiplyMatrices(A2, B2) {
  let m2 = A2.length;
  if (!Array.isArray(A2[0])) {
    A2 = [A2];
  }
  if (!Array.isArray(B2[0])) {
    B2 = B2.map((x3) => [x3]);
  }
  let p = B2[0].length;
  let B_cols = B2[0].map((_, i) => B2.map((x3) => x3[i]));
  let product = A2.map(
    (row) => B_cols.map((col) => {
      if (!Array.isArray(row)) {
        return col.reduce((a2, c4) => a2 + c4 * row, 0);
      }
      return row.reduce((a2, c4, i) => a2 + c4 * (col[i] || 0), 0);
    })
  );
  if (m2 === 1) {
    product = product[0];
  }
  if (p === 1) {
    return product.map((x3) => x3[0]);
  }
  return product;
}

// node_modules/chroma-js/src/io/oklab/oklab2rgb.js
var oklab2rgb = (...args) => {
  args = unpack_default(args, "lab");
  const [L, a2, b, ...rest] = args;
  const [X2, Y2, Z] = OKLab_to_XYZ([L, a2, b]);
  const [r, g2, b_] = xyz2rgb(X2, Y2, Z);
  return [r, g2, b_, ...rest.length > 0 && rest[0] < 1 ? [rest[0]] : []];
};
function OKLab_to_XYZ(OKLab) {
  var LMStoXYZ = [
    [1.2268798758459243, -0.5578149944602171, 0.2813910456659647],
    [-0.0405757452148008, 1.112286803280317, -0.0717110580655164],
    [-0.0763729366746601, -0.4214933324022432, 1.5869240198367816]
  ];
  var OKLabtoLMS = [
    [1, 0.3963377773761749, 0.2158037573099136],
    [1, -0.1055613458156586, -0.0638541728258133],
    [1, -0.0894841775298119, -1.2914855480194092]
  ];
  var LMSnl = multiplyMatrices(OKLabtoLMS, OKLab);
  return multiplyMatrices(
    LMStoXYZ,
    LMSnl.map((c4) => c4 ** 3)
  );
}
var oklab2rgb_default = oklab2rgb;

// node_modules/chroma-js/src/io/oklab/rgb2oklab.js
var rgb2oklab = (...args) => {
  const [r, g2, b, ...rest] = unpack_default(args, "rgb");
  const xyz = rgb2xyz(r, g2, b);
  const oklab3 = XYZ_to_OKLab(xyz);
  return [...oklab3, ...rest.length > 0 && rest[0] < 1 ? [rest[0]] : []];
};
function XYZ_to_OKLab(XYZ) {
  const XYZtoLMS = [
    [0.819022437996703, 0.3619062600528904, -0.1288737815209879],
    [0.0329836539323885, 0.9292868615863434, 0.0361446663506424],
    [0.0481771893596242, 0.2642395317527308, 0.6335478284694309]
  ];
  const LMStoOKLab = [
    [0.210454268309314, 0.7936177747023054, -0.0040720430116193],
    [1.9779985324311684, -2.42859224204858, 0.450593709617411],
    [0.0259040424655478, 0.7827717124575296, -0.8086757549230774]
  ];
  const LMS = multiplyMatrices(XYZtoLMS, XYZ);
  return multiplyMatrices(
    LMStoOKLab,
    LMS.map((c4) => Math.cbrt(c4))
  );
}
var rgb2oklab_default = rgb2oklab;

// node_modules/chroma-js/src/io/oklab/index.js
Color_default.prototype.oklab = function() {
  return rgb2oklab_default(this._rgb);
};
var oklab = (...args) => new Color_default(...args, "oklab");
Object.assign(chroma_default, { oklab });
input_default.format.oklab = oklab2rgb_default;
input_default.autodetect.push({
  p: 2,
  test: (...args) => {
    args = unpack_default(args, "oklab");
    if (type_default(args) === "array" && args.length === 3) {
      return "oklab";
    }
  }
});

// node_modules/chroma-js/src/interpolator/oklab.js
var oklab2 = (col1, col2, f) => {
  const xyz0 = col1.oklab();
  const xyz1 = col2.oklab();
  return new Color_default(
    xyz0[0] + f * (xyz1[0] - xyz0[0]),
    xyz0[1] + f * (xyz1[1] - xyz0[1]),
    xyz0[2] + f * (xyz1[2] - xyz0[2]),
    "oklab"
  );
};
interpolator_default.oklab = oklab2;

// node_modules/chroma-js/src/interpolator/oklch.js
var oklch = (col1, col2, f) => {
  return hsx_default(col1, col2, f, "oklch");
};
interpolator_default.oklch = oklch;

// node_modules/chroma-js/src/generator/average.js
var { pow: pow3, sqrt: sqrt5, PI: PI2, cos: cos4, sin: sin3, atan2: atan23 } = Math;
var average_default = (colors, mode = "lrgb", weights = null) => {
  const l = colors.length;
  if (!weights) weights = Array.from(new Array(l)).map(() => 1);
  const k = l / weights.reduce(function(a2, b) {
    return a2 + b;
  });
  weights.forEach((w, i) => {
    weights[i] *= k;
  });
  colors = colors.map((c4) => new Color_default(c4));
  if (mode === "lrgb") {
    return _average_lrgb(colors, weights);
  }
  const first = colors.shift();
  const xyz = first.get(mode);
  const cnt = [];
  let dx = 0;
  let dy = 0;
  for (let i = 0; i < xyz.length; i++) {
    xyz[i] = (xyz[i] || 0) * weights[0];
    cnt.push(isNaN(xyz[i]) ? 0 : weights[0]);
    if (mode.charAt(i) === "h" && !isNaN(xyz[i])) {
      const A2 = xyz[i] / 180 * PI2;
      dx += cos4(A2) * weights[0];
      dy += sin3(A2) * weights[0];
    }
  }
  let alpha = first.alpha() * weights[0];
  colors.forEach((c4, ci) => {
    const xyz2 = c4.get(mode);
    alpha += c4.alpha() * weights[ci + 1];
    for (let i = 0; i < xyz.length; i++) {
      if (!isNaN(xyz2[i])) {
        cnt[i] += weights[ci + 1];
        if (mode.charAt(i) === "h") {
          const A2 = xyz2[i] / 180 * PI2;
          dx += cos4(A2) * weights[ci + 1];
          dy += sin3(A2) * weights[ci + 1];
        } else {
          xyz[i] += xyz2[i] * weights[ci + 1];
        }
      }
    }
  });
  for (let i = 0; i < xyz.length; i++) {
    if (mode.charAt(i) === "h") {
      let A2 = atan23(dy / cnt[i], dx / cnt[i]) / PI2 * 180;
      while (A2 < 0) A2 += 360;
      while (A2 >= 360) A2 -= 360;
      xyz[i] = A2;
    } else {
      xyz[i] = xyz[i] / cnt[i];
    }
  }
  alpha /= l;
  return new Color_default(xyz, mode).alpha(alpha > 0.99999 ? 1 : alpha, true);
};
var _average_lrgb = (colors, weights) => {
  const l = colors.length;
  const xyz = [0, 0, 0, 0];
  for (let i = 0; i < colors.length; i++) {
    const col = colors[i];
    const f = weights[i] / l;
    const rgb4 = col._rgb;
    xyz[0] += pow3(rgb4[0], 2) * f;
    xyz[1] += pow3(rgb4[1], 2) * f;
    xyz[2] += pow3(rgb4[2], 2) * f;
    xyz[3] += rgb4[3] * f;
  }
  xyz[0] = sqrt5(xyz[0]);
  xyz[1] = sqrt5(xyz[1]);
  xyz[2] = sqrt5(xyz[2]);
  if (xyz[3] > 0.9999999) xyz[3] = 1;
  return new Color_default(clip_rgb_default(xyz));
};

// node_modules/chroma-js/src/generator/scale.js
var { pow: pow4 } = Math;
function scale_default(colors) {
  let _mode = "rgb";
  let _nacol = chroma_default("#ccc");
  let _spread = 0;
  let _positions = [0, 1];
  let _domain = [0, 1];
  let _pos = [];
  let _padding = [0, 0];
  let _classes = false;
  let _colors = [];
  let _out = false;
  let _min = 0;
  let _max = 1;
  let _correctLightness = false;
  let _colorCache = {};
  let _useCache = true;
  let _gamma = 1;
  const setColors = function(colors2) {
    colors2 = colors2 || ["#fff", "#000"];
    if (colors2 && type_default(colors2) === "string" && chroma_default.brewer && chroma_default.brewer[colors2.toLowerCase()]) {
      colors2 = chroma_default.brewer[colors2.toLowerCase()];
    }
    if (type_default(colors2) === "array") {
      if (colors2.length === 1) {
        colors2 = [colors2[0], colors2[0]];
      }
      colors2 = colors2.slice(0);
      for (let c4 = 0; c4 < colors2.length; c4++) {
        colors2[c4] = chroma_default(colors2[c4]);
      }
      _pos.length = 0;
      for (let c4 = 0; c4 < colors2.length; c4++) {
        _pos.push(c4 / (colors2.length - 1));
      }
    }
    resetCache();
    return _colors = colors2;
  };
  const getClass = function(value) {
    if (_classes != null) {
      const n = _classes.length - 1;
      let i = 0;
      while (i < n && value >= _classes[i]) {
        i++;
      }
      return i - 1;
    }
    return 0;
  };
  let tMapLightness = (t2) => t2;
  let tMapDomain = (t2) => t2;
  const getColor = function(val, bypassMap) {
    let col, t2;
    if (bypassMap == null) {
      bypassMap = false;
    }
    if (isNaN(val) || val === null) {
      return _nacol;
    }
    if (!bypassMap) {
      if (_classes && _classes.length > 2) {
        const c4 = getClass(val);
        t2 = c4 / (_classes.length - 2);
      } else if (_max !== _min) {
        t2 = (val - _min) / (_max - _min);
      } else {
        t2 = 1;
      }
    } else {
      t2 = val;
    }
    t2 = tMapDomain(t2);
    if (!bypassMap) {
      t2 = tMapLightness(t2);
    }
    if (_gamma !== 1) {
      t2 = pow4(t2, _gamma);
    }
    t2 = _padding[0] + t2 * (1 - _padding[0] - _padding[1]);
    t2 = limit_default(t2, 0, 1);
    const k = Math.floor(t2 * 1e4);
    if (_useCache && _colorCache[k]) {
      col = _colorCache[k];
    } else {
      if (type_default(_colors) === "array") {
        for (let i = 0; i < _pos.length; i++) {
          const p = _pos[i];
          if (t2 <= p) {
            col = _colors[i];
            break;
          }
          if (t2 >= p && i === _pos.length - 1) {
            col = _colors[i];
            break;
          }
          if (t2 > p && t2 < _pos[i + 1]) {
            t2 = (t2 - p) / (_pos[i + 1] - p);
            col = chroma_default.interpolate(
              _colors[i],
              _colors[i + 1],
              t2,
              _mode
            );
            break;
          }
        }
      } else if (type_default(_colors) === "function") {
        col = _colors(t2);
      }
      if (_useCache) {
        _colorCache[k] = col;
      }
    }
    return col;
  };
  var resetCache = () => _colorCache = {};
  setColors(colors);
  const f = function(v) {
    const c4 = chroma_default(getColor(v));
    if (_out && c4[_out]) {
      return c4[_out]();
    } else {
      return c4;
    }
  };
  f.classes = function(classes) {
    if (classes != null) {
      if (type_default(classes) === "array") {
        _classes = classes;
        _positions = [classes[0], classes[classes.length - 1]];
      } else {
        const d = chroma_default.analyze(_positions);
        if (classes === 0) {
          _classes = [d.min, d.max];
        } else {
          _classes = chroma_default.limits(d, "e", classes);
        }
      }
      return f;
    }
    return _classes;
  };
  f.domain = function(domain) {
    if (!arguments.length) {
      return _domain;
    }
    _domain = domain.slice(0);
    _min = domain[0];
    _max = domain[domain.length - 1];
    _pos = [];
    const k = _colors.length;
    if (domain.length === k && _min !== _max) {
      for (let d of Array.from(domain)) {
        _pos.push((d - _min) / (_max - _min));
      }
    } else {
      for (let c4 = 0; c4 < k; c4++) {
        _pos.push(c4 / (k - 1));
      }
      if (domain.length > 2) {
        const tOut = domain.map((d, i) => i / (domain.length - 1));
        const tBreaks = domain.map((d) => (d - _min) / (_max - _min));
        if (!tBreaks.every((val, i) => tOut[i] === val)) {
          tMapDomain = (t2) => {
            if (t2 <= 0 || t2 >= 1) return t2;
            let i = 0;
            while (t2 >= tBreaks[i + 1]) i++;
            const f2 = (t2 - tBreaks[i]) / (tBreaks[i + 1] - tBreaks[i]);
            const out = tOut[i] + f2 * (tOut[i + 1] - tOut[i]);
            return out;
          };
        }
      }
    }
    _positions = [_min, _max];
    return f;
  };
  f.mode = function(_m) {
    if (!arguments.length) {
      return _mode;
    }
    _mode = _m;
    resetCache();
    return f;
  };
  f.range = function(colors2, _pos2) {
    setColors(colors2, _pos2);
    return f;
  };
  f.out = function(_o) {
    _out = _o;
    return f;
  };
  f.spread = function(val) {
    if (!arguments.length) {
      return _spread;
    }
    _spread = val;
    return f;
  };
  f.correctLightness = function(v) {
    if (v == null) {
      v = true;
    }
    _correctLightness = v;
    resetCache();
    if (_correctLightness) {
      tMapLightness = function(t2) {
        const L0 = getColor(0, true).lab()[0];
        const L1 = getColor(1, true).lab()[0];
        const pol = L0 > L1;
        let L_actual = getColor(t2, true).lab()[0];
        const L_ideal = L0 + (L1 - L0) * t2;
        let L_diff = L_actual - L_ideal;
        let t0 = 0;
        let t1 = 1;
        let max_iter = 20;
        while (Math.abs(L_diff) > 0.01 && max_iter-- > 0) {
          (function() {
            if (pol) {
              L_diff *= -1;
            }
            if (L_diff < 0) {
              t0 = t2;
              t2 += (t1 - t2) * 0.5;
            } else {
              t1 = t2;
              t2 += (t0 - t2) * 0.5;
            }
            L_actual = getColor(t2, true).lab()[0];
            return L_diff = L_actual - L_ideal;
          })();
        }
        return t2;
      };
    } else {
      tMapLightness = (t2) => t2;
    }
    return f;
  };
  f.padding = function(p) {
    if (p != null) {
      if (type_default(p) === "number") {
        p = [p, p];
      }
      _padding = p;
      return f;
    } else {
      return _padding;
    }
  };
  f.colors = function(numColors, out) {
    if (arguments.length < 2) {
      out = "hex";
    }
    let result = [];
    if (arguments.length === 0) {
      result = _colors.slice(0);
    } else if (numColors === 1) {
      result = [f(0.5)];
    } else if (numColors > 1) {
      const dm = _positions[0];
      const dd = _positions[1] - dm;
      result = __range__(0, numColors, false).map(
        (i) => f(dm + i / (numColors - 1) * dd)
      );
    } else {
      colors = [];
      let samples = [];
      if (_classes && _classes.length > 2) {
        for (let i = 1, end = _classes.length, asc = 1 <= end; asc ? i < end : i > end; asc ? i++ : i--) {
          samples.push((_classes[i - 1] + _classes[i]) * 0.5);
        }
      } else {
        samples = _positions;
      }
      result = samples.map((v) => f(v));
    }
    if (chroma_default[out]) {
      result = result.map((c4) => c4[out]());
    }
    return result;
  };
  f.cache = function(c4) {
    if (c4 != null) {
      _useCache = c4;
      return f;
    } else {
      return _useCache;
    }
  };
  f.gamma = function(g2) {
    if (g2 != null) {
      _gamma = g2;
      return f;
    } else {
      return _gamma;
    }
  };
  f.nodata = function(d) {
    if (d != null) {
      _nacol = chroma_default(d);
      return f;
    } else {
      return _nacol;
    }
  };
  return f;
}
function __range__(left2, right2, inclusive) {
  let range2 = [];
  let ascending3 = left2 < right2;
  let end = !inclusive ? right2 : ascending3 ? right2 + 1 : right2 - 1;
  for (let i = left2; ascending3 ? i < end : i > end; ascending3 ? i++ : i--) {
    range2.push(i);
  }
  return range2;
}

// node_modules/chroma-js/src/generator/bezier.js
var binom_row = function(n) {
  let row = [1, 1];
  for (let i = 1; i < n; i++) {
    let newrow = [1];
    for (let j = 1; j <= row.length; j++) {
      newrow[j] = (row[j] || 0) + row[j - 1];
    }
    row = newrow;
  }
  return row;
};
var bezier = function(colors) {
  let I, lab0, lab1, lab22;
  colors = colors.map((c4) => new Color_default(c4));
  if (colors.length === 2) {
    [lab0, lab1] = colors.map((c4) => c4.lab());
    I = function(t2) {
      const lab3 = [0, 1, 2].map((i) => lab0[i] + t2 * (lab1[i] - lab0[i]));
      return new Color_default(lab3, "lab");
    };
  } else if (colors.length === 3) {
    [lab0, lab1, lab22] = colors.map((c4) => c4.lab());
    I = function(t2) {
      const lab3 = [0, 1, 2].map(
        (i) => (1 - t2) * (1 - t2) * lab0[i] + 2 * (1 - t2) * t2 * lab1[i] + t2 * t2 * lab22[i]
      );
      return new Color_default(lab3, "lab");
    };
  } else if (colors.length === 4) {
    let lab3;
    [lab0, lab1, lab22, lab3] = colors.map((c4) => c4.lab());
    I = function(t2) {
      const lab4 = [0, 1, 2].map(
        (i) => (1 - t2) * (1 - t2) * (1 - t2) * lab0[i] + 3 * (1 - t2) * (1 - t2) * t2 * lab1[i] + 3 * (1 - t2) * t2 * t2 * lab22[i] + t2 * t2 * t2 * lab3[i]
      );
      return new Color_default(lab4, "lab");
    };
  } else if (colors.length >= 5) {
    let labs, row, n;
    labs = colors.map((c4) => c4.lab());
    n = colors.length - 1;
    row = binom_row(n);
    I = function(t2) {
      const u = 1 - t2;
      const lab3 = [0, 1, 2].map(
        (i) => labs.reduce(
          (sum2, el, j) => sum2 + row[j] * u ** (n - j) * t2 ** j * el[i],
          0
        )
      );
      return new Color_default(lab3, "lab");
    };
  } else {
    throw new RangeError("No point in running bezier with only one color.");
  }
  return I;
};
var bezier_default = (colors) => {
  const f = bezier(colors);
  f.scale = () => scale_default(f);
  return f;
};

// node_modules/chroma-js/src/io/rgb/index.js
var { round: round3 } = Math;
Color_default.prototype.rgb = function(rnd = true) {
  if (rnd === false) return this._rgb.slice(0, 3);
  return this._rgb.slice(0, 3).map(round3);
};
Color_default.prototype.rgba = function(rnd = true) {
  return this._rgb.slice(0, 4).map((v, i) => {
    return i < 3 ? rnd === false ? v : round3(v) : v;
  });
};
var rgb3 = (...args) => new Color_default(...args, "rgb");
Object.assign(chroma_default, { rgb: rgb3 });
input_default.format.rgb = (...args) => {
  const rgba2 = unpack_default(args, "rgba");
  if (rgba2[3] === void 0) rgba2[3] = 1;
  return rgba2;
};
input_default.autodetect.push({
  p: 3,
  test: (...args) => {
    args = unpack_default(args, "rgba");
    if (type_default(args) === "array" && (args.length === 3 || args.length === 4 && type_default(args[3]) == "number" && args[3] >= 0 && args[3] <= 1)) {
      return "rgb";
    }
  }
});

// node_modules/chroma-js/src/generator/blend.js
var blend = (bottom2, top2, mode) => {
  if (!blend[mode]) {
    throw new Error("unknown blend mode " + mode);
  }
  return blend[mode](bottom2, top2);
};
var blend_f = (f) => (bottom2, top2) => {
  const c0 = chroma_default(top2).rgb();
  const c1 = chroma_default(bottom2).rgb();
  return chroma_default.rgb(f(c0, c1));
};
var each = (f) => (c0, c1) => {
  const out = [];
  out[0] = f(c0[0], c1[0]);
  out[1] = f(c0[1], c1[1]);
  out[2] = f(c0[2], c1[2]);
  return out;
};
var normal = (a2) => a2;
var multiply = (a2, b) => a2 * b / 255;
var darken = (a2, b) => a2 > b ? b : a2;
var lighten = (a2, b) => a2 > b ? a2 : b;
var screen = (a2, b) => 255 * (1 - (1 - a2 / 255) * (1 - b / 255));
var overlay = (a2, b) => b < 128 ? 2 * a2 * b / 255 : 255 * (1 - 2 * (1 - a2 / 255) * (1 - b / 255));
var burn = (a2, b) => 255 * (1 - (1 - b / 255) / (a2 / 255));
var dodge = (a2, b) => {
  if (a2 === 255) return 255;
  a2 = 255 * (b / 255) / (1 - a2 / 255);
  return a2 > 255 ? 255 : a2;
};
blend.normal = blend_f(each(normal));
blend.multiply = blend_f(each(multiply));
blend.screen = blend_f(each(screen));
blend.overlay = blend_f(each(overlay));
blend.darken = blend_f(each(darken));
blend.lighten = blend_f(each(lighten));
blend.dodge = blend_f(each(dodge));
blend.burn = blend_f(each(burn));
var blend_default = blend;

// node_modules/chroma-js/src/generator/cubehelix.js
var { pow: pow5, sin: sin4, cos: cos5 } = Math;
function cubehelix_default3(start2 = 300, rotations = -1.5, hue2 = 1, gamma2 = 1, lightness = [0, 1]) {
  let dh = 0, dl;
  if (type_default(lightness) === "array") {
    dl = lightness[1] - lightness[0];
  } else {
    dl = 0;
    lightness = [lightness, lightness];
  }
  const f = function(fract) {
    const a2 = TWOPI * ((start2 + 120) / 360 + rotations * fract);
    const l = pow5(lightness[0] + dl * fract, gamma2);
    const h = dh !== 0 ? hue2[0] + fract * dh : hue2;
    const amp = h * l * (1 - l) / 2;
    const cos_a = cos5(a2);
    const sin_a = sin4(a2);
    const r = l + amp * (-0.14861 * cos_a + 1.78277 * sin_a);
    const g2 = l + amp * (-0.29227 * cos_a - 0.90649 * sin_a);
    const b = l + amp * (1.97294 * cos_a);
    return chroma_default(clip_rgb_default([r * 255, g2 * 255, b * 255, 1]));
  };
  f.start = function(s) {
    if (s == null) {
      return start2;
    }
    start2 = s;
    return f;
  };
  f.rotations = function(r) {
    if (r == null) {
      return rotations;
    }
    rotations = r;
    return f;
  };
  f.gamma = function(g2) {
    if (g2 == null) {
      return gamma2;
    }
    gamma2 = g2;
    return f;
  };
  f.hue = function(h) {
    if (h == null) {
      return hue2;
    }
    hue2 = h;
    if (type_default(hue2) === "array") {
      dh = hue2[1] - hue2[0];
      if (dh === 0) {
        hue2 = hue2[1];
      }
    } else {
      dh = 0;
    }
    return f;
  };
  f.lightness = function(h) {
    if (h == null) {
      return lightness;
    }
    if (type_default(h) === "array") {
      lightness = h;
      dl = h[1] - h[0];
    } else {
      lightness = [h, h];
      dl = 0;
    }
    return f;
  };
  f.scale = () => chroma_default.scale(f);
  f.hue(hue2);
  return f;
}

// node_modules/chroma-js/src/generator/random.js
var digits = "0123456789abcdef";
var { floor: floor3, random } = Math;
var random_default = (rng = random) => {
  let code = "#";
  for (let i = 0; i < 6; i++) {
    code += digits.charAt(floor3(rng() * 16));
  }
  return new Color_default(code, "hex");
};

// node_modules/chroma-js/src/utils/analyze.js
var { log, pow: pow6, floor: floor4, abs: abs3 } = Math;
function analyze(data, key = null) {
  const r = {
    min: Number.MAX_VALUE,
    max: Number.MAX_VALUE * -1,
    sum: 0,
    values: [],
    count: 0
  };
  if (type_default(data) === "object") {
    data = Object.values(data);
  }
  data.forEach((val) => {
    if (key && type_default(val) === "object") val = val[key];
    if (val !== void 0 && val !== null && !isNaN(val)) {
      r.values.push(val);
      r.sum += val;
      if (val < r.min) r.min = val;
      if (val > r.max) r.max = val;
      r.count += 1;
    }
  });
  r.domain = [r.min, r.max];
  r.limits = (mode, num3) => limits(r, mode, num3);
  return r;
}
function limits(data, mode = "equal", num3 = 7) {
  if (type_default(data) == "array") {
    data = analyze(data);
  }
  const { min: min8, max: max8 } = data;
  const values = data.values.sort((a2, b) => a2 - b);
  if (num3 === 1) {
    return [min8, max8];
  }
  const limits2 = [];
  if (mode.substr(0, 1) === "c") {
    limits2.push(min8);
    limits2.push(max8);
  }
  if (mode.substr(0, 1) === "e") {
    limits2.push(min8);
    for (let i = 1; i < num3; i++) {
      limits2.push(min8 + i / num3 * (max8 - min8));
    }
    limits2.push(max8);
  } else if (mode.substr(0, 1) === "l") {
    if (min8 <= 0) {
      throw new Error(
        "Logarithmic scales are only possible for values > 0"
      );
    }
    const min_log = Math.LOG10E * log(min8);
    const max_log = Math.LOG10E * log(max8);
    limits2.push(min8);
    for (let i = 1; i < num3; i++) {
      limits2.push(pow6(10, min_log + i / num3 * (max_log - min_log)));
    }
    limits2.push(max8);
  } else if (mode.substr(0, 1) === "q") {
    limits2.push(min8);
    for (let i = 1; i < num3; i++) {
      const p = (values.length - 1) * i / num3;
      const pb = floor4(p);
      if (pb === p) {
        limits2.push(values[pb]);
      } else {
        const pr = p - pb;
        limits2.push(values[pb] * (1 - pr) + values[pb + 1] * pr);
      }
    }
    limits2.push(max8);
  } else if (mode.substr(0, 1) === "k") {
    let cluster;
    const n = values.length;
    const assignments = new Array(n);
    const clusterSizes = new Array(num3);
    let repeat = true;
    let nb_iters = 0;
    let centroids = null;
    centroids = [];
    centroids.push(min8);
    for (let i = 1; i < num3; i++) {
      centroids.push(min8 + i / num3 * (max8 - min8));
    }
    centroids.push(max8);
    while (repeat) {
      for (let j = 0; j < num3; j++) {
        clusterSizes[j] = 0;
      }
      for (let i = 0; i < n; i++) {
        const value = values[i];
        let mindist = Number.MAX_VALUE;
        let best;
        for (let j = 0; j < num3; j++) {
          const dist = abs3(centroids[j] - value);
          if (dist < mindist) {
            mindist = dist;
            best = j;
          }
          clusterSizes[best]++;
          assignments[i] = best;
        }
      }
      const newCentroids = new Array(num3);
      for (let j = 0; j < num3; j++) {
        newCentroids[j] = null;
      }
      for (let i = 0; i < n; i++) {
        cluster = assignments[i];
        if (newCentroids[cluster] === null) {
          newCentroids[cluster] = values[i];
        } else {
          newCentroids[cluster] += values[i];
        }
      }
      for (let j = 0; j < num3; j++) {
        newCentroids[j] *= 1 / clusterSizes[j];
      }
      repeat = false;
      for (let j = 0; j < num3; j++) {
        if (newCentroids[j] !== centroids[j]) {
          repeat = true;
          break;
        }
      }
      centroids = newCentroids;
      nb_iters++;
      if (nb_iters > 200) {
        repeat = false;
      }
    }
    const kClusters = {};
    for (let j = 0; j < num3; j++) {
      kClusters[j] = [];
    }
    for (let i = 0; i < n; i++) {
      cluster = assignments[i];
      kClusters[cluster].push(values[i]);
    }
    let tmpKMeansBreaks = [];
    for (let j = 0; j < num3; j++) {
      tmpKMeansBreaks.push(kClusters[j][0]);
      tmpKMeansBreaks.push(kClusters[j][kClusters[j].length - 1]);
    }
    tmpKMeansBreaks = tmpKMeansBreaks.sort((a2, b) => a2 - b);
    limits2.push(tmpKMeansBreaks[0]);
    for (let i = 1; i < tmpKMeansBreaks.length; i += 2) {
      const v = tmpKMeansBreaks[i];
      if (!isNaN(v) && limits2.indexOf(v) === -1) {
        limits2.push(v);
      }
    }
  }
  return limits2;
}

// node_modules/chroma-js/src/utils/contrast.js
var contrast_default = (a2, b) => {
  a2 = new Color_default(a2);
  b = new Color_default(b);
  const l1 = a2.luminance();
  const l2 = b.luminance();
  return l1 > l2 ? (l1 + 0.05) / (l2 + 0.05) : (l2 + 0.05) / (l1 + 0.05);
};

// node_modules/chroma-js/src/utils/contrastAPCA.js
var W_offset = 0.027;
var P_in = 5e-4;
var P_out = 0.1;
var R_scale = 1.14;
var B_threshold = 0.022;
var B_exp = 1.414;
var contrastAPCA_default = (text, bg) => {
  text = new Color_default(text);
  bg = new Color_default(bg);
  if (text.alpha() < 1) {
    text = mix_default(bg, text, text.alpha(), "rgb");
  }
  const l_text = lum(...text.rgb());
  const l_bg = lum(...bg.rgb());
  const Y_text = l_text >= B_threshold ? l_text : l_text + Math.pow(B_threshold - l_text, B_exp);
  const Y_bg = l_bg >= B_threshold ? l_bg : l_bg + Math.pow(B_threshold - l_bg, B_exp);
  const S_norm = Math.pow(Y_bg, 0.56) - Math.pow(Y_text, 0.57);
  const S_rev = Math.pow(Y_bg, 0.65) - Math.pow(Y_text, 0.62);
  const C2 = Math.abs(Y_bg - Y_text) < P_in ? 0 : Y_text < Y_bg ? S_norm * R_scale : S_rev * R_scale;
  const S_apc = Math.abs(C2) < P_out ? 0 : C2 > 0 ? C2 - W_offset : C2 + W_offset;
  return S_apc * 100;
};
function lum(r, g2, b) {
  return 0.2126729 * Math.pow(r / 255, 2.4) + 0.7151522 * Math.pow(g2 / 255, 2.4) + 0.072175 * Math.pow(b / 255, 2.4);
}

// node_modules/chroma-js/src/utils/delta-e.js
var { sqrt: sqrt6, pow: pow7, min: min7, max: max6, atan2: atan24, abs: abs4, cos: cos6, sin: sin5, exp, PI: PI3 } = Math;
function delta_e_default(a2, b, Kl = 1, Kc = 1, Kh = 1) {
  var rad2deg = function(rad) {
    return 360 * rad / (2 * PI3);
  };
  var deg2rad = function(deg) {
    return 2 * PI3 * deg / 360;
  };
  a2 = new Color_default(a2);
  b = new Color_default(b);
  const [L1, a1, b1] = Array.from(a2.lab());
  const [L2, a22, b2] = Array.from(b.lab());
  const avgL = (L1 + L2) / 2;
  const C1 = sqrt6(pow7(a1, 2) + pow7(b1, 2));
  const C2 = sqrt6(pow7(a22, 2) + pow7(b2, 2));
  const avgC = (C1 + C2) / 2;
  const G = 0.5 * (1 - sqrt6(pow7(avgC, 7) / (pow7(avgC, 7) + pow7(25, 7))));
  const a1p = a1 * (1 + G);
  const a2p = a22 * (1 + G);
  const C1p = sqrt6(pow7(a1p, 2) + pow7(b1, 2));
  const C2p = sqrt6(pow7(a2p, 2) + pow7(b2, 2));
  const avgCp = (C1p + C2p) / 2;
  const arctan1 = rad2deg(atan24(b1, a1p));
  const arctan2 = rad2deg(atan24(b2, a2p));
  const h1p = arctan1 >= 0 ? arctan1 : arctan1 + 360;
  const h2p = arctan2 >= 0 ? arctan2 : arctan2 + 360;
  const avgHp = abs4(h1p - h2p) > 180 ? (h1p + h2p + 360) / 2 : (h1p + h2p) / 2;
  const T = 1 - 0.17 * cos6(deg2rad(avgHp - 30)) + 0.24 * cos6(deg2rad(2 * avgHp)) + 0.32 * cos6(deg2rad(3 * avgHp + 6)) - 0.2 * cos6(deg2rad(4 * avgHp - 63));
  let deltaHp = h2p - h1p;
  deltaHp = abs4(deltaHp) <= 180 ? deltaHp : h2p <= h1p ? deltaHp + 360 : deltaHp - 360;
  deltaHp = 2 * sqrt6(C1p * C2p) * sin5(deg2rad(deltaHp) / 2);
  const deltaL = L2 - L1;
  const deltaCp = C2p - C1p;
  const sl = 1 + 0.015 * pow7(avgL - 50, 2) / sqrt6(20 + pow7(avgL - 50, 2));
  const sc = 1 + 0.045 * avgCp;
  const sh = 1 + 0.015 * avgCp * T;
  const deltaTheta = 30 * exp(-pow7((avgHp - 275) / 25, 2));
  const Rc = 2 * sqrt6(pow7(avgCp, 7) / (pow7(avgCp, 7) + pow7(25, 7)));
  const Rt = -Rc * sin5(2 * deg2rad(deltaTheta));
  const result = sqrt6(
    pow7(deltaL / (Kl * sl), 2) + pow7(deltaCp / (Kc * sc), 2) + pow7(deltaHp / (Kh * sh), 2) + Rt * (deltaCp / (Kc * sc)) * (deltaHp / (Kh * sh))
  );
  return max6(0, min7(100, result));
}

// node_modules/chroma-js/src/utils/distance.js
function distance_default(a2, b, mode = "lab") {
  a2 = new Color_default(a2);
  b = new Color_default(b);
  const l1 = a2.get(mode);
  const l2 = b.get(mode);
  let sum_sq = 0;
  for (let i in l1) {
    const d = (l1[i] || 0) - (l2[i] || 0);
    sum_sq += d * d;
  }
  return Math.sqrt(sum_sq);
}

// node_modules/chroma-js/src/utils/valid.js
var valid_default = (...args) => {
  try {
    new Color_default(...args);
    return true;
  } catch (e) {
    return false;
  }
};

// node_modules/chroma-js/src/utils/scales.js
var scales_default = {
  cool() {
    return scale_default([chroma_default.hsl(180, 1, 0.9), chroma_default.hsl(250, 0.7, 0.4)]);
  },
  hot() {
    return scale_default(["#000", "#f00", "#ff0", "#fff"], [0, 0.25, 0.75, 1]).mode(
      "rgb"
    );
  }
};

// node_modules/chroma-js/src/colors/colorbrewer.js
var colorbrewer = {
  // sequential
  OrRd: ["#fff7ec", "#fee8c8", "#fdd49e", "#fdbb84", "#fc8d59", "#ef6548", "#d7301f", "#b30000", "#7f0000"],
  PuBu: ["#fff7fb", "#ece7f2", "#d0d1e6", "#a6bddb", "#74a9cf", "#3690c0", "#0570b0", "#045a8d", "#023858"],
  BuPu: ["#f7fcfd", "#e0ecf4", "#bfd3e6", "#9ebcda", "#8c96c6", "#8c6bb1", "#88419d", "#810f7c", "#4d004b"],
  Oranges: ["#fff5eb", "#fee6ce", "#fdd0a2", "#fdae6b", "#fd8d3c", "#f16913", "#d94801", "#a63603", "#7f2704"],
  BuGn: ["#f7fcfd", "#e5f5f9", "#ccece6", "#99d8c9", "#66c2a4", "#41ae76", "#238b45", "#006d2c", "#00441b"],
  YlOrBr: ["#ffffe5", "#fff7bc", "#fee391", "#fec44f", "#fe9929", "#ec7014", "#cc4c02", "#993404", "#662506"],
  YlGn: ["#ffffe5", "#f7fcb9", "#d9f0a3", "#addd8e", "#78c679", "#41ab5d", "#238443", "#006837", "#004529"],
  Reds: ["#fff5f0", "#fee0d2", "#fcbba1", "#fc9272", "#fb6a4a", "#ef3b2c", "#cb181d", "#a50f15", "#67000d"],
  RdPu: ["#fff7f3", "#fde0dd", "#fcc5c0", "#fa9fb5", "#f768a1", "#dd3497", "#ae017e", "#7a0177", "#49006a"],
  Greens: ["#f7fcf5", "#e5f5e0", "#c7e9c0", "#a1d99b", "#74c476", "#41ab5d", "#238b45", "#006d2c", "#00441b"],
  YlGnBu: ["#ffffd9", "#edf8b1", "#c7e9b4", "#7fcdbb", "#41b6c4", "#1d91c0", "#225ea8", "#253494", "#081d58"],
  Purples: ["#fcfbfd", "#efedf5", "#dadaeb", "#bcbddc", "#9e9ac8", "#807dba", "#6a51a3", "#54278f", "#3f007d"],
  GnBu: ["#f7fcf0", "#e0f3db", "#ccebc5", "#a8ddb5", "#7bccc4", "#4eb3d3", "#2b8cbe", "#0868ac", "#084081"],
  Greys: ["#ffffff", "#f0f0f0", "#d9d9d9", "#bdbdbd", "#969696", "#737373", "#525252", "#252525", "#000000"],
  YlOrRd: ["#ffffcc", "#ffeda0", "#fed976", "#feb24c", "#fd8d3c", "#fc4e2a", "#e31a1c", "#bd0026", "#800026"],
  PuRd: ["#f7f4f9", "#e7e1ef", "#d4b9da", "#c994c7", "#df65b0", "#e7298a", "#ce1256", "#980043", "#67001f"],
  Blues: ["#f7fbff", "#deebf7", "#c6dbef", "#9ecae1", "#6baed6", "#4292c6", "#2171b5", "#08519c", "#08306b"],
  PuBuGn: ["#fff7fb", "#ece2f0", "#d0d1e6", "#a6bddb", "#67a9cf", "#3690c0", "#02818a", "#016c59", "#014636"],
  Viridis: ["#440154", "#482777", "#3f4a8a", "#31678e", "#26838f", "#1f9d8a", "#6cce5a", "#b6de2b", "#fee825"],
  // diverging
  Spectral: ["#9e0142", "#d53e4f", "#f46d43", "#fdae61", "#fee08b", "#ffffbf", "#e6f598", "#abdda4", "#66c2a5", "#3288bd", "#5e4fa2"],
  RdYlGn: ["#a50026", "#d73027", "#f46d43", "#fdae61", "#fee08b", "#ffffbf", "#d9ef8b", "#a6d96a", "#66bd63", "#1a9850", "#006837"],
  RdBu: ["#67001f", "#b2182b", "#d6604d", "#f4a582", "#fddbc7", "#f7f7f7", "#d1e5f0", "#92c5de", "#4393c3", "#2166ac", "#053061"],
  PiYG: ["#8e0152", "#c51b7d", "#de77ae", "#f1b6da", "#fde0ef", "#f7f7f7", "#e6f5d0", "#b8e186", "#7fbc41", "#4d9221", "#276419"],
  PRGn: ["#40004b", "#762a83", "#9970ab", "#c2a5cf", "#e7d4e8", "#f7f7f7", "#d9f0d3", "#a6dba0", "#5aae61", "#1b7837", "#00441b"],
  RdYlBu: ["#a50026", "#d73027", "#f46d43", "#fdae61", "#fee090", "#ffffbf", "#e0f3f8", "#abd9e9", "#74add1", "#4575b4", "#313695"],
  BrBG: ["#543005", "#8c510a", "#bf812d", "#dfc27d", "#f6e8c3", "#f5f5f5", "#c7eae5", "#80cdc1", "#35978f", "#01665e", "#003c30"],
  RdGy: ["#67001f", "#b2182b", "#d6604d", "#f4a582", "#fddbc7", "#ffffff", "#e0e0e0", "#bababa", "#878787", "#4d4d4d", "#1a1a1a"],
  PuOr: ["#7f3b08", "#b35806", "#e08214", "#fdb863", "#fee0b6", "#f7f7f7", "#d8daeb", "#b2abd2", "#8073ac", "#542788", "#2d004b"],
  // qualitative
  Set2: ["#66c2a5", "#fc8d62", "#8da0cb", "#e78ac3", "#a6d854", "#ffd92f", "#e5c494", "#b3b3b3"],
  Accent: ["#7fc97f", "#beaed4", "#fdc086", "#ffff99", "#386cb0", "#f0027f", "#bf5b17", "#666666"],
  Set1: ["#e41a1c", "#377eb8", "#4daf4a", "#984ea3", "#ff7f00", "#ffff33", "#a65628", "#f781bf", "#999999"],
  Set3: ["#8dd3c7", "#ffffb3", "#bebada", "#fb8072", "#80b1d3", "#fdb462", "#b3de69", "#fccde5", "#d9d9d9", "#bc80bd", "#ccebc5", "#ffed6f"],
  Dark2: ["#1b9e77", "#d95f02", "#7570b3", "#e7298a", "#66a61e", "#e6ab02", "#a6761d", "#666666"],
  Paired: ["#a6cee3", "#1f78b4", "#b2df8a", "#33a02c", "#fb9a99", "#e31a1c", "#fdbf6f", "#ff7f00", "#cab2d6", "#6a3d9a", "#ffff99", "#b15928"],
  Pastel2: ["#b3e2cd", "#fdcdac", "#cbd5e8", "#f4cae4", "#e6f5c9", "#fff2ae", "#f1e2cc", "#cccccc"],
  Pastel1: ["#fbb4ae", "#b3cde3", "#ccebc5", "#decbe4", "#fed9a6", "#ffffcc", "#e5d8bd", "#fddaec", "#f2f2f2"]
};
var colorbrewerTypes = Object.keys(colorbrewer);
var typeMap = new Map(colorbrewerTypes.map((key) => [key.toLowerCase(), key]));
var colorbrewerProxy = typeof Proxy === "function" ? new Proxy(colorbrewer, {
  get(target, prop) {
    const lower2 = prop.toLowerCase();
    if (typeMap.has(lower2)) {
      return target[typeMap.get(lower2)];
    }
  },
  getOwnPropertyNames() {
    return Object.getOwnPropertyNames(colorbrewerTypes);
  }
}) : colorbrewer;
var colorbrewer_default = colorbrewerProxy;

// node_modules/chroma-js/src/io/cmyk/cmyk2rgb.js
var cmyk2rgb = (...args) => {
  args = unpack_default(args, "cmyk");
  const [c4, m2, y3, k] = args;
  const alpha = args.length > 4 ? args[4] : 1;
  if (k === 1) return [0, 0, 0, alpha];
  return [
    c4 >= 1 ? 0 : 255 * (1 - c4) * (1 - k),
    // r
    m2 >= 1 ? 0 : 255 * (1 - m2) * (1 - k),
    // g
    y3 >= 1 ? 0 : 255 * (1 - y3) * (1 - k),
    // b
    alpha
  ];
};
var cmyk2rgb_default = cmyk2rgb;

// node_modules/chroma-js/src/io/cmyk/rgb2cmyk.js
var { max: max7 } = Math;
var rgb2cmyk = (...args) => {
  let [r, g2, b] = unpack_default(args, "rgb");
  r = r / 255;
  g2 = g2 / 255;
  b = b / 255;
  const k = 1 - max7(r, max7(g2, b));
  const f = k < 1 ? 1 / (1 - k) : 0;
  const c4 = (1 - r - k) * f;
  const m2 = (1 - g2 - k) * f;
  const y3 = (1 - b - k) * f;
  return [c4, m2, y3, k];
};
var rgb2cmyk_default = rgb2cmyk;

// node_modules/chroma-js/src/io/cmyk/index.js
Color_default.prototype.cmyk = function() {
  return rgb2cmyk_default(this._rgb);
};
var cmyk = (...args) => new Color_default(...args, "cmyk");
Object.assign(chroma_default, { cmyk });
input_default.format.cmyk = cmyk2rgb_default;
input_default.autodetect.push({
  p: 2,
  test: (...args) => {
    args = unpack_default(args, "cmyk");
    if (type_default(args) === "array" && args.length === 4) {
      return "cmyk";
    }
  }
});

// node_modules/chroma-js/src/io/css/hsl2css.js
var hsl2css = (...args) => {
  const hsla2 = unpack_default(args, "hsla");
  let mode = last_default(args) || "lsa";
  hsla2[0] = rnd2(hsla2[0] || 0) + "deg";
  hsla2[1] = rnd2(hsla2[1] * 100) + "%";
  hsla2[2] = rnd2(hsla2[2] * 100) + "%";
  if (mode === "hsla" || hsla2.length > 3 && hsla2[3] < 1) {
    hsla2[3] = "/ " + (hsla2.length > 3 ? hsla2[3] : 1);
    mode = "hsla";
  } else {
    hsla2.length = 3;
  }
  return `${mode.substr(0, 3)}(${hsla2.join(" ")})`;
};
var hsl2css_default = hsl2css;

// node_modules/chroma-js/src/io/css/lab2css.js
var lab2css = (...args) => {
  const laba = unpack_default(args, "lab");
  let mode = last_default(args) || "lab";
  laba[0] = rnd2(laba[0]) + "%";
  laba[1] = rnd2(laba[1]);
  laba[2] = rnd2(laba[2]);
  if (mode === "laba" || laba.length > 3 && laba[3] < 1) {
    laba[3] = "/ " + (laba.length > 3 ? laba[3] : 1);
  } else {
    laba.length = 3;
  }
  return `lab(${laba.join(" ")})`;
};
var lab2css_default = lab2css;

// node_modules/chroma-js/src/io/css/lch2css.js
var lch2css = (...args) => {
  const lcha = unpack_default(args, "lch");
  let mode = last_default(args) || "lab";
  lcha[0] = rnd2(lcha[0]) + "%";
  lcha[1] = rnd2(lcha[1]);
  lcha[2] = isNaN(lcha[2]) ? "none" : rnd2(lcha[2]) + "deg";
  if (mode === "lcha" || lcha.length > 3 && lcha[3] < 1) {
    lcha[3] = "/ " + (lcha.length > 3 ? lcha[3] : 1);
  } else {
    lcha.length = 3;
  }
  return `lch(${lcha.join(" ")})`;
};
var lch2css_default = lch2css;

// node_modules/chroma-js/src/io/css/oklab2css.js
var oklab2css = (...args) => {
  const laba = unpack_default(args, "lab");
  laba[0] = rnd2(laba[0] * 100) + "%";
  laba[1] = rnd3(laba[1]);
  laba[2] = rnd3(laba[2]);
  if (laba.length > 3 && laba[3] < 1) {
    laba[3] = "/ " + (laba.length > 3 ? laba[3] : 1);
  } else {
    laba.length = 3;
  }
  return `oklab(${laba.join(" ")})`;
};
var oklab2css_default = oklab2css;

// node_modules/chroma-js/src/io/oklch/rgb2oklch.js
var rgb2oklch = (...args) => {
  const [r, g2, b, ...rest] = unpack_default(args, "rgb");
  const [l, a2, b_] = rgb2oklab_default(r, g2, b);
  const [L, c4, h] = lab2lch_default(l, a2, b_);
  return [L, c4, h, ...rest.length > 0 && rest[0] < 1 ? [rest[0]] : []];
};
var rgb2oklch_default = rgb2oklch;

// node_modules/chroma-js/src/io/css/oklch2css.js
var oklch2css = (...args) => {
  const lcha = unpack_default(args, "lch");
  lcha[0] = rnd2(lcha[0] * 100) + "%";
  lcha[1] = rnd3(lcha[1]);
  lcha[2] = isNaN(lcha[2]) ? "none" : rnd2(lcha[2]) + "deg";
  if (lcha.length > 3 && lcha[3] < 1) {
    lcha[3] = "/ " + (lcha.length > 3 ? lcha[3] : 1);
  } else {
    lcha.length = 3;
  }
  return `oklch(${lcha.join(" ")})`;
};
var oklch2css_default = oklch2css;

// node_modules/chroma-js/src/io/css/rgb2css.js
var { round: round4 } = Math;
var rgb2css = (...args) => {
  const rgba2 = unpack_default(args, "rgba");
  let mode = last_default(args) || "rgb";
  if (mode.substr(0, 3) === "hsl") {
    return hsl2css_default(rgb2hsl_default(rgba2), mode);
  }
  if (mode.substr(0, 3) === "lab") {
    const prevWhitePoint = getLabWhitePoint();
    setLabWhitePoint("d50");
    const cssColor = lab2css_default(rgb2lab_default(rgba2), mode);
    setLabWhitePoint(prevWhitePoint);
    return cssColor;
  }
  if (mode.substr(0, 3) === "lch") {
    const prevWhitePoint = getLabWhitePoint();
    setLabWhitePoint("d50");
    const cssColor = lch2css_default(rgb2lch_default(rgba2), mode);
    setLabWhitePoint(prevWhitePoint);
    return cssColor;
  }
  if (mode.substr(0, 5) === "oklab") {
    return oklab2css_default(rgb2oklab_default(rgba2));
  }
  if (mode.substr(0, 5) === "oklch") {
    return oklch2css_default(rgb2oklch_default(rgba2));
  }
  rgba2[0] = round4(rgba2[0]);
  rgba2[1] = round4(rgba2[1]);
  rgba2[2] = round4(rgba2[2]);
  if (mode === "rgba" || rgba2.length > 3 && rgba2[3] < 1) {
    rgba2[3] = "/ " + (rgba2.length > 3 ? rgba2[3] : 1);
    mode = "rgba";
  }
  return `${mode.substr(0, 3)}(${rgba2.slice(0, mode === "rgb" ? 3 : 4).join(" ")})`;
};
var rgb2css_default = rgb2css;

// node_modules/chroma-js/src/io/oklch/oklch2rgb.js
var oklch2rgb = (...args) => {
  args = unpack_default(args, "lch");
  const [l, c4, h, ...rest] = args;
  const [L, a2, b_] = lch2lab_default(l, c4, h);
  const [r, g2, b] = oklab2rgb_default(L, a2, b_);
  return [r, g2, b, ...rest.length > 0 && rest[0] < 1 ? [rest[0]] : []];
};
var oklch2rgb_default = oklch2rgb;

// node_modules/chroma-js/src/io/css/css2rgb.js
var INT_OR_PCT = /((?:-?\d+)|(?:-?\d+(?:\.\d+)?)%|none)/.source;
var FLOAT_OR_PCT = /((?:-?(?:\d+(?:\.\d*)?|\.\d+)%?)|none)/.source;
var PCT = /((?:-?(?:\d+(?:\.\d*)?|\.\d+)%)|none)/.source;
var RE_S = /\s*/.source;
var SEP = /\s+/.source;
var COMMA = /\s*,\s*/.source;
var ANLGE = /((?:-?(?:\d+(?:\.\d*)?|\.\d+)(?:deg)?)|none)/.source;
var ALPHA = /\s*(?:\/\s*((?:[01]|[01]?\.\d+)|\d+(?:\.\d+)?%))?/.source;
var RE_RGB = new RegExp(
  "^rgba?\\(" + RE_S + [INT_OR_PCT, INT_OR_PCT, INT_OR_PCT].join(SEP) + ALPHA + "\\)$"
);
var RE_RGB_LEGACY = new RegExp(
  "^rgb\\(" + RE_S + [INT_OR_PCT, INT_OR_PCT, INT_OR_PCT].join(COMMA) + RE_S + "\\)$"
);
var RE_RGBA_LEGACY = new RegExp(
  "^rgba\\(" + RE_S + [INT_OR_PCT, INT_OR_PCT, INT_OR_PCT, FLOAT_OR_PCT].join(COMMA) + RE_S + "\\)$"
);
var RE_HSL = new RegExp(
  "^hsla?\\(" + RE_S + [ANLGE, PCT, PCT].join(SEP) + ALPHA + "\\)$"
);
var RE_HSL_LEGACY = new RegExp(
  "^hsl?\\(" + RE_S + [ANLGE, PCT, PCT].join(COMMA) + RE_S + "\\)$"
);
var RE_HSLA_LEGACY = /^hsla\(\s*(-?\d+(?:\.\d+)?),\s*(-?\d+(?:\.\d+)?)%\s*,\s*(-?\d+(?:\.\d+)?)%\s*,\s*([01]|[01]?\.\d+)\)$/;
var RE_LAB = new RegExp(
  "^lab\\(" + RE_S + [FLOAT_OR_PCT, FLOAT_OR_PCT, FLOAT_OR_PCT].join(SEP) + ALPHA + "\\)$"
);
var RE_LCH = new RegExp(
  "^lch\\(" + RE_S + [FLOAT_OR_PCT, FLOAT_OR_PCT, ANLGE].join(SEP) + ALPHA + "\\)$"
);
var RE_OKLAB = new RegExp(
  "^oklab\\(" + RE_S + [FLOAT_OR_PCT, FLOAT_OR_PCT, FLOAT_OR_PCT].join(SEP) + ALPHA + "\\)$"
);
var RE_OKLCH = new RegExp(
  "^oklch\\(" + RE_S + [FLOAT_OR_PCT, FLOAT_OR_PCT, ANLGE].join(SEP) + ALPHA + "\\)$"
);
var { round: round5 } = Math;
var roundRGB = (rgb4) => {
  return rgb4.map((v, i) => i <= 2 ? limit_default(round5(v), 0, 255) : v);
};
var percentToAbsolute = (pct, min8 = 0, max8 = 100, signed = false) => {
  if (typeof pct === "string" && pct.endsWith("%")) {
    pct = parseFloat(pct.substring(0, pct.length - 1)) / 100;
    if (signed) {
      pct = min8 + (pct + 1) * 0.5 * (max8 - min8);
    } else {
      pct = min8 + pct * (max8 - min8);
    }
  }
  return +pct;
};
var noneToValue = (v, noneValue) => {
  return v === "none" ? noneValue : v;
};
var css2rgb = (css2) => {
  css2 = css2.toLowerCase().trim();
  if (css2 === "transparent") {
    return [0, 0, 0, 0];
  }
  let m2;
  if (input_default.format.named) {
    try {
      return input_default.format.named(css2);
    } catch (e) {
    }
  }
  if ((m2 = css2.match(RE_RGB)) || (m2 = css2.match(RE_RGB_LEGACY))) {
    let rgb4 = m2.slice(1, 4);
    for (let i = 0; i < 3; i++) {
      rgb4[i] = +percentToAbsolute(noneToValue(rgb4[i], 0), 0, 255);
    }
    rgb4 = roundRGB(rgb4);
    const alpha = m2[4] !== void 0 ? +percentToAbsolute(m2[4], 0, 1) : 1;
    rgb4[3] = alpha;
    return rgb4;
  }
  if (m2 = css2.match(RE_RGBA_LEGACY)) {
    const rgb4 = m2.slice(1, 5);
    for (let i = 0; i < 4; i++) {
      rgb4[i] = +percentToAbsolute(rgb4[i], 0, 255);
    }
    return rgb4;
  }
  if ((m2 = css2.match(RE_HSL)) || (m2 = css2.match(RE_HSL_LEGACY))) {
    const hsl4 = m2.slice(1, 4);
    hsl4[0] = +noneToValue(hsl4[0].replace("deg", ""), 0);
    hsl4[1] = +percentToAbsolute(noneToValue(hsl4[1], 0), 0, 100) * 0.01;
    hsl4[2] = +percentToAbsolute(noneToValue(hsl4[2], 0), 0, 100) * 0.01;
    const rgb4 = roundRGB(hsl2rgb_default(hsl4));
    const alpha = m2[4] !== void 0 ? +percentToAbsolute(m2[4], 0, 1) : 1;
    rgb4[3] = alpha;
    return rgb4;
  }
  if (m2 = css2.match(RE_HSLA_LEGACY)) {
    const hsl4 = m2.slice(1, 4);
    hsl4[1] *= 0.01;
    hsl4[2] *= 0.01;
    const rgb4 = hsl2rgb_default(hsl4);
    for (let i = 0; i < 3; i++) {
      rgb4[i] = round5(rgb4[i]);
    }
    rgb4[3] = +m2[4];
    return rgb4;
  }
  if (m2 = css2.match(RE_LAB)) {
    const lab3 = m2.slice(1, 4);
    lab3[0] = percentToAbsolute(noneToValue(lab3[0], 0), 0, 100);
    lab3[1] = percentToAbsolute(noneToValue(lab3[1], 0), -125, 125, true);
    lab3[2] = percentToAbsolute(noneToValue(lab3[2], 0), -125, 125, true);
    const wp = getLabWhitePoint();
    setLabWhitePoint("d50");
    const rgb4 = roundRGB(lab2rgb_default(lab3));
    setLabWhitePoint(wp);
    const alpha = m2[4] !== void 0 ? +percentToAbsolute(m2[4], 0, 1) : 1;
    rgb4[3] = alpha;
    return rgb4;
  }
  if (m2 = css2.match(RE_LCH)) {
    const lch3 = m2.slice(1, 4);
    lch3[0] = percentToAbsolute(lch3[0], 0, 100);
    lch3[1] = percentToAbsolute(noneToValue(lch3[1], 0), 0, 150, false);
    lch3[2] = +noneToValue(lch3[2].replace("deg", ""), 0);
    const wp = getLabWhitePoint();
    setLabWhitePoint("d50");
    const rgb4 = roundRGB(lch2rgb_default(lch3));
    setLabWhitePoint(wp);
    const alpha = m2[4] !== void 0 ? +percentToAbsolute(m2[4], 0, 1) : 1;
    rgb4[3] = alpha;
    return rgb4;
  }
  if (m2 = css2.match(RE_OKLAB)) {
    const oklab3 = m2.slice(1, 4);
    oklab3[0] = percentToAbsolute(noneToValue(oklab3[0], 0), 0, 1);
    oklab3[1] = percentToAbsolute(noneToValue(oklab3[1], 0), -0.4, 0.4, true);
    oklab3[2] = percentToAbsolute(noneToValue(oklab3[2], 0), -0.4, 0.4, true);
    const rgb4 = roundRGB(oklab2rgb_default(oklab3));
    const alpha = m2[4] !== void 0 ? +percentToAbsolute(m2[4], 0, 1) : 1;
    rgb4[3] = alpha;
    return rgb4;
  }
  if (m2 = css2.match(RE_OKLCH)) {
    const oklch3 = m2.slice(1, 4);
    oklch3[0] = percentToAbsolute(noneToValue(oklch3[0], 0), 0, 1);
    oklch3[1] = percentToAbsolute(noneToValue(oklch3[1], 0), 0, 0.4, false);
    oklch3[2] = +noneToValue(oklch3[2].replace("deg", ""), 0);
    const rgb4 = roundRGB(oklch2rgb_default(oklch3));
    const alpha = m2[4] !== void 0 ? +percentToAbsolute(m2[4], 0, 1) : 1;
    rgb4[3] = alpha;
    return rgb4;
  }
};
css2rgb.test = (s) => {
  return (
    // modern
    RE_RGB.test(s) || RE_HSL.test(s) || RE_LAB.test(s) || RE_LCH.test(s) || RE_OKLAB.test(s) || RE_OKLCH.test(s) || // legacy
    RE_RGB_LEGACY.test(s) || RE_RGBA_LEGACY.test(s) || RE_HSL_LEGACY.test(s) || RE_HSLA_LEGACY.test(s) || s === "transparent"
  );
};
var css2rgb_default = css2rgb;

// node_modules/chroma-js/src/io/css/index.js
Color_default.prototype.css = function(mode) {
  return rgb2css_default(this._rgb, mode);
};
var css = (...args) => new Color_default(...args, "css");
chroma_default.css = css;
input_default.format.css = css2rgb_default;
input_default.autodetect.push({
  p: 5,
  test: (h, ...rest) => {
    if (!rest.length && type_default(h) === "string" && css2rgb_default.test(h)) {
      return "css";
    }
  }
});

// node_modules/chroma-js/src/io/gl/index.js
input_default.format.gl = (...args) => {
  const rgb4 = unpack_default(args, "rgba");
  rgb4[0] *= 255;
  rgb4[1] *= 255;
  rgb4[2] *= 255;
  return rgb4;
};
var gl = (...args) => new Color_default(...args, "gl");
chroma_default.gl = gl;
Color_default.prototype.gl = function() {
  const rgb4 = this._rgb;
  return [rgb4[0] / 255, rgb4[1] / 255, rgb4[2] / 255, rgb4[3]];
};

// node_modules/chroma-js/src/io/hex/index.js
Color_default.prototype.hex = function(mode) {
  return rgb2hex_default(this._rgb, mode);
};
var hex2 = (...args) => new Color_default(...args, "hex");
chroma_default.hex = hex2;
input_default.format.hex = hex2rgb_default;
input_default.autodetect.push({
  p: 4,
  test: (h, ...rest) => {
    if (!rest.length && type_default(h) === "string" && [3, 4, 5, 6, 7, 8, 9].indexOf(h.length) >= 0) {
      return "hex";
    }
  }
});

// node_modules/chroma-js/src/io/temp/temperature2rgb.js
var { log: log2 } = Math;
var temperature2rgb = (kelvin) => {
  const temp2 = kelvin / 100;
  let r, g2, b;
  if (temp2 < 66) {
    r = 255;
    g2 = temp2 < 6 ? 0 : -155.25485562709179 - 0.44596950469579133 * (g2 = temp2 - 2) + 104.49216199393888 * log2(g2);
    b = temp2 < 20 ? 0 : -254.76935184120902 + 0.8274096064007395 * (b = temp2 - 10) + 115.67994401066147 * log2(b);
  } else {
    r = 351.97690566805693 + 0.114206453784165 * (r = temp2 - 55) - 40.25366309332127 * log2(r);
    g2 = 325.4494125711974 + 0.07943456536662342 * (g2 = temp2 - 50) - 28.0852963507957 * log2(g2);
    b = 255;
  }
  return [r, g2, b, 1];
};
var temperature2rgb_default = temperature2rgb;

// node_modules/chroma-js/src/io/temp/rgb2temperature.js
var { round: round6 } = Math;
var rgb2temperature = (...args) => {
  const rgb4 = unpack_default(args, "rgb");
  const r = rgb4[0], b = rgb4[2];
  let minTemp = 1e3;
  let maxTemp = 4e4;
  const eps = 0.4;
  let temp2;
  while (maxTemp - minTemp > eps) {
    temp2 = (maxTemp + minTemp) * 0.5;
    const rgb5 = temperature2rgb_default(temp2);
    if (rgb5[2] / rgb5[0] >= b / r) {
      maxTemp = temp2;
    } else {
      minTemp = temp2;
    }
  }
  return round6(temp2);
};
var rgb2temperature_default = rgb2temperature;

// node_modules/chroma-js/src/io/temp/index.js
Color_default.prototype.temp = Color_default.prototype.kelvin = Color_default.prototype.temperature = function() {
  return rgb2temperature_default(this._rgb);
};
var temp = (...args) => new Color_default(...args, "temp");
Object.assign(chroma_default, { temp, kelvin: temp, temperature: temp });
input_default.format.temp = input_default.format.kelvin = input_default.format.temperature = temperature2rgb_default;

// node_modules/chroma-js/src/io/oklch/index.js
Color_default.prototype.oklch = function() {
  return rgb2oklch_default(this._rgb);
};
var oklch2 = (...args) => new Color_default(...args, "oklch");
Object.assign(chroma_default, { oklch: oklch2 });
input_default.format.oklch = oklch2rgb_default;
input_default.autodetect.push({
  p: 2,
  test: (...args) => {
    args = unpack_default(args, "oklch");
    if (type_default(args) === "array" && args.length === 3) {
      return "oklch";
    }
  }
});

// node_modules/chroma-js/index.js
Object.assign(chroma_default, {
  analyze,
  average: average_default,
  bezier: bezier_default,
  blend: blend_default,
  brewer: colorbrewer_default,
  Color: Color_default,
  colors: w3cx11_default,
  contrast: contrast_default,
  contrastAPCA: contrastAPCA_default,
  cubehelix: cubehelix_default3,
  deltaE: delta_e_default,
  distance: distance_default,
  input: input_default,
  interpolate: mix_default,
  limits,
  mix: mix_default,
  random: random_default,
  scale: scale_default,
  scales: scales_default,
  valid: valid_default
});

// src/types/color-palette.ts
var CATEGORIES = {
  COLORBREWER: "ColorBrewer",
  D3: "D3",
  UBER: "Uber",
  COLORBLIND: "ColorBlind"
};
var PALETTE_TYPES = {
  SEQ: "sequential",
  QUA: "qualitative",
  DIV: "diverging",
  CYC: "cyclical"
};

// src/lib/color-palette.ts
var COLORBREWER_SCHEME = {
  [PALETTE_TYPES.SEQ]: [
    "BuGn",
    "BuPu",
    "GnBu",
    "OrRd",
    "PuBu",
    "PuBuGn",
    "PuRd",
    "RdPu",
    "YlGn",
    "YlGnBu",
    "YlOrBr",
    "YlOrRd",
    "Blues",
    "Greens",
    "Greys",
    "Oranges",
    "Purples",
    "Reds"
  ],
  [PALETTE_TYPES.DIV]: [
    "BrBG",
    "PiYG",
    "PRGn",
    "PuOr",
    "RdBu",
    "RdGy",
    "RdYlBu",
    "RdYlGn",
    "Spectral"
  ],
  [PALETTE_TYPES.QUA]: [
    "Accent",
    "Dark2",
    "Paired",
    "Pastel1",
    "Pastel2",
    "Set1",
    "Set2",
    "Set3"
  ]
};
var D3_COLOR_CHROMATIC_SCHEME = {
  [PALETTE_TYPES.CYC]: ["Sinebow", "Rainbow", "Turbo"],
  [PALETTE_TYPES.SEQ]: [
    "Viridis",
    "Magma",
    "Plasma",
    "Cividis",
    "CubehelixDefault",
    "Warm",
    "Cool"
  ],
  // [PALETTE_TYPES.DIV]: [],
  [PALETTE_TYPES.QUA]: ["Tableau10"]
};
var COLOR_BLIND_SAFE_MAP = {
  // colorbrewer
  BrBG: true,
  // Brown-Blue-Green: Safe for color blind users
  PiYG: true,
  // Pink-Yellow-Green: Safe
  PRGn: true,
  // Purple-Green: Safe
  PuOr: true,
  // Purple-Orange: Safe
  RdBu: true,
  // Red-Blue: Safe
  RdGy: false,
  // Red-Grey: Not safe
  RdYlBu: true,
  // Red-Yellow-Blue: Safe
  RdYlGn: false,
  // Red-Yellow-Green: Not safe
  Spectral: false,
  // Rainbow spectrum: Not safe
  // Qualitative schemes
  Accent: false,
  // High contrast accents: Not safe
  Dark2: true,
  // Dark colors: Safe
  Paired: true,
  // Paired colors: Safe
  Pastel1: false,
  // Light pastel: Not safe
  Pastel2: false,
  // Light pastel: Not safe
  Set1: false,
  // Bright set: Not safe
  Set2: true,
  // Muted set: Safe
  Set3: false,
  // Pastel set: Not safe
  // Sequential single-hue schemes
  Blues: true,
  // Blue scale: Safe
  BuGn: true,
  // Blue-Green: Safe
  BuPu: true,
  // Blue-Purple: Safe
  GnBu: true,
  // Green-Blue: Safe
  Greens: true,
  // Green scale: Safe
  Greys: true,
  // Grey scale: Safe
  Oranges: true,
  // Orange scale: Safe
  OrRd: true,
  // Orange-Red: Safe
  PuBu: true,
  // Purple-Blue: Safe
  PuBuGn: true,
  // Purple-Blue-Green: Safe
  PuRd: true,
  // Purple-Red: Safe
  Purples: true,
  // Purple scale: Safe
  RdPu: true,
  // Red-Purple: Safe
  Reds: true,
  // Red scale: Safe
  YlGn: true,
  // Yellow-Green: Safe
  YlGnBu: true,
  // Yellow-Green-Blue: Safe
  YlOrBr: true,
  // Yellow-Orange-Brown: Safe
  YlOrRd: true,
  // Yellow-Orange-Red: Safe
  // d3 scale chromatic
  Sinebow: true,
  // Circular rainbow: Safe
  Rainbow: false,
  // Traditional rainbow: Not safe
  Turbo: true,
  // Improved rainbow: Safe
  Viridis: true,
  // Yellow-Green-Blue: Safe
  Inferno: true,
  // Yellow-Red-Purple: Safe
  Magma: true,
  // White-Purple-Black: Safe
  Plasma: true,
  // Blue-Red-Yellow: Safe
  Cividis: true,
  // Blue-Yellow: Safe
  Warm: true,
  // Warm temperature: Safe
  Cool: false,
  // Cool temperature: Not safe
  CubehelixDefault: true,
  // Spiral in color space: Safe
  Tableau10: false
  // Tableau's categorical: Not safe
};
function _colorToUppercase(c4) {
  return color(c4)?.formatHex().toUpperCase() || "#FFFFFF";
}
function buildCategoricalPalette({
  name,
  category,
  colors,
  colorBlindSafe
}) {
  let allColors;
  const scheme28 = src_exports[`scheme${name}`];
  if (!scheme28 && !colors) {
    allColors = ["#DDDDDD"];
  } else if (!scheme28) {
    allColors = colors || [];
  } else {
    allColors = scheme28;
  }
  if (!allColors.length) {
  }
  return {
    name,
    category,
    type: "qualitative",
    colorBlindSafe: colorBlindSafe ?? COLOR_BLIND_SAFE_MAP[name],
    maxStep: allColors.length,
    colors: (numColors) => {
      return allColors.slice(0, numColors).map(_colorToUppercase);
    }
  };
}
function buildSequentialPalette({
  name,
  type: type2,
  category
}) {
  if (!Object.prototype.hasOwnProperty.call(COLOR_BLIND_SAFE_MAP, name)) {
  }
  const interpolator = src_exports[`interpolate${name}`];
  return {
    name,
    type: type2,
    category,
    colorBlindSafe: COLOR_BLIND_SAFE_MAP[name],
    colors: (numColors) => {
      const divisor = Math.max(numColors - 1, 1);
      return range(0, numColors, 1).map((d) => interpolator ? interpolator(d / divisor) : "#FFFFFF").map(_colorToUppercase);
    },
    linear: () => (n) => interpolator ? interpolator(n) : "#FFFFFF"
  };
}
function buildPaletteBySchemeGroups(schemeGroups, category) {
  return Object.entries(schemeGroups).reduce((accu, [type2, palettes]) => {
    const newPalettes = palettes.reduce((group, name) => {
      const colorPalette = type2 === PALETTE_TYPES.QUA ? buildCategoricalPalette({ name, category }) : buildSequentialPalette({ name, type: type2, category });
      group.push(colorPalette);
      return group;
    }, []);
    return [...accu, ...newPalettes];
  }, []);
}
var COLORBREWER_PALETTES = buildPaletteBySchemeGroups(COLORBREWER_SCHEME, CATEGORIES.COLORBREWER);
var D3_COLOR_PALETTES = buildPaletteBySchemeGroups(D3_COLOR_CHROMATIC_SCHEME, CATEGORIES.D3);
var KEPLER_COLOR_PALETTES = [
  ...COLORBREWER_PALETTES,
  ...D3_COLOR_PALETTES
];
function colorPaletteToColorRange(colorPalette, colorConfig) {
  const { steps, reversed } = colorConfig;
  const colors = colorPalette.colors(steps).slice();
  if (reversed) {
    colors.reverse();
  }
  return {
    name: colorPalette.name,
    type: colorPalette.type,
    category: colorPalette.category,
    colors,
    ...reversed ? { reversed } : {}
  };
}

// src/components/graph-view/GraphView.ts
var _GraphView = class _GraphView {
  constructor(app, settings, dataStore) {
    this.nodes = [];
    this.links = [];
    // Centrality state tracking
    this.centralityTypes = ["betweenness", "closeness", "eigenvector"];
    this.centralityState = {
      betweenness: false,
      closeness: false,
      eigenvector: false
    };
    this.lastCentralityScores = {};
    // Animation and timing constants
    this.ANIMATION = {
      DURATION: 200,
      RECENTER_DURATION: 300,
      TOOLTIP_DELAY: 500
    };
    // Node visualization constants
    this.NODE = {
      RADIUS: {
        SMALL_GRAPH: {
          BASE: 2,
          MAX: 4
        },
        MEDIUM_GRAPH: {
          BASE: 3,
          MAX: 6
        },
        LARGE_GRAPH: {
          BASE: 3,
          MAX: 9
        }
      },
      COLORS: {
        DEFAULT: "var(--graph-node-color-default)",
        HIGHLIGHTED: "var(--graph-node-color-highlighted)"
      },
      HIGHLIGHT_SCALE: 1.05,
      SIZE_CATEGORIES: 10
      // Using 10 categories for optimal visual distinction while maintaining meaningful degree variations
    };
    // Zoom behavior constants
    this.ZOOM = {
      OUT_SCALE_FACTOR: 600,
      IN_SCALE_FACTOR: 60,
      CONTAINER_SCALE: {
        MIN: 0.3,
        // Minimum scale (30% of viewport)
        MAX: 0.85,
        // Maximum scale (85% of viewport)
        NODE_SCALE_FACTOR: 600
        // Node count that represents mid-point of scaling
      }
    };
    // UI elements
    this.loadingIndicator = null;
    this.resizeObserver = null;
    this.visibilityObserver = null;
    this.lastVisibilityChange = 0;
    this.wasInvisible = false;
    this.graphMetadata = null;
    this.activeButton = null;
    this.isVisible = false;
    // Animation frame request reference
    this._frameRequest = null;
    this.highlightedNodeId = null;
    this._tooltipTimeout = null;
    this.isDraggingNode = false;
    // Neighbors cache to avoid repeated WASM calls
    this.cachedNeighbors = null;
    this.cachedNodeId = null;
    // Add this property at the class level after the private readonly constants section
    this.currentTooltip = null;
    // New tooltip timeout
    this._hideTooltipTimeout = null;
    // Control panel elements
    this.controlPanel = null;
    this.documentClickHandler = null;
    // Track selected gradients for each centrality type
    this.selectedPalettes = {
      betweenness: "Viridis",
      closeness: "Magma",
      eigenvector: "Plasma"
    };
    // Track gradient settings for each centrality type
    this.gradientSettings = {
      betweenness: { type: "sequential", reversed: false, steps: _GraphView.DEFAULT_GRADIENT_STEPS, distribution: "jenks" },
      closeness: { type: "sequential", reversed: false, steps: _GraphView.DEFAULT_GRADIENT_STEPS, distribution: "jenks" },
      eigenvector: { type: "sequential", reversed: false, steps: _GraphView.DEFAULT_GRADIENT_STEPS, distribution: "jenks" }
    };
    // Add color palette state
    this.colorPalettes = KEPLER_COLOR_PALETTES;
    // Add this as a class property after the NODE constant
    this.nodeRadiusScale = null;
    this.nodeRadiusCache = /* @__PURE__ */ new Map();
    this.cachedZoomLimits = null;
    this.cachedZoomLimitsWidth = 0;
    this.cachedZoomLimitsHeight = 0;
    // Display toggles for labels and arrows
    this.showNodeLabels = true;
    this.showArrows = true;
    this.markerIdDefault = "";
    this.markerIdHighlighted = "";
    this.app = app;
    this.pluginService = new PluginService(app);
    this.graphDataBuilder = new GraphDataBuilder(app);
    this.vaultAnalysisManager = new VaultSemanticAnalysisManager(app, settings, dataStore);
  }
  /** Window from container's document (avoids global window for pop-out compatibility) */
  get win() {
    return this.container.ownerDocument.defaultView;
  }
  isDarkTheme() {
    return this.container?.ownerDocument?.body?.classList?.contains("theme-dark") ?? true;
  }
  applyThemeDefaultPalettes() {
    const defaults = this.isDarkTheme() ? _GraphView.DEFAULT_PALETTES_DARK : _GraphView.DEFAULT_PALETTES_LIGHT;
    this.centralityTypes.forEach((type2) => {
      this.selectedPalettes[type2] = defaults[type2];
    });
  }
  async onload(container) {
    this.container = container;
    this.isVisible = true;
    this.applyThemeDefaultPalettes();
    this.initializeD3();
    this.createControlPanel();
    this.setupThemeChangeListener();
    this.setupVisibilityObserver();
    this.container.addClass("graph-initialized");
    this.showLoadingIndicator();
    try {
      await this.pluginService.ensureWasmLoaded();
      await this.loadVaultData();
    } catch (error) {
      new import_obsidian13.Notice(t("notices.graphLoadError", { message: error.message }));
    } finally {
      this.hideLoadingIndicator();
    }
  }
  initializeD3() {
    this.updateDimensions();
    this.svg = select_default2(this.container).append("svg").attr("width", "100%").attr("height", "100%").attr("viewBox", [
      -this.width / 2,
      // Center the viewBox at (0,0)
      -this.height / 2,
      this.width,
      this.height
    ].join(" ")).style("display", "block").style("max-width", "none").style("max-height", "none").attr("class", "graph-view-svg");
    this.svgGroup = this.svg.append("g");
    const defs = this.svg.append("defs");
    const markerAttrs = {
      markerUnits: "userSpaceOnUse",
      markerWidth: 4,
      markerHeight: 4,
      refX: 3,
      refY: 0,
      orient: "auto",
      viewBox: "0 -2 4 4"
    };
    this.markerIdDefault = `graph-arrow-default-${Date.now()}`;
    defs.append("marker").attr("id", this.markerIdDefault).attr("markerUnits", markerAttrs.markerUnits).attr("markerWidth", markerAttrs.markerWidth).attr("markerHeight", markerAttrs.markerHeight).attr("refX", markerAttrs.refX).attr("refY", markerAttrs.refY).attr("orient", markerAttrs.orient).attr("viewBox", markerAttrs.viewBox).append("path").attr("d", "M0,-1.5 L4,0 L0,1.5 Z").attr("fill", "var(--graph-link-color-default)");
    this.markerIdHighlighted = `graph-arrow-highlighted-${Date.now()}`;
    defs.append("marker").attr("id", this.markerIdHighlighted).attr("markerUnits", markerAttrs.markerUnits).attr("markerWidth", markerAttrs.markerWidth).attr("markerHeight", markerAttrs.markerHeight).attr("refX", markerAttrs.refX).attr("refY", markerAttrs.refY).attr("orient", markerAttrs.orient).attr("viewBox", markerAttrs.viewBox).append("path").attr("d", "M0,-1.5 L4,0 L0,1.5 Z").attr("fill", "var(--graph-link-color-highlighted)");
    const linksGroup = this.svgGroup.append("g").attr("class", "links-group").style("stroke", "var(--graph-link-color-default)").style("stroke-width", "var(--graph-link-width-default)").style("stroke-opacity", "var(--graph-link-opacity-default)");
    const nodesGroup = this.svgGroup.append("g").attr("class", "nodes-group").style("fill", "var(--graph-node-color-default)").style("opacity", "var(--graph-node-opacity-default)");
    const labelsGroup = this.svgGroup.append("g").attr("class", "labels-group");
    this.linksSelection = linksGroup.selectAll("line");
    this.nodesSelection = nodesGroup.selectAll("circle");
    this.labelsSelection = labelsGroup.selectAll("text");
    this.initializeSimulation();
    this.setupZoomBehavior();
    this.setupResizeObserver();
  }
  /**
   * Calculate dynamic zoom limits based on screen size and node radius
   * Centralized method to ensure consistent limits across the application
   * Results are cached and invalidated when nodes or dimensions change
   */
  calculateZoomLimits() {
    if (!this.nodes || this.nodes.length === 0) {
      this.cachedZoomLimits = null;
      return [0.1, 4];
    }
    if (this.cachedZoomLimits !== null && this.cachedZoomLimitsWidth === this.width && this.cachedZoomLimitsHeight === this.height) {
      return this.cachedZoomLimits;
    }
    let maxRadius = 0;
    let totalRadius = 0;
    const nodeCount = this.nodes.length;
    const baseRadius = this.NODE.RADIUS.SMALL_GRAPH.BASE;
    for (let i = 0; i < nodeCount; i++) {
      const radius = this.nodeRadiusCache.get(this.nodes[i].id) ?? baseRadius;
      maxRadius = Math.max(maxRadius, radius);
      totalRadius += radius;
    }
    const avgRadius = totalRadius / nodeCount;
    const baseOutScaleFactor = 600;
    const baseInScaleFactor = 60;
    const outScaleFactor = nodeCount < 100 ? baseOutScaleFactor / 2 : baseOutScaleFactor;
    const inScaleFactor = nodeCount < 100 ? baseInScaleFactor / 2 : baseInScaleFactor;
    let minZoom = this.width / (avgRadius * outScaleFactor);
    let maxZoom = this.width / (maxRadius * inScaleFactor);
    minZoom = Math.max(0.1, Math.min(minZoom, 1));
    maxZoom = Math.max(2, Math.min(maxZoom, 8));
    this.cachedZoomLimits = [minZoom, maxZoom];
    this.cachedZoomLimitsWidth = this.width;
    this.cachedZoomLimitsHeight = this.height;
    return this.cachedZoomLimits;
  }
  setupZoomBehavior() {
    this.zoom = zoom_default2().scaleExtent(this.calculateZoomLimits()).on("start", () => {
      if (this._frameRequest) {
        this.win.cancelAnimationFrame(this._frameRequest);
        this._frameRequest = null;
      }
      if (this.simulation) {
        this.simulation.alphaTarget(0);
      }
      this.container.addClass("zooming");
    }).on("zoom", (evt) => {
      const t2 = evt.transform;
      if (!isFinite(t2.x) || !isFinite(t2.y) || !isFinite(t2.k)) {
        return;
      }
      this.svgGroup.attr("transform", String(t2));
      if (!this._frameRequest) {
        this._frameRequest = this.win.requestAnimationFrame(() => {
          this.updateGraph();
          this._frameRequest = null;
        });
      }
    }).on("end", () => {
      this.container.removeClass("zooming");
    });
    this.svg.call(this.zoom);
  }
  /**
   * Initialize the force simulation with simplified forces similar to the D3 example
   */
  initializeSimulation() {
    this.simulation = simulation_default().force("link", link_default().id((d) => d.id).distance(50)).force("charge", manyBody_default().strength(-300)).force("x", x_default2().strength(0.8)).force("y", y_default2().strength(0.8)).force("collision", collide_default().radius((d) => this.getNodeRadius(d) + 1).strength(0.8)).alphaDecay(0.0228).velocityDecay(0.4).on("tick", () => {
      if (!this._frameRequest) {
        this._frameRequest = this.win.requestAnimationFrame(() => {
          this.updateGraph();
          this._frameRequest = null;
        });
      }
    });
  }
  /**
   * Gently restart the simulation with lower alpha
   */
  restartSimulationGently() {
    try {
      if (this.simulation) {
        this.simulation.alpha(0.3).restart();
      }
    } catch {
    }
  }
  /** Compute all four link endpoints at once (edge-to-edge for arrows) */
  linkEndpoints(d) {
    const s = d.source;
    const t2 = d.target;
    const sx = s.x ?? 0, sy = s.y ?? 0, tx = t2.x ?? 0, ty = t2.y ?? 0;
    const dx = tx - sx, dy = ty - sy;
    const len = Math.hypot(dx, dy) || 1;
    const nx = dx / len, ny = dy / len;
    const baseRadius = this.NODE.RADIUS.SMALL_GRAPH.BASE;
    const sr = this.nodeRadiusCache.get(s.id) ?? baseRadius;
    const tr = this.nodeRadiusCache.get(t2.id) ?? baseRadius;
    return [sx + nx * sr, sy + ny * sr, tx - nx * tr, ty - ny * tr];
  }
  updateGraph() {
    const linksSelection = this.linksSelection;
    const nodesSelection = this.nodesSelection;
    if (!linksSelection || !nodesSelection) return;
    if (this.showArrows) {
      linksSelection.each((d, i, nodes) => {
        const [x1, y1, x22, y22] = this.linkEndpoints(d);
        const el = nodes[i];
        el.setAttribute("x1", String(x1));
        el.setAttribute("y1", String(y1));
        el.setAttribute("x2", String(x22));
        el.setAttribute("y2", String(y22));
      });
    } else {
      linksSelection.attr("x1", (d) => d.source.x || 0).attr("y1", (d) => d.source.y || 0).attr("x2", (d) => d.target.x || 0).attr("y2", (d) => d.target.y || 0);
    }
    nodesSelection.attr("cx", (d) => d.x || 0).attr("cy", (d) => d.y || 0);
    if (this.showNodeLabels && this.labelsSelection && !this.labelsSelection.empty()) {
      this.labelsSelection.attr("x", (d) => d.x || 0).attr("y", (d) => (d.y || 0) + (this.nodeRadiusCache.get(d.id) ?? this.NODE.RADIUS.SMALL_GRAPH.BASE) + 5);
    }
  }
  updateDimensions() {
    if (!this.container || !this.container.isConnected) {
      return;
    }
    const rect = this.container.getBoundingClientRect();
    if (rect.width > 0 && rect.height > 0 && isFinite(rect.width) && isFinite(rect.height)) {
      this.width = rect.width;
      this.height = rect.height;
      this.cachedZoomLimits = null;
      if (this.zoom) {
        this.zoom.scaleExtent(this.calculateZoomLimits());
      }
    }
  }
  setupResizeObserver() {
    if (this.resizeObserver) {
      this.resizeObserver.disconnect();
    }
    this.resizeObserver = new ResizeObserver((entries) => {
      const containerEntry = entries.find((entry) => entry.target === this.container);
      if (!containerEntry) return;
      if (!this.container || !this.svg || !this.svgGroup) {
        if (this.resizeObserver) {
          this.resizeObserver.disconnect();
          this.resizeObserver = null;
        }
        return;
      }
      try {
        const rect = this.container.getBoundingClientRect();
        this.width = rect.width;
        this.height = rect.height;
        if (!isFinite(this.width) || !isFinite(this.height) || this.width <= 0 || this.height <= 0) {
          return;
        }
        this.svg.attr("viewBox", [
          -this.width / 2,
          -this.height / 2,
          this.width,
          this.height
        ].join(" "));
        if (this.nodes.length > 0 && this.simulation) {
          this.recenterGraph(false);
        }
      } catch {
        if (this.resizeObserver) {
          this.resizeObserver.disconnect();
          this.resizeObserver = null;
        }
      }
    });
    if (this.container) {
      this.resizeObserver.observe(this.container);
    }
  }
  setupNodeEventHandlers() {
    this.nodesSelection.on("mouseover", this.onNodeMouseOver.bind(this)).on("mouseout", this.onNodeMouseOut.bind(this)).on("click", this.onNodeClick.bind(this));
  }
  onNodeMouseOver(event, d) {
    if (this.isDraggingNode) return;
    if (this._hideTooltipTimeout) {
      this.win.clearTimeout(this._hideTooltipTimeout);
      this._hideTooltipTimeout = null;
    }
    this.highlightedNodeId = d.id;
    this.highlightNode(event.currentTarget, true);
    this.highlightConnections(d.id, true);
    if (!this.isDraggingNode) {
      this.scheduleTooltip(d, event);
    }
  }
  onNodeMouseOut(event, d) {
    if (this.isDraggingNode) return;
    this.highlightNode(event.currentTarget, false);
    this.highlightConnections(d.id, false);
    this.scheduleTooltipRemoval();
    this.highlightedNodeId = null;
  }
  onNodeClick(event, d) {
    event.stopPropagation();
    if (d.path) {
      const file = this.app.vault.getAbstractFileByPath(d.path);
      if (file instanceof import_obsidian13.TFile) {
        void this.app.workspace.getLeaf(false).openFile(file);
      }
    }
  }
  removeNodeTooltip() {
    if (this.currentTooltip) {
      this.currentTooltip.remove();
      this.currentTooltip = null;
    }
  }
  createTooltip(node, event) {
    this.removeNodeTooltip();
    const tooltip = this.container.createDiv({ cls: "graph-node-tooltip" });
    this.currentTooltip = tooltip;
    tooltip.addEventListener("mouseenter", () => {
      if (this._hideTooltipTimeout) {
        this.win.clearTimeout(this._hideTooltipTimeout);
        this._hideTooltipTimeout = null;
      }
    });
    tooltip.addEventListener("mouseleave", () => {
      this.scheduleTooltipRemoval();
    });
    tooltip.createEl("h4", { text: node.name, cls: "node-tooltip-title" });
    const metadataContainer = tooltip.createDiv({ cls: "metadata-container" });
    if (node.path) {
      const file = this.app.vault.getAbstractFileByPath(node.path);
      if (file instanceof import_obsidian13.TFile) {
        const metadata = this.app.metadataCache.getFileCache(file);
        const createdField = metadataContainer.createDiv({ cls: "metadata-field" });
        createdField.createSpan({ text: t("graph.tooltip.created"), cls: "metadata-label" });
        createdField.createSpan({
          text: new Date(file.stat.ctime).toLocaleString(),
          cls: "metadata-value"
        });
        const modifiedField = metadataContainer.createDiv({ cls: "metadata-field" });
        modifiedField.createSpan({ text: t("graph.tooltip.modified"), cls: "metadata-label" });
        modifiedField.createSpan({
          text: new Date(file.stat.mtime).toLocaleString(),
          cls: "metadata-value"
        });
        const sizeField = metadataContainer.createDiv({ cls: "metadata-field" });
        sizeField.createSpan({ text: t("graph.tooltip.size"), cls: "metadata-label" });
        sizeField.createSpan({
          text: `${(file.stat.size / 1024).toFixed(2)} KB`,
          cls: "metadata-value"
        });
        if (metadata && metadata.tags && metadata.tags.length > 0) {
          const tagsField = metadataContainer.createDiv({ cls: "metadata-field" });
          tagsField.createSpan({ text: t("graph.tooltip.tags"), cls: "metadata-label" });
          const tagsContainer = tagsField.createSpan({ cls: "metadata-value metadata-tags" });
          metadata.tags.forEach((tag) => {
            tagsContainer.createSpan({
              text: tag.tag,
              cls: "metadata-tag"
            });
          });
        }
        if (metadata && metadata.frontmatter) {
          const frontmatterField = metadataContainer.createDiv({ cls: "metadata-section" });
          const frontmatterContent = frontmatterField.createDiv({ cls: "frontmatter-content" });
          const excludedProps = ["position", "cssclass", "tag", "tags"];
          Object.entries(metadata.frontmatter).forEach(([key, value]) => {
            if (!excludedProps.includes(key.toLowerCase())) {
              const propDiv = frontmatterContent.createDiv({ cls: "metadata-field" });
              propDiv.createSpan({
                text: `${key}: `,
                cls: "metadata-label"
              });
              let displayValue;
              if (value === null || value === void 0) {
                displayValue = "";
              } else if (Array.isArray(value)) {
                displayValue = value.join(", ");
              } else if (typeof value === "object") {
                try {
                  displayValue = JSON.stringify(value);
                } catch {
                  displayValue = "[Object]";
                }
              } else {
                displayValue = String(value);
              }
              propDiv.createSpan({
                text: displayValue,
                cls: "metadata-value"
              });
            }
          });
        }
        const actionHint = metadataContainer.createDiv({ cls: "action-hint" });
        const openNoteBtn = actionHint.createEl("button", {
          text: t("graph.tooltip.openNote"),
          cls: "open-note-button"
        });
        openNoteBtn.addEventListener("click", (ev) => {
          ev.preventDefault();
          ev.stopPropagation();
          if (node.path) {
            const file2 = this.app.vault.getAbstractFileByPath(node.path);
            if (file2 instanceof import_obsidian13.TFile) {
              void this.app.workspace.getLeaf().openFile(file2);
            }
          }
        });
        const previewSection = tooltip.createDiv({ cls: "note-preview-section" });
        previewSection.createEl("div", {
          text: t("graph.tooltip.notePreview"),
          cls: "preview-section-title"
        });
        const previewContent = previewSection.createDiv({ cls: "preview-content" });
        void this.app.vault.read(file).then((content) => {
          if (this.currentTooltip !== tooltip) return;
          const previewText = this.formatNotePreview(content);
          previewContent.setText(previewText);
        }).catch(() => {
          if (this.currentTooltip !== tooltip) return;
          previewContent.setText(t("graph.tooltip.previewFailed"));
          previewContent.classList.add("metadata-error-text");
        });
      } else {
        const noteInfo = metadataContainer.createDiv({ cls: "metadata-error" });
        noteInfo.createSpan({
          text: t("graph.tooltip.noteNotFound"),
          cls: "metadata-error-text"
        });
      }
    } else {
      const errorInfo = metadataContainer.createDiv({ cls: "metadata-error" });
      errorInfo.createSpan({
        text: t("graph.tooltip.noFilePath"),
        cls: "metadata-error-text"
      });
    }
    const containerRect = this.container.getBoundingClientRect();
    this.positionTooltip(tooltip, event.clientX - containerRect.left, event.clientY - containerRect.top, containerRect);
  }
  /** Raw content: strip frontmatter, condense empty lines, keep one blank line before each heading, truncate to 900 chars. */
  formatNotePreview(content) {
    const withoutFrontmatter = content.replace(/^---[\s\S]*?---\n/m, "");
    const condensed = withoutFrontmatter.replace(/\n{2,}/g, "\n").trim();
    const withHeadingSpacing = condensed.replace(/([^\n])\n(#{1,6}\s)/g, "$1\n\n$2").replace(/^\n(#{1,6}\s)/, "\n\n$1");
    return withHeadingSpacing.slice(0, 900) + (withHeadingSpacing.length > 900 ? "..." : "");
  }
  getTooltipSetting(settingName) {
    const workspace = this.container.ownerDocument.querySelector(".workspace");
    if (!workspace) {
      return 0;
    }
    const value = this.win.getComputedStyle(workspace).getPropertyValue(`--graph-tooltip-${settingName}`).trim();
    return parseInt(value) || 0;
  }
  positionTooltip(tooltip, mouseX, mouseY, containerRect) {
    const tooltipWidth = this.getTooltipSetting("width");
    const tooltipHeight = this.getTooltipSetting("height");
    const offsetX = this.getTooltipSetting("offset-x");
    const offsetY = this.getTooltipSetting("offset-y");
    let tooltipX = mouseX + offsetX;
    let tooltipY = mouseY + offsetY;
    if (tooltipX + tooltipWidth > containerRect.width) {
      tooltipX = mouseX - offsetX - tooltipWidth;
    }
    if (tooltipY + tooltipHeight > containerRect.height) {
      tooltipY = mouseY - offsetY - tooltipHeight;
    }
    tooltip.style.setProperty("--graph-tooltip-x", `${tooltipX}px`);
    tooltip.style.setProperty("--graph-tooltip-y", `${tooltipY}px`);
    tooltip.classList.add("graph-node-tooltip-visible");
  }
  highlightConnections(nodeId, highlight) {
    if (!highlight && this.isDraggingNode && this.highlightedNodeId === nodeId) {
      return;
    }
    if (!highlight) {
      this.resetHighlights();
      return;
    }
    const animationDuration = this.ANIMATION.DURATION;
    let connectedNodeIds = /* @__PURE__ */ new Set();
    const nodeIdInt = parseInt(nodeId);
    const cacheValid = this.cachedNodeId === nodeIdInt && this.cachedNeighbors !== null;
    if (this.isDraggingNode && this.highlightedNodeId === nodeId || cacheValid) {
      if (this.cachedNeighbors) {
        connectedNodeIds = this.cachedNeighbors;
      }
    } else {
      try {
        const neighborResult = this.pluginService.getNodeNeighbors(nodeIdInt);
        if (neighborResult && neighborResult.neighbors) {
          neighborResult.neighbors.forEach((neighbor) => {
            connectedNodeIds.add(neighbor.node_id);
          });
          this.cachedNodeId = nodeIdInt;
          this.cachedNeighbors = connectedNodeIds;
        } else {
          throw new Error("Unexpected result format from WASM");
        }
      } catch {
        this.cachedNodeId = null;
        this.cachedNeighbors = null;
        return;
      }
    }
    const isCentralityActive = Object.values(this.centralityState).some((state) => state);
    const scaleFactor = this.NODE.HIGHLIGHT_SCALE;
    const getRadius = (n) => this.getNodeRadius(n);
    this.nodesSelection.each(function(d) {
      const isSelected = d.id === nodeId;
      const isConnected = isSelected || connectedNodeIds.has(parseInt(d.id));
      const selection2 = select_default2(this);
      const baseRadius = getRadius(d);
      const radius = isSelected ? baseRadius * scaleFactor : baseRadius;
      const trans = selection2.transition().duration(animationDuration);
      trans.attr("r", radius);
      trans.style("opacity", isConnected ? "var(--graph-node-opacity-default)" : "var(--graph-node-opacity-dimmed)");
      if (!isCentralityActive) {
        trans.style("fill", isSelected ? "var(--graph-node-color-highlighted)" : "var(--graph-node-color-default)");
      }
    });
    const showArrows = this.showArrows;
    const markerIdDefault = this.markerIdDefault;
    const markerIdHighlighted = this.markerIdHighlighted;
    this.linksSelection.each(function(d) {
      const sourceId = typeof d.source === "string" ? d.source : d.source.id;
      const targetId = typeof d.target === "string" ? d.target : d.target.id;
      const isConnected = sourceId === nodeId || targetId === nodeId;
      const sel = select_default2(this).transition().duration(animationDuration).style("stroke", isConnected ? "var(--graph-link-color-highlighted)" : "var(--graph-link-color-default)").style("stroke-width", isConnected ? "var(--graph-link-width-highlighted)" : "var(--graph-link-width-default)").style("stroke-opacity", isConnected ? "var(--graph-link-opacity-default)" : "var(--graph-link-opacity-dimmed)");
      if (showArrows) {
        sel.attr("marker-end", isConnected ? `url(#${markerIdHighlighted})` : `url(#${markerIdDefault})`);
      }
    });
  }
  resetHighlights() {
    this.cachedNodeId = null;
    this.cachedNeighbors = null;
    const animationDuration = this.ANIMATION.DURATION;
    const isCentralityActive = Object.values(this.centralityState).some((state) => state);
    const resetTrans = this.nodesSelection.transition().duration(animationDuration);
    resetTrans.style("opacity", "var(--graph-node-opacity-default)");
    resetTrans.attr("r", (d) => this.getNodeRadius(d));
    if (!isCentralityActive) {
      resetTrans.style("fill", "var(--graph-node-color-default)");
    }
    this.linksSelection.transition().duration(animationDuration).style("stroke-opacity", "var(--graph-link-opacity-default)").style("stroke-width", "var(--graph-link-width-default)").style("stroke", "var(--graph-link-color-default)").attr("marker-end", this.showArrows ? `url(#${this.markerIdDefault})` : null);
  }
  setupDragBehavior() {
    return drag_default().on("start", (event, d) => {
      if (!event.active && this.simulation) {
        this.simulation.alphaTarget(0.3).restart();
      }
      d.fx = d.x ?? null;
      d.fy = d.y ?? null;
      this.isDraggingNode = true;
      this.container.ownerDocument.body.addClass("graph-view-dragging");
      this.clearTooltipTimeout();
      this.removeNodeTooltip();
      this.highlightedNodeId = d.id;
      const target = event.sourceEvent.currentTarget;
      this.highlightNode(target, true);
      this.highlightConnections(d.id, true);
    }).on("drag", (event, d) => {
      d.fx = event.x;
      d.fy = event.y;
      if (this.highlightedNodeId !== d.id) {
        this.highlightedNodeId = d.id;
        const target = event.sourceEvent.currentTarget;
        this.highlightNode(target, true);
        this.highlightConnections(d.id, true);
      }
    }).on("end", (event, d) => {
      if (!event.active && this.simulation) {
        this.simulation.alphaTarget(0);
      }
      const sourceEvent = event.sourceEvent;
      if (!sourceEvent.shiftKey) {
        d.fx = null;
        d.fy = null;
      }
      this.isDraggingNode = false;
      this.container.ownerDocument.body.removeClass("graph-view-dragging");
      const element = sourceEvent.target;
      const bounds = element.getBoundingClientRect();
      const mouseX = sourceEvent.clientX;
      const mouseY = sourceEvent.clientY;
      const isMouseOver = mouseX >= bounds.left && mouseX <= bounds.right && mouseY >= bounds.top && mouseY <= bounds.bottom;
      if (!isMouseOver) {
        this.win.setTimeout(() => {
          if (!this.isDraggingNode && this.highlightedNodeId === d.id) {
            this.highlightNode(element, false);
            this.highlightConnections(d.id, false);
            this.highlightedNodeId = null;
          }
        }, this.ANIMATION.DURATION);
      }
    });
  }
  /**
   * Apply or remove visual highlighting from a node element
   */
  highlightNode(element, highlight) {
    const node = select_default2(element);
    const datum2 = node.datum();
    const baseRadius = this.getNodeRadius(datum2);
    const isCentralityActive = Object.values(this.centralityState).some((state) => state);
    const trans = node.transition().duration(this.ANIMATION.DURATION);
    trans.attr("r", highlight ? baseRadius * this.NODE.HIGHLIGHT_SCALE : baseRadius);
    if (!isCentralityActive) {
      trans.style("fill", highlight ? "var(--graph-node-color-highlighted)" : "var(--graph-node-color-default)");
    }
  }
  /**
   * Schedule tooltip display after delay
   */
  scheduleTooltip(node, event) {
    this.clearTooltipTimeout();
    if (this.highlightedNodeId !== node.id) return;
    this._tooltipTimeout = this.win.setTimeout(() => {
      if (this.highlightedNodeId === node.id) {
        this.createTooltip(node, event);
      }
      this._tooltipTimeout = null;
    }, this.ANIMATION.TOOLTIP_DELAY);
  }
  /**
   * Clear tooltip timeout if it exists
   */
  clearTooltipTimeout() {
    if (this._tooltipTimeout) {
      this.win.clearTimeout(this._tooltipTimeout);
      this._tooltipTimeout = null;
    }
  }
  async loadVaultData() {
    const { graphData, degreeCentrality, metadata } = await this.graphDataBuilder.buildGraphData();
    this.graphMetadata = metadata;
    const degreeMap = /* @__PURE__ */ new Map();
    if (degreeCentrality) {
      for (const r of degreeCentrality) {
        if (r?.centrality?.degree !== void 0) {
          degreeMap.set(r.node_id, r.centrality.degree);
        }
      }
    }
    const nodes = graphData.nodes.map((nodePath, index2) => {
      const fileName = nodePath.split("/").pop() || nodePath;
      const displayName = fileName.replace(".md", "");
      const degreeCentralityScore = degreeMap.get(index2) ?? 0;
      return {
        id: index2.toString(),
        name: displayName,
        path: nodePath,
        degreeCentrality: degreeCentralityScore,
        x: void 0,
        y: void 0,
        vx: void 0,
        vy: void 0,
        fx: void 0,
        fy: void 0
      };
    });
    const links = graphData.edges.map(([sourceIdx, targetIdx]) => ({
      source: sourceIdx.toString(),
      target: targetIdx.toString()
    }));
    await this.updateData({ nodes, links });
  }
  updateData(graphData) {
    this.cachedZoomLimits = null;
    this.nodes = graphData.nodes || [];
    this.links = graphData.links || [];
    this.initializeNodeRadiusScale();
    this.cachedNodeId = null;
    this.cachedNeighbors = null;
    this.linksSelection = this.svgGroup.select(".links-group").selectAll("line").data(this.links, (d) => {
      const sid = typeof d.source === "string" ? d.source : d.source.id;
      const tid = typeof d.target === "string" ? d.target : d.target.id;
      return `${sid}-${tid}`;
    }).join(
      (enter) => enter.append("line").style("stroke", "var(--graph-link-color-default)").style("stroke-width", "var(--graph-link-width-default)").style("stroke-opacity", "var(--graph-link-opacity-default)").attr("class", "graph-link").attr("marker-end", this.showArrows ? `url(#${this.markerIdDefault})` : null),
      (update) => update.attr("marker-end", this.showArrows ? `url(#${this.markerIdDefault})` : null),
      (exit) => exit.remove()
    );
    this.nodesSelection = this.svgGroup.select(".nodes-group").selectAll("circle").data(this.nodes, (d) => d.id).join(
      (enter) => {
        const nodeEnter = enter.append("circle").attr("r", (d) => this.getNodeRadius(d)).style("fill", "var(--graph-node-color-default)").style("opacity", "var(--graph-node-opacity-default)").call(this.setupDragBehavior());
        nodeEnter.style("fill", (d) => d.highlighted ? "var(--graph-node-color-highlighted)" : "var(--graph-node-color-default)").style("opacity", (d) => d.dimmed ? "var(--graph-node-opacity-dimmed)" : "var(--graph-node-opacity-default)");
        return nodeEnter;
      },
      (update) => update,
      (exit) => exit.remove()
    );
    this.labelsSelection = this.svgGroup.select(".labels-group").selectAll("text").data(this.nodes, (d) => d.id).join(
      (enter) => {
        const textEnter = enter.append("text").attr("class", "graph-node-label-svg").attr("text-anchor", "middle").attr("x", (d) => d.x ?? 0).attr("y", (d) => (d.y ?? 0) + this.getNodeRadius(d) + 5).text((d) => {
          const name = d.name ?? "";
          if (name.length > 30) return name.slice(0, 27) + "...";
          return name;
        }).style("pointer-events", "none");
        if (!this.showNodeLabels) textEnter.style("display", "none");
        return textEnter;
      },
      (update) => {
        const textUpdate = update.attr("x", (d) => d.x ?? 0).attr("y", (d) => (d.y ?? 0) + this.getNodeRadius(d) + 5);
        if (this.showNodeLabels) textUpdate.style("display", null);
        else textUpdate.style("display", "none");
        return textUpdate;
      },
      (exit) => exit.remove()
    );
    this.setupNodeEventHandlers();
    if (this.simulation) {
      const radius = Math.min(this.width, this.height) / 6;
      const angleStep = 2 * Math.PI / this.nodes.length;
      const nodeCount = this.nodes.length;
      for (let i = 0; i < nodeCount; i++) {
        const node = this.nodes[i];
        const angle = i * angleStep;
        node.x = Math.cos(angle) * radius;
        node.y = Math.sin(angle) * radius;
        node.fx = null;
        node.fy = null;
      }
      this.simulation.nodes(this.nodes);
      const linkForce = this.simulation.force("link");
      if (linkForce) {
        linkForce.links(this.links);
      }
      this.recenterGraph(false);
      this.simulation.alpha(1).alphaTarget(0.3).restart();
      this.recenterGraph(true);
      this.simulation.on("tick.init", () => {
        if (this.simulation.alpha() < 0.1) {
          this.simulation.on("tick.init", null);
          this.simulation.alphaTarget(0);
        }
      });
    }
    return Promise.resolve();
  }
  /**
   * Initialize the node radius scale using Jenks natural breaks
   * This ensures orphan nodes (degree 0) map to the smallest radius
   * This should be called when the graph data is updated
   */
  initializeNodeRadiusScale() {
    if (!this.nodes.length) {
      this.nodeRadiusCache.clear();
      return;
    }
    const degrees3 = this.nodes.map((n) => n.degreeCentrality).filter((d) => d !== void 0);
    if (degrees3.length === 0) {
      this.nodeRadiusCache.clear();
      return;
    }
    const breaks = jenks(degrees3, this.NODE.SIZE_CATEGORIES);
    let minRadius;
    let maxRadius;
    if (this.nodes.length <= 20) {
      minRadius = this.NODE.RADIUS.SMALL_GRAPH.BASE;
      maxRadius = this.NODE.RADIUS.SMALL_GRAPH.MAX;
    } else if (this.nodes.length <= 100) {
      minRadius = this.NODE.RADIUS.MEDIUM_GRAPH.BASE;
      maxRadius = this.NODE.RADIUS.MEDIUM_GRAPH.MAX;
    } else {
      minRadius = this.NODE.RADIUS.LARGE_GRAPH.BASE;
      maxRadius = this.NODE.RADIUS.LARGE_GRAPH.MAX;
    }
    const radiusSteps = Array.from({ length: breaks.length }, (_, i) => {
      const t2 = i / (breaks.length - 1);
      return minRadius + (maxRadius - minRadius) * t2;
    });
    this.nodeRadiusScale = threshold().domain(breaks.slice(1)).range(radiusSteps);
    this.nodeRadiusCache.clear();
    const baseRadius = this.NODE.RADIUS.SMALL_GRAPH.BASE;
    for (const node of this.nodes) {
      const radius = this.nodeRadiusScale(node.degreeCentrality);
      this.nodeRadiusCache.set(node.id, radius ?? baseRadius);
    }
  }
  /**
   * Calculate node radius based on centrality and other factors
   * Uses cached values when available for performance
   */
  getNodeRadius(node) {
    if (!node) {
      return this.NODE.RADIUS.SMALL_GRAPH.BASE;
    }
    return this.nodeRadiusCache.get(node.id) ?? this.NODE.RADIUS.SMALL_GRAPH.BASE;
  }
  refreshGraphView() {
    if (!this.container || !this.container.isConnected || !this.isVisible) {
      return;
    }
    const rect = this.container.getBoundingClientRect();
    if (rect.width <= 0 || rect.height <= 0) {
      return;
    }
    this.updateDimensions();
    this.recenterGraph();
  }
  /**
   * Reload vault data and refresh the graph visualization
   * Called when user switches back to the graph view to ensure data is up to date
   */
  async reloadVaultData() {
    if (!this.container || !this.container.isConnected) {
      return;
    }
    try {
      this.showLoadingIndicator();
      await this.loadVaultData();
    } catch (err) {
      new import_obsidian13.Notice(t("notices.graphReloadError", {
        message: err instanceof Error ? err.message : String(err)
      }));
    } finally {
      this.hideLoadingIndicator();
    }
  }
  updateSettings(settings) {
    this.vaultAnalysisManager.updateSettings(settings);
    void this.reloadVaultData();
  }
  recenterGraph(animate = true) {
    if (this.nodes.length === 0) return;
    if (!this.container || !this.container.isConnected) {
      return;
    }
    if (!isFinite(this.width) || !isFinite(this.height) || this.width <= 0 || this.height <= 0) {
      return;
    }
    let minX = Infinity, minY = Infinity;
    let maxX = -Infinity, maxY = -Infinity;
    const nodeCount = this.nodes.length;
    for (let i = 0; i < nodeCount; i++) {
      const node = this.nodes[i];
      if (node.x === void 0 || node.y === void 0) continue;
      const radius = this.getNodeRadius(node);
      minX = Math.min(minX, node.x - radius);
      minY = Math.min(minY, node.y - radius);
      maxX = Math.max(maxX, node.x + radius);
      maxY = Math.max(maxY, node.y + radius);
    }
    if (!isFinite(minX) || !isFinite(minY)) return;
    const graphWidth = maxX - minX;
    const graphHeight = maxY - minY;
    if (graphWidth === 0 || graphHeight === 0) return;
    const containerScale = this.calculateOptimalContainerScale();
    const minDimension = Math.min(this.width, this.height);
    const targetSize = minDimension * containerScale;
    const scale = targetSize / Math.max(graphWidth, graphHeight);
    if (!isFinite(scale) || scale <= 0) {
      return;
    }
    const centerX = minX + graphWidth / 2;
    const centerY = minY + graphHeight / 2;
    if (!isFinite(centerX) || !isFinite(centerY)) {
      return;
    }
    const transform2 = identity3.translate(-centerX * scale, -centerY * scale).scale(scale);
    if (!isFinite(transform2.x) || !isFinite(transform2.y) || !isFinite(transform2.k)) {
      return;
    }
    const zoomTransform = this.zoom.transform.bind(this.zoom);
    if (animate) {
      this.svg.transition().duration(this.ANIMATION.RECENTER_DURATION).call(zoomTransform, transform2);
    } else {
      this.svg.call(zoomTransform, transform2);
    }
  }
  setupVisibilityObserver() {
    if (this.visibilityObserver) {
      this.visibilityObserver.disconnect();
    }
    this.visibilityObserver = new IntersectionObserver(
      (entries) => {
        const now2 = this.win.performance.now();
        const entry = entries[0];
        if (entry.isIntersecting && this.wasInvisible) {
          this.isVisible = true;
          if (now2 - this.lastVisibilityChange > 1e3) {
            this.recenterGraph();
            this.restartSimulationGently();
          }
          this.wasInvisible = false;
        } else if (!entry.isIntersecting) {
          this.isVisible = false;
          this.wasInvisible = true;
        }
        this.lastVisibilityChange = now2;
      },
      { threshold: 0.1 }
      // Trigger when at least 10% is visible
    );
    this.visibilityObserver.observe(this.container);
  }
  setupThemeChangeListener() {
    const doc = this.container.ownerDocument;
    const win = doc.defaultView;
    this._themeChangeHandler = () => {
      if (this._themeChangeTimeout) {
        win.clearTimeout(this._themeChangeTimeout);
      }
      this._themeChangeTimeout = win.setTimeout(() => {
        this.applyThemeDefaultPalettes();
        this.refreshGradientPreviewsOnThemeChange();
        this.centralityTypes.forEach((type2) => {
          if (this.centralityState[type2]) {
            void this.calculateAndDisplayCentrality(type2);
          }
        });
      }, 150);
    };
    this._themeObserver = new MutationObserver((mutations) => {
      for (const mutation of mutations) {
        if (mutation.type === "attributes" && mutation.attributeName === "class" && mutation.target === doc.body) {
          const classList2 = mutation.target.className;
          if (classList2.includes("theme-") || classList2.includes("color-scheme-")) {
            this._themeChangeHandler?.();
          }
          break;
        }
      }
    });
    this._themeObserver.observe(doc.body, {
      attributes: true,
      attributeFilter: ["class"]
    });
  }
  refreshGradientPreviewsOnThemeChange() {
    const sections = this.container.querySelectorAll(".gradient-section");
    this.centralityTypes.forEach((type2, i) => {
      const section = sections[i];
      const preview = section?.querySelector(".gradient-preview");
      if (preview instanceof HTMLElement) {
        this.updateGradientPreview(preview, this.selectedPalettes[type2], type2);
      }
      const optionsContainer = section?.querySelector(".gradient-options");
      if (optionsContainer) {
        optionsContainer.querySelectorAll(".gradient-option").forEach((opt) => {
          opt.classList.toggle("selected", opt.dataset.paletteName === this.selectedPalettes[type2]);
        });
      }
    });
  }
  showLoadingIndicator() {
    this.loadingIndicator = this.container.createDiv({ cls: "graph-loading-indicator" });
    this.loadingIndicator.setText(t("graph.loading"));
    return this.loadingIndicator;
  }
  hideLoadingIndicator() {
    if (this.loadingIndicator) {
      this.loadingIndicator.remove();
      this.loadingIndicator = null;
    }
  }
  onunload() {
    if (this.documentClickHandler) {
      this.container.ownerDocument.removeEventListener("click", this.documentClickHandler);
      this.documentClickHandler = null;
    }
    if (this._frameRequest) {
      this.win.cancelAnimationFrame(this._frameRequest);
      this._frameRequest = null;
    }
    if (this._tooltipTimeout) {
      this.win.clearTimeout(this._tooltipTimeout);
      this._tooltipTimeout = null;
    }
    if (this._themeObserver) {
      this._themeObserver.disconnect();
      this._themeObserver = void 0;
    }
    if (this._themeChangeTimeout) {
      this.win.clearTimeout(this._themeChangeTimeout);
      this._themeChangeTimeout = void 0;
    }
    this.removeNodeTooltip();
    if (this.loadingIndicator) {
      this.loadingIndicator.remove();
      this.loadingIndicator = null;
    }
    const centralityLeaf = this.app.workspace.getLeavesOfType(CENTRALITY_RESULTS_VIEW_TYPE)[0];
    if (centralityLeaf) {
      centralityLeaf.detach();
      const rightSplit = this.app.workspace.rightSplit;
      if (rightSplit && rightSplit.collapsed === false) {
        rightSplit.collapse();
      }
    }
    this.cachedNodeId = null;
    this.cachedNeighbors = null;
    this.nodeRadiusCache.clear();
    this.nodes = [];
    this.links = [];
    if (this.simulation) {
      this.simulation.stop();
      ["link", "charge", "x", "y", "collision"].forEach(
        (force) => this.simulation.force(force, null)
      );
      this.simulation.nodes([]);
      this.simulation = null;
    }
    if (this.resizeObserver) {
      this.resizeObserver.disconnect();
      this.resizeObserver = null;
    }
    if (this.visibilityObserver) {
      this.visibilityObserver.disconnect();
      this.visibilityObserver = null;
    }
    if (this.nodesSelection) {
      this.nodesSelection.on("mouseover", null).on("mouseout", null).on("click", null);
    }
    if (this.svg) {
      this.svg.on(".zoom", null);
      this.svg.selectAll("*").remove();
      this.svg.remove();
      this.svgGroup = null;
      this.zoom = null;
      this.nodesSelection = void 0;
      this.linksSelection = void 0;
      this.labelsSelection = void 0;
      this.svg = null;
    }
    if (this.controlPanel) {
      this.controlPanel.remove();
      this.controlPanel = null;
    }
    this.container = null;
    this.graphDataBuilder = null;
    this.pluginService = null;
    this.vaultAnalysisManager = null;
    this.app = null;
  }
  scheduleTooltipRemoval() {
    this.clearTooltipTimeout();
    if (this._hideTooltipTimeout) {
      this.win.clearTimeout(this._hideTooltipTimeout);
    }
    this._hideTooltipTimeout = this.win.setTimeout(() => {
      const tooltip = this.currentTooltip;
      if (tooltip && !tooltip.matches(":hover")) {
        this.removeNodeTooltip();
      }
      this._hideTooltipTimeout = null;
    }, this.getTooltipSetting("hide-delay"));
  }
  createControlPanel() {
    this.controlPanel = this.container.createDiv({ cls: "centrality-control-panel" });
    this.createColorSettingsButton();
    this.centralityTypes.forEach((type2) => {
      this.createCentralityButton(type2);
    });
    const vaultAnalysisContainer = this.container.createDiv({ cls: "vault-analysis-container" });
    this.vaultAnalysisManager.createGraphViewButton(vaultAnalysisContainer);
  }
  createColorSettingsButton() {
    const settingsButton = this.container.createDiv({ cls: "color-settings-button" });
    (0, import_obsidian13.setIcon)(settingsButton, "settings-2");
    const dropdown = this.container.createDiv({ cls: "color-settings-dropdown" });
    const displaySection = dropdown.createDiv({ cls: "graph-settings-display-section" });
    displaySection.createDiv({ cls: "graph-settings-section-title", text: t("graph.display") });
    const labelsRow = displaySection.createDiv({ cls: "graph-settings-toggle-row" });
    labelsRow.createDiv({ cls: "graph-settings-toggle-label", text: t("graph.labels") });
    const labelsTrack = labelsRow.createDiv({ cls: "graph-settings-toggle-switch" });
    const labelsToggle = labelsTrack.createDiv({ cls: `toggle-track ${this.showNodeLabels ? "active" : ""}` });
    labelsToggle.createDiv({ cls: "toggle-handle" });
    labelsToggle.addEventListener("click", (e) => {
      e.stopPropagation();
      this.toggleNodeLabels(!this.showNodeLabels);
      labelsToggle.classList.toggle("active", this.showNodeLabels);
    });
    const arrowsRow = displaySection.createDiv({ cls: "graph-settings-toggle-row" });
    arrowsRow.createDiv({ cls: "graph-settings-toggle-label", text: t("graph.arrows") });
    const arrowsTrack = arrowsRow.createDiv({ cls: "graph-settings-toggle-switch" });
    const arrowsToggle = arrowsTrack.createDiv({ cls: `toggle-track ${this.showArrows ? "active" : ""}` });
    arrowsToggle.createDiv({ cls: "toggle-handle" });
    arrowsToggle.addEventListener("click", (e) => {
      e.stopPropagation();
      this.toggleArrows(!this.showArrows);
      arrowsToggle.classList.toggle("active", this.showArrows);
    });
    this.centralityTypes.forEach((type2) => {
      const section = dropdown.createDiv({ cls: "gradient-section" });
      section.createDiv({
        cls: "gradient-section-title",
        text: type2
      });
      const preview = section.createDiv({ cls: "gradient-preview" });
      this.updateGradientPreview(preview, this.selectedPalettes[type2], type2);
      const optionsContainer = section.createDiv({ cls: "gradient-options" });
      const controls = optionsContainer.createDiv({ cls: "gradient-controls" });
      const typeRow = controls.createDiv({ cls: "gradient-control-row" });
      typeRow.createDiv({ cls: "gradient-control-label", text: t("graph.type") });
      const typeSelect = typeRow.createDiv({ cls: "gradient-control-input" }).createEl("select");
      ["sequential", "diverging", "cyclical", "qualitative"].forEach((t2) => {
        const option = typeSelect.createEl("option", { value: t2, text: t2 });
        if (t2 === this.gradientSettings[type2].type) {
          option.selected = true;
        }
      });
      const distributionRow = controls.createDiv({ cls: "gradient-control-row" });
      distributionRow.createDiv({ cls: "gradient-control-label", text: t("graph.scale") });
      const distributionSelect = distributionRow.createDiv({ cls: "gradient-control-input" }).createEl("select");
      ["linear", "quantize", "jenks"].forEach((d) => {
        const option = distributionSelect.createEl("option", { value: d, text: d });
        if (d === this.gradientSettings[type2].distribution) {
          option.selected = true;
        }
      });
      distributionSelect.addEventListener("change", (e) => {
        e.stopPropagation();
        const target = e.target;
        this.gradientSettings[type2].distribution = target.value;
        if (this.centralityState[type2]) {
          void this.calculateAndDisplayCentrality(type2);
        }
      });
      typeSelect.addEventListener("change", (e) => {
        e.stopPropagation();
        const target = e.target;
        const val = target.value;
        if (val === "sequential" || val === "diverging" || val === "cyclical" || val === "qualitative") {
          this.gradientSettings[type2].type = val;
        }
        optionsContainer.querySelectorAll(".gradient-option").forEach((opt) => opt.remove());
        this.colorPalettes.filter((palette) => {
          if (target.value === "qualitative") {
            return palette.type === "qualitative";
          } else if (target.value === "sequential") {
            return palette.type === "sequential";
          } else if (target.value === "diverging") {
            return palette.type === "diverging";
          } else if (target.value === "cyclical") {
            return palette.type === "cyclical";
          }
          return false;
        }).forEach((palette) => {
          const option = optionsContainer.createDiv({
            cls: `gradient-option ${this.selectedPalettes[type2] === palette.name ? "selected" : ""}`
          });
          option.dataset.paletteName = palette.name;
          this.updateGradientPreview(option, palette.name, type2);
          option.addEventListener("click", (e3) => {
            e3.stopPropagation();
            this.selectedPalettes[type2] = palette.name;
            this.updateGradientPreview(preview, palette.name, type2);
            optionsContainer.querySelectorAll(".gradient-option").forEach(
              (opt) => opt.classList.remove("selected")
            );
            option.classList.add("selected");
            if (this.centralityState[type2]) {
              void this.calculateAndDisplayCentrality(type2);
            }
          });
        });
        this.updateGradientPreview(preview, this.selectedPalettes[type2], type2);
        if (this.centralityState[type2]) {
          void this.calculateAndDisplayCentrality(type2);
        }
      });
      const stepsRow = controls.createDiv({ cls: "gradient-control-row" });
      stepsRow.createDiv({ cls: "gradient-control-label", text: t("graph.steps") });
      const stepsSelect = stepsRow.createDiv({ cls: "gradient-control-input" }).createEl("select");
      for (let i = 2; i <= 20; i++) {
        const option = stepsSelect.createEl("option", { value: String(i), text: String(i) });
        if (i === this.gradientSettings[type2].steps) {
          option.selected = true;
        }
      }
      stepsSelect.addEventListener("change", (e) => {
        e.stopPropagation();
        const value = parseInt(e.target.value);
        this.gradientSettings[type2].steps = value;
        this.updateGradientPreview(preview, this.selectedPalettes[type2], type2);
        if (this.centralityState[type2]) {
          void this.calculateAndDisplayCentrality(type2);
        }
      });
      const reversedRow = controls.createDiv({ cls: "gradient-control-row" });
      reversedRow.createDiv({ cls: "gradient-control-label", text: t("graph.reverse") });
      const reversedButton = reversedRow.createDiv({ cls: "gradient-control-input" }).createEl("button", {
        cls: `gradient-control-button ${this.gradientSettings[type2].reversed ? "active" : ""}`,
        text: this.gradientSettings[type2].reversed ? t("graph.on") : t("graph.off")
      });
      reversedButton.addEventListener("click", (e) => {
        e.stopPropagation();
        this.gradientSettings[type2].reversed = !this.gradientSettings[type2].reversed;
        reversedButton.classList.toggle("active", this.gradientSettings[type2].reversed);
        reversedButton.setText(this.gradientSettings[type2].reversed ? t("graph.on") : t("graph.off"));
        this.updateGradientPreview(preview, this.selectedPalettes[type2], type2);
        if (this.centralityState[type2]) {
          void this.calculateAndDisplayCentrality(type2);
        }
      });
      this.colorPalettes.filter((palette) => {
        const currentType = this.gradientSettings[type2].type;
        if (currentType === "qualitative") {
          return palette.type === "qualitative";
        } else if (currentType === "sequential") {
          return palette.type === "sequential";
        } else if (currentType === "diverging") {
          return palette.type === "diverging";
        } else if (currentType === "cyclical") {
          return palette.type === "cyclical";
        }
        return false;
      }).forEach((palette) => {
        const option = optionsContainer.createDiv({
          cls: `gradient-option ${this.selectedPalettes[type2] === palette.name ? "selected" : ""}`
        });
        option.dataset.paletteName = palette.name;
        this.updateGradientPreview(option, palette.name, type2);
        option.addEventListener("click", (e) => {
          e.stopPropagation();
          this.selectedPalettes[type2] = palette.name;
          this.updateGradientPreview(preview, palette.name, type2);
          optionsContainer.querySelectorAll(".gradient-option").forEach(
            (opt) => opt.classList.remove("selected")
          );
          option.classList.add("selected");
          if (this.centralityState[type2]) {
            void this.calculateAndDisplayCentrality(type2);
          }
        });
      });
      preview.addEventListener("click", (e) => {
        e.stopPropagation();
        dropdown.querySelectorAll(".gradient-options.expanded").forEach((opt) => {
          if (opt !== optionsContainer) {
            opt.classList.remove("expanded");
          }
        });
        optionsContainer.classList.toggle("expanded");
      });
      optionsContainer.addEventListener("click", (e) => {
        e.stopPropagation();
      });
    });
    settingsButton.addEventListener("click", (e) => {
      e.stopPropagation();
      dropdown.classList.toggle("color-settings-dropdown-visible");
    });
    dropdown.addEventListener("click", (e) => {
      e.stopPropagation();
    });
    this.documentClickHandler = () => {
      dropdown.classList.remove("color-settings-dropdown-visible");
    };
    this.container.ownerDocument.addEventListener("click", this.documentClickHandler);
  }
  toggleNodeLabels(enabled) {
    this.showNodeLabels = enabled;
    if (this.labelsSelection && !this.labelsSelection.empty()) {
      if (enabled) {
        this.labelsSelection.style("display", null);
      } else {
        this.labelsSelection.style("display", "none");
      }
    }
  }
  toggleArrows(enabled) {
    this.showArrows = enabled;
    if (this.linksSelection && !this.linksSelection.empty()) {
      this.linksSelection.attr("marker-end", enabled ? `url(#${this.markerIdDefault})` : null);
    }
    this.updateGraph();
  }
  updateGradientPreview(element, paletteName, type2) {
    element.empty();
    const palette = this.colorPalettes.find((p) => p.name === paletteName);
    if (palette) {
      const settings = type2 ? this.gradientSettings[type2] : { steps: _GraphView.DEFAULT_GRADIENT_STEPS, reversed: false };
      const colorRange = colorPaletteToColorRange(palette, {
        steps: settings.steps,
        reversed: settings.reversed
      });
      colorRange.colors.forEach((color2) => {
        const colorBox = element.createDiv({ cls: "color-box" });
        colorBox.style.setProperty("background-color", color2);
      });
    }
  }
  createCentralityButton(type2) {
    if (!this.controlPanel) throw new Error("Control panel not initialized");
    const button = this.controlPanel.createDiv({ cls: "centrality-button" });
    const label = type2.charAt(0).toUpperCase();
    button.setText(label);
    const tooltipEl = button.createDiv({ cls: "centrality-button-tooltip" });
    tooltipEl.createDiv({
      cls: "tooltip-title",
      text: t("graph.centralityTitle", {
        type: type2.charAt(0).toUpperCase() + type2.slice(1)
      })
    });
    const description = tooltipEl.createDiv({ cls: "tooltip-description" });
    switch (type2) {
      case "betweenness":
        description.setText(t("graph.betweennessDesc"));
        break;
      case "closeness":
        description.setText(t("graph.closenessDesc"));
        break;
      case "eigenvector":
        description.setText(t("graph.eigenvectorDesc"));
        break;
    }
    button.addEventListener("click", () => {
      void (async () => {
        const isActive = this.centralityState[type2];
        if (isActive) {
          button.removeClass("active");
          this.centralityState[type2] = false;
          this.activeButton = null;
          this.nodesSelection.transition().duration(this.ANIMATION.DURATION).style("fill", "var(--graph-node-color-default)").style("opacity", "var(--graph-node-opacity-default)");
          this.lastCentralityScores = {};
          const leaf = this.app.workspace.getLeavesOfType(CENTRALITY_RESULTS_VIEW_TYPE)[0];
          if (leaf) {
            leaf.detach();
            const rightSplit = this.app.workspace.rightSplit;
            if (rightSplit && rightSplit.collapsed === false) {
              rightSplit.collapse();
            }
          }
        } else {
          this.centralityTypes.forEach((t2) => {
            this.centralityState[t2] = false;
            const otherButton = this.controlPanel?.querySelector(`[data-centrality-type="${t2}"]`);
            if (t2 !== type2 && otherButton instanceof HTMLElement) {
              otherButton.removeClass("active");
            }
          });
          button.addClass("active");
          this.centralityState[type2] = true;
          this.activeButton = button;
          await this.calculateAndDisplayCentrality(type2);
        }
      })();
    });
    button.setAttribute("data-centrality-type", type2);
    return button;
  }
  calculateAndDisplayCentrality(type2) {
    try {
      let results;
      const pluginInstance = this.pluginService.getPlugin();
      switch (type2) {
        case "betweenness":
          results = pluginInstance.calculateBetweennessCentralityCached();
          break;
        case "closeness":
          results = pluginInstance.calculateClosenessCentralityCached();
          break;
        case "eigenvector":
          results = pluginInstance.calculateEigenvectorCentralityCached();
          break;
      }
      this.lastCentralityScores = {};
      const resultCount = results.length;
      for (let i = 0; i < resultCount; i++) {
        const node = results[i];
        this.lastCentralityScores[node.node_id] = node.centrality[type2] || 0;
      }
      const scores = Object.values(this.lastCentralityScores);
      const minScore = scores.reduce((min8, v) => Math.min(min8, v), Infinity);
      const maxScore = scores.reduce((max8, v) => Math.max(max8, v), -Infinity);
      const palette = this.colorPalettes.find((p) => p.name === this.selectedPalettes[type2]);
      if (!palette) return Promise.resolve();
      const colorRange = colorPaletteToColorRange(palette, {
        steps: this.gradientSettings[type2].steps,
        reversed: this.gradientSettings[type2].reversed
      });
      let colorScale;
      const colors = colorRange.colors;
      switch (this.gradientSettings[type2].distribution) {
        case "linear":
          colorScale = linear2().domain([minScore, maxScore]).range([colors[0], colors[colors.length - 1]]);
          break;
        case "quantize":
          colorScale = quantize().domain([minScore, maxScore]).range(colors);
          break;
        case "jenks": {
          const breaks = this.calculateJenksBreaks(scores, colors.length);
          const domain = breaks.length > 2 ? breaks.slice(1, -1) : [];
          const range2 = colors.slice(0, domain.length + 1);
          colorScale = threshold().domain(domain).range(range2.length > 0 ? range2 : [colors[0]]);
          break;
        }
        default:
          colorScale = linear2().domain([minScore, maxScore]).range([colors[0], colors[colors.length - 1]]);
      }
      const currentHighlightedNodeId = this.highlightedNodeId;
      this.nodesSelection.transition().duration(this.ANIMATION.DURATION).style("fill", (d) => {
        const score2 = this.lastCentralityScores[parseInt(d.id)];
        if (score2 === void 0 || score2 === null) {
          return this.NODE.COLORS.DEFAULT;
        }
        return colorScale(score2);
      }).style("opacity", "var(--graph-node-opacity-default)");
      if (currentHighlightedNodeId) {
        const highlightedNode = this.nodesSelection.filter((d) => d.id === currentHighlightedNodeId).node();
        if (highlightedNode) {
          this.win.setTimeout(() => {
            this.highlightNode(highlightedNode, true);
            this.highlightConnections(currentHighlightedNodeId, true);
          }, this.ANIMATION.DURATION);
        }
      }
      pluginInstance.displayResults(results, `${type2.charAt(0).toUpperCase() + type2.slice(1)} Centrality`);
      return Promise.resolve();
    } catch (err) {
      new import_obsidian13.Notice(t("notices.centralityFailed", {
        type: type2,
        message: err instanceof Error ? err.message : String(err)
      }));
      return Promise.resolve();
    }
  }
  /**
   * Calculates the optimal container scale based on node count.
   * Uses a logarithmic scale to create smooth transitions between different graph sizes.
   * Small graphs (few nodes) will use less space, while larger graphs will use more.
   */
  calculateOptimalContainerScale() {
    if (!this.nodes.length) return this.ZOOM.CONTAINER_SCALE.MIN;
    const normalizedCount = Math.log(this.nodes.length + 1) / Math.log(this.ZOOM.CONTAINER_SCALE.NODE_SCALE_FACTOR + 1);
    const scaleRange = this.ZOOM.CONTAINER_SCALE.MAX - this.ZOOM.CONTAINER_SCALE.MIN;
    const scale = this.ZOOM.CONTAINER_SCALE.MIN + scaleRange * Math.min(normalizedCount, 1);
    return scale;
  }
  /**
   * Calculate Jenks natural breaks for a dataset
   * @param data Array of numbers to classify
   * @param numClasses Number of classes to create
   * @returns Array of break points including min and max values
   */
  calculateJenksBreaks(data, numClasses) {
    if (data.length === 0) return [];
    if (data.length === 1) return [data[0], data[0]];
    const sorted = [...data].sort((a2, b) => a2 - b);
    const minVal = sorted[0];
    const maxVal = sorted[sorted.length - 1];
    const uniqueCount = new Set(sorted).size;
    if (uniqueCount === 1) return [minVal, minVal];
    const effectiveClasses = Math.min(Math.max(1, Math.floor(numClasses)), uniqueCount, data.length);
    if (effectiveClasses >= data.length) {
      return [...new Set(sorted)].sort((a2, b) => a2 - b);
    }
    let breaks = null;
    try {
      breaks = jenks(sorted, effectiveClasses);
    } catch {
    }
    if (!breaks || !Array.isArray(breaks) || breaks.length < 2) {
      breaks = [];
      for (let i = 0; i <= effectiveClasses; i++) {
        const pos = (sorted.length - 1) * (i / effectiveClasses);
        breaks.push(sorted[Math.min(sorted.length - 1, Math.max(0, Math.round(pos)))]);
      }
    }
    const result = [.../* @__PURE__ */ new Set([...breaks, minVal, maxVal])].filter((v) => Number.isFinite(v)).sort((a2, b) => a2 - b);
    return result.length < 2 ? [minVal, maxVal] : result;
  }
  updateNodeColors(results, type2) {
    const values = results.map((r) => r.centrality[type2] || 0);
    const minValue = Math.min(...values);
    const maxValue = Math.max(...values);
    this.nodesSelection.each(function(d) {
      const node = results.find((r) => r.node_id.toString() === d.id);
      if (node && node.centrality[type2] !== void 0) {
        const normalizedValue = (node.centrality[type2] - minValue) / (maxValue - minValue);
        const color2 = RdYlBu_default(1 - normalizedValue);
        select_default2(this).transition().duration(200).style("fill", color2);
      }
    });
  }
};
/** Default number of steps for centrality gradient palettes (used when type is unspecified) */
_GraphView.DEFAULT_GRADIENT_STEPS = 12;
/** Default palettes for light theme (darker colors for light background) */
_GraphView.DEFAULT_PALETTES_LIGHT = {
  betweenness: "Viridis",
  closeness: "Plasma",
  eigenvector: "Plasma"
};
/** Default palettes for dark theme (brighter colors for dark background) */
_GraphView.DEFAULT_PALETTES_DARK = {
  betweenness: "Cool",
  closeness: "Warm",
  eigenvector: "Warm"
};
var GraphView = _GraphView;

// src/views/GraphAnalysisView.ts
var GRAPH_ANALYSIS_VIEW_TYPE = "graph-analysis-view";
var GraphAnalysisView = class _GraphAnalysisView extends import_obsidian14.ItemView {
  constructor(leaf, plugin) {
    super(leaf);
    this.plugin = plugin;
    this.hasInitialized = false;
    this.wasActive = false;
    this.lastKnownWidth = 0;
    this.lastKnownHeight = 0;
    const dataStore = this.plugin.dataStore;
    if (!dataStore) {
      throw new Error("Plugin data store not initialized");
    }
    this.graphView = new GraphView(this.app, this.plugin.settings, dataStore);
    this.activeLeafChangeHandler = (leaf2) => {
      this.updateStatusBarVisibility();
      const isNowActive = leaf2 === this.leaf;
      if (isNowActive && this.hasInitialized && !this.wasActive) {
        this.contentEl.ownerDocument.defaultView.setTimeout(() => {
          void (async () => {
            await this.reloadGraphData();
            await this.centerGraphSafely();
          })();
        }, 100);
      } else if (isNowActive) {
        this.contentEl.ownerDocument.defaultView.setTimeout(() => {
          void this.centerGraphSafely();
        }, 100);
      }
      const newViewType = leaf2?.view?.getViewType?.();
      if (newViewType !== CENTRALITY_RESULTS_VIEW_TYPE) {
        this.wasActive = isNowActive;
      }
    };
  }
  getViewType() {
    return GRAPH_ANALYSIS_VIEW_TYPE;
  }
  getDisplayText() {
    return "Graph analysis";
  }
  getIcon() {
    return "waypoints";
  }
  async onOpen() {
    const container = this.containerEl.children[1];
    container.empty();
    container.classList.add("graph-analysis-view-container");
    if (this.app.workspace.layoutReady) {
      this.updateStatusBarVisibility();
    } else {
      this.app.workspace.onLayoutReady(() => {
        this.updateStatusBarVisibility();
      });
    }
    await this.graphView.onload(container);
    const rect = this.containerEl.getBoundingClientRect();
    this.lastKnownWidth = rect.width;
    this.lastKnownHeight = rect.height;
    this.hasInitialized = true;
    this.wasActive = true;
    this.contentEl.ownerDocument.defaultView.setTimeout(() => {
      this.registerEvent(
        this.app.workspace.on("active-leaf-change", this.activeLeafChangeHandler)
      );
    }, 200);
  }
  onResize() {
    if (this.graphView) {
      const rect = this.containerEl.getBoundingClientRect();
      if (Math.abs(rect.width - this.lastKnownWidth) < 1 && Math.abs(rect.height - this.lastKnownHeight) < 1) {
        return;
      }
      this.lastKnownWidth = rect.width;
      this.lastKnownHeight = rect.height;
      this.contentEl.ownerDocument.defaultView.setTimeout(() => {
        void this.centerGraphSafely();
      }, 50);
    }
  }
  setEphemeralState(state) {
    super.setEphemeralState(state);
    void this.centerGraphSafely();
  }
  getState() {
    const state = super.getState();
    return {
      ...state,
      lastActive: Date.now()
    };
  }
  onClose() {
    if (this.graphView) {
      try {
        this.graphView.onunload();
      } catch {
      }
    }
    this.contentEl.empty();
    this.contentEl.ownerDocument.defaultView.setTimeout(() => {
      this.updateStatusBarVisibility();
    }, 10);
    return Promise.resolve();
  }
  hideStatusBar() {
    this.contentEl.ownerDocument.body.addClass("graph-analysis-hide-status-bar");
  }
  showStatusBar() {
    this.contentEl.ownerDocument.body.removeClass("graph-analysis-hide-status-bar");
  }
  /**
   * Determines whether the status bar should be visible based on the current workspace state
   * Returns true if status bar should be visible, false if it should be hidden
   */
  shouldShowStatusBar() {
    const activeView = this.app.workspace.getActiveViewOfType(import_obsidian14.ItemView);
    if (!activeView) {
      return true;
    }
    const activeViewType = activeView.getViewType();
    return activeViewType !== GRAPH_ANALYSIS_VIEW_TYPE && activeViewType !== CENTRALITY_RESULTS_VIEW_TYPE;
  }
  /**
   * Updates status bar visibility based on current workspace state
   * This method can be called to ensure consistent status bar behavior
   */
  updateStatusBarVisibility() {
    const shouldShow = this.shouldShowStatusBar();
    const currentlyHidden = this.contentEl.ownerDocument.body.hasClass("graph-analysis-hide-status-bar");
    if (shouldShow && currentlyHidden) {
      this.showStatusBar();
    } else if (!shouldShow && !currentlyHidden) {
      this.hideStatusBar();
    }
  }
  /**
   * Reload graph data when switching back to the view
   */
  async reloadGraphData() {
    try {
      const graphView = this.graphView;
      if (!graphView) return;
      const isActive = this.app.workspace.getActiveViewOfType(_GraphAnalysisView) === this;
      if (!isActive) return;
      await graphView.reloadVaultData();
    } catch {
    }
  }
  centerGraphSafely() {
    try {
      const graphView = this.graphView;
      if (!graphView) return Promise.resolve();
      const isActive = this.app.workspace.getActiveViewOfType(_GraphAnalysisView) === this;
      if (!isActive) return Promise.resolve();
      graphView.refreshGraphView();
      this.contentEl.ownerDocument.defaultView.setTimeout(() => {
        try {
          graphView.restartSimulationGently();
        } catch {
        }
      }, 50);
    } catch {
    }
    return Promise.resolve();
  }
  updateSettings() {
    if (this.graphView) {
      this.graphView.updateSettings(this.plugin.settings);
    }
  }
  getGraphView() {
    return this.graphView;
  }
};

// src/settings/GraphAnalysisSettingTab.ts
var import_obsidian15 = require("obsidian");
var GraphAnalysisSettingTab = class extends import_obsidian15.PluginSettingTab {
  constructor(app, plugin) {
    super(app, plugin);
    this.exclusionStatsEl = null;
    this.plugin = plugin;
  }
  display() {
    const { containerEl } = this;
    containerEl.empty();
    containerEl.addClass("graph-analysis-settings");
    new import_obsidian15.Setting(containerEl).setName(t("settings.excludeHeading")).setHeading();
    const exclusionContainer = containerEl.createDiv({ cls: "graph-settings-section-container" });
    new import_obsidian15.Setting(exclusionContainer).setClass("graph-settings-item").setName(t("settings.excludeFolders.name")).setDesc(t("settings.excludeFolders.desc")).addText((text) => text.setPlaceholder(t("settings.excludeFolders.placeholder")).setValue(this.plugin.settings.excludeFolders.join(",")).onChange(async (value) => {
      this.plugin.settings.excludeFolders = value.split(",").map((s) => s.trim()).filter((s) => s);
      await this.plugin.saveSettings();
      this.updateExclusionStats();
    }));
    new import_obsidian15.Setting(exclusionContainer).setClass("graph-settings-item").setName(t("settings.excludeTags.name")).setDesc(t("settings.excludeTags.desc")).addText((text) => text.setPlaceholder(t("settings.excludeTags.placeholder")).setValue(this.plugin.settings.excludeTags.join(",")).onChange(async (value) => {
      this.plugin.settings.excludeTags = value.split(",").map((s) => s.trim()).filter((s) => s);
      await this.plugin.saveSettings();
      this.updateExclusionStats();
    }));
    this.createExclusionStatsSection(exclusionContainer);
    new import_obsidian15.Setting(containerEl).setName(t("settings.llmHeading")).setHeading();
    const apiContainer = containerEl.createDiv({ cls: "graph-settings-section-container" });
    let apiKeyTextComponent;
    new import_obsidian15.Setting(apiContainer).setClass("graph-settings-item").setName(t("settings.geminiApiKey.name")).setDesc((() => {
      const doc = this.containerEl.ownerDocument;
      const frag = doc.createDocumentFragment();
      frag.append(doc.createTextNode(t("settings.geminiApiKey.descPrefix")));
      const link = doc.createElement("a");
      link.textContent = t("settings.geminiApiKey.getKeyLink");
      link.href = "https://aistudio.google.com/apikey";
      link.setAttribute("target", "_blank");
      link.setAttribute("rel", "noopener");
      frag.append(link);
      return frag;
    })()).addText((text) => {
      text.setPlaceholder(t("settings.geminiApiKey.placeholder")).setValue(this.plugin.settings.geminiApiKey).onChange(async (value) => {
        this.plugin.settings.geminiApiKey = value;
        await this.plugin.saveSettings();
      });
      text.inputEl.type = "password";
      apiKeyTextComponent = text;
      return text;
    }).addExtraButton((btn) => {
      btn.setIcon("eye").setTooltip(t("settings.geminiApiKey.showTooltip")).onClick(() => {
        const input = apiKeyTextComponent.inputEl;
        const isVisible = input.type === "text";
        input.type = isVisible ? "password" : "text";
        btn.setIcon(isVisible ? "eye" : "eye-off");
        btn.setTooltip(isVisible ? t("settings.geminiApiKey.showTooltip") : t("settings.geminiApiKey.hideTooltip"));
      });
      return btn;
    });
    const networkDisclosureSetting = new import_obsidian15.Setting(apiContainer).setName(t("settings.networkDisclosure.name")).setDesc(t("settings.networkDisclosure.desc"));
    networkDisclosureSetting.settingEl.addClasses([
      "graph-settings-item",
      "graph-settings-network-disclosure"
    ]);
    new import_obsidian15.Setting(containerEl).setName(t("settings.languageHeading")).setHeading();
    const languageContainer = containerEl.createDiv({ cls: "graph-settings-section-container" });
    new import_obsidian15.Setting(languageContainer).setClass("graph-settings-item").setName(t("settings.uiLanguage.name")).setDesc(t("settings.uiLanguage.desc")).addDropdown((dropdown) => {
      dropdown.addOption("auto", t("settings.uiLanguage.obsidian")).addOption("en", t("settings.uiLanguage.en")).addOption("zh-Hans", t("settings.uiLanguage.zhHans")).setValue(this.plugin.settings.uiLanguage).onChange(async (value) => {
        this.plugin.settings.uiLanguage = value;
        configureI18n(this.plugin.settings.uiLanguage);
        await this.plugin.saveSettings();
        this.display();
      });
      return dropdown;
    });
    new import_obsidian15.Setting(languageContainer).setClass("graph-settings-item").setName(t("settings.aiResponseLanguage.name")).setDesc(t("settings.aiResponseLanguage.desc")).addDropdown((dropdown) => {
      dropdown.addOption("auto", t("settings.aiResponseLanguage.auto")).addOption("en", t("settings.aiResponseLanguage.en")).addOption("zh-Hans", t("settings.aiResponseLanguage.zhHans")).setValue(this.plugin.settings.aiResponseLanguage).onChange(async (value) => {
        this.plugin.settings.aiResponseLanguage = value;
        await this.plugin.saveSettings();
      });
      return dropdown;
    });
  }
  createExclusionStatsSection(containerEl) {
    this.exclusionStatsEl = containerEl.createDiv({ cls: "exclusion-stats" });
    this.updateExclusionStats();
  }
  updateExclusionStats() {
    if (!this.exclusionStatsEl || !this.plugin.exclusionUtils) {
      return;
    }
    this.exclusionStatsEl.empty();
    try {
      const stats = this.plugin.exclusionUtils.getExclusionStats();
      const statsContainer = this.exclusionStatsEl.createDiv({ cls: "stats-container" });
      const statsText = statsContainer.createDiv({ cls: "stats-text" });
      const excludedParts = [];
      if (stats.excludedByFolder > 0) {
        excludedParts.push(t("settings.stats.excludedByFolder", { count: stats.excludedByFolder }));
      }
      if (stats.excludedByTag > 0) {
        excludedParts.push(t("settings.stats.excludedByTag", { count: stats.excludedByTag }));
      }
      const excludedBreakdown = excludedParts.length > 0 ? ` (${excludedParts.join(", ")})` : "";
      statsText.createDiv({
        text: t("settings.stats.excludedTotal", {
          total: stats.totalExcluded,
          breakdown: excludedBreakdown
        }),
        cls: "stat-item excluded-total"
      });
      statsText.createDiv({
        text: t("settings.stats.includedTotal", {
          included: stats.includedFiles,
          total: stats.totalFiles
        }),
        cls: "stat-item included-total"
      });
      if (stats.totalExcluded > 0) {
        const btn = statsContainer.createEl("button", {
          text: t("settings.stats.showExcluded"),
          cls: "mod-cta"
        });
        btn.addEventListener("click", () => this.showExcludedFilesList());
      }
    } catch {
      this.exclusionStatsEl.createDiv({
        text: t("settings.stats.error"),
        cls: "stat-error"
      });
    }
  }
  showExcludedFilesList() {
    if (!this.plugin.exclusionUtils) return;
    const excludedFiles = this.plugin.exclusionUtils.getExcludedFiles();
    const modal = new ExcludedFilesModal(this.app, excludedFiles);
    modal.open();
  }
};
var ExcludedFilesModal = class extends import_obsidian15.Modal {
  constructor(app, excludedFiles) {
    super(app);
    this.excludedFiles = excludedFiles;
  }
  onOpen() {
    const { contentEl } = this;
    contentEl.empty();
    contentEl.createEl("h2", { text: t("settings.excludedModal.title") });
    if (this.excludedFiles.length === 0) {
      contentEl.createDiv({ text: t("settings.excludedModal.empty") });
      return;
    }
    const fileList = contentEl.createDiv({ cls: "excluded-files-list" });
    this.excludedFiles.forEach((filePath) => {
      const fileItem = fileList.createDiv({ cls: "excluded-file-item" });
      fileItem.createSpan({ text: filePath });
    });
  }
  onClose() {
    const { contentEl } = this;
    contentEl.empty();
  }
};

// src/utils/ExclusionUtils.ts
var import_obsidian16 = require("obsidian");
var ExclusionUtils = class {
  constructor(app, settings) {
    this.app = app;
    this.settings = settings;
  }
  /**
   * Update settings reference when settings change
   */
  updateSettings(settings) {
    this.settings = settings;
  }
  /**
   * Check if a file should be excluded from analysis based on folder and tag exclusion rules
   */
  isFileExcluded(file) {
    if (this.isFileInExcludedFolder(file)) {
      return true;
    }
    if (this.hasExcludedTags(file)) {
      return true;
    }
    return false;
  }
  /**
   * Check if a file is in an excluded folder
   */
  isFileInExcludedFolder(file) {
    if (!this.settings.excludeFolders || this.settings.excludeFolders.length === 0) {
      return false;
    }
    const filePath = file.path;
    for (const folder of this.settings.excludeFolders) {
      if (!folder || folder.trim() === "") continue;
      const normalizedFolder = this.normalizeFolderPath(folder.trim());
      if (filePath.startsWith(normalizedFolder)) {
        return true;
      }
    }
    return false;
  }
  /**
   * Check if a file has any excluded tags
   */
  hasExcludedTags(file) {
    if (!this.settings.excludeTags || this.settings.excludeTags.length === 0) {
      return false;
    }
    const fileTags = this.getFileTags(file);
    if (fileTags.length === 0) {
      return false;
    }
    for (const excludedTag of this.settings.excludeTags) {
      if (!excludedTag || excludedTag.trim() === "") continue;
      const normalizedExcludedTag = this.normalizeTag(excludedTag.trim());
      for (const fileTag of fileTags) {
        const normalizedFileTag = this.normalizeTag(fileTag);
        if (normalizedFileTag === normalizedExcludedTag) {
          return true;
        }
      }
    }
    return false;
  }
  /**
   * Get all tags from a file (both frontmatter and inline tags)
   */
  getFileTags(file) {
    const tags = [];
    const fileCache = this.app.metadataCache.getFileCache(file);
    if (!fileCache) {
      return tags;
    }
    if (fileCache.frontmatter && fileCache.frontmatter.tags) {
      const frontmatterTags = Array.isArray(fileCache.frontmatter.tags) ? fileCache.frontmatter.tags : [fileCache.frontmatter.tags];
      tags.push(...frontmatterTags.map((tag) => String(tag)));
    }
    if (fileCache.tags) {
      for (const tagCache of fileCache.tags) {
        tags.push(tagCache.tag);
      }
    }
    return tags;
  }
  /**
   * Normalize folder path for consistent comparison using Obsidian's normalizePath
   */
  normalizeFolderPath(folder) {
    let normalized = (0, import_obsidian16.normalizePath)(folder.trim());
    normalized = normalized.replace(/^\/+|\/+$/g, "");
    if (normalized && !normalized.endsWith("/")) {
      normalized += "/";
    }
    return normalized;
  }
  /**
   * Normalize tag for consistent comparison
   */
  normalizeTag(tag) {
    return tag.replace(/^#+/, "").toLowerCase().trim();
  }
  /**
   * Get a list of all excluded file paths for debugging/logging
   */
  getExcludedFiles(allFiles) {
    const excludedFiles = [];
    const files = allFiles ?? this.app.vault.getMarkdownFiles();
    for (const file of files) {
      if (this.isFileExcluded(file)) {
        excludedFiles.push(file.path);
      }
    }
    return excludedFiles;
  }
  /**
   * Get exclusion statistics for debugging
   */
  getExclusionStats(allFiles) {
    const files = allFiles ?? this.app.vault.getMarkdownFiles();
    let excludedByFolder = 0;
    let excludedByTag = 0;
    let totalExcluded = 0;
    for (const file of files) {
      const isExcludedByFolder = this.isFileInExcludedFolder(file);
      const isExcludedByTag = this.hasExcludedTags(file);
      if (isExcludedByFolder) excludedByFolder++;
      if (isExcludedByTag) excludedByTag++;
      if (isExcludedByFolder || isExcludedByTag) totalExcluded++;
    }
    return {
      totalFiles: files.length,
      excludedByFolder,
      excludedByTag,
      totalExcluded,
      includedFiles: files.length - totalExcluded
    };
  }
};

// src/utils/VaultScope.ts
var VaultScope = class {
  constructor(app, exclusionUtils) {
    this.app = app;
    this.exclusionUtils = exclusionUtils;
  }
  getAllMarkdownFiles() {
    return this.app.vault.getMarkdownFiles();
  }
  getIncludedMarkdownFiles() {
    return this.getAllMarkdownFiles().filter((file) => !this.exclusionUtils.isFileExcluded(file));
  }
  getIncludedMarkdownPaths() {
    return this.getIncludedMarkdownFiles().map((file) => file.path);
  }
};

// src/utils/PluginDataStore.ts
var import_obsidian17 = require("obsidian");
var PLUGIN_ID = "knowledge-graph-analysis";
var LEGACY_PATHS = {
  vaultAnalysis: "vault-analysis.json",
  failedBatches: "vault-analysis-failed-batches.json",
  structure: "structure-analysis.json",
  evolution: "evolution-analysis.json",
  actions: "actions-analysis.json"
};
var PluginDataStore = class {
  constructor(host) {
    this.host = host;
  }
  async read() {
    const data = await this.host.loadData();
    if (data && typeof data === "object") {
      return data;
    }
    return {};
  }
  async write(data) {
    await this.host.saveData(data);
  }
  async getVaultAnalysis() {
    return (await this.read()).vaultAnalysis ?? null;
  }
  async setVaultAnalysis(data) {
    const cache = await this.read();
    cache.vaultAnalysis = data;
    await this.write(cache);
  }
  async getFailedBatches() {
    return (await this.read()).failedBatches ?? null;
  }
  async setFailedBatches(data) {
    const cache = await this.read();
    cache.failedBatches = data;
    await this.write(cache);
  }
  async getTabAnalysis(tabName) {
    const tab = (await this.read()).tabAnalyses?.[tabName];
    return tab ?? null;
  }
  async setTabAnalysis(tabName, data) {
    const cache = await this.read();
    if (!cache.tabAnalyses) {
      cache.tabAnalyses = {};
    }
    cache.tabAnalyses[tabName] = data;
    await this.write(cache);
  }
  async getDerivedVisualizations() {
    return (await this.read()).derivedVisualizations ?? null;
  }
  async setDerivedVisualizations(data) {
    const cache = await this.read();
    cache.derivedVisualizations = data;
    await this.write(cache);
  }
  /**
   * One-time import from legacy per-file cache under .obsidian/plugins/.../responses/
   * using Vault API (getAbstractFileByPath + read), not Node fs or vault.adapter.
   */
  async migrateLegacyCacheFromVaultFiles(app) {
    const cache = await this.read();
    const base = `${app.vault.configDir}/plugins/${PLUGIN_ID}/responses`;
    let changed = false;
    if (!cache.vaultAnalysis) {
      const parsed = await this.readLegacyJsonFile(app, `${base}/${LEGACY_PATHS.vaultAnalysis}`);
      if (parsed) {
        cache.vaultAnalysis = parsed;
        changed = true;
      }
    }
    if (!cache.failedBatches) {
      const parsed = await this.readLegacyJsonFile(app, `${base}/${LEGACY_PATHS.failedBatches}`);
      if (parsed) {
        cache.failedBatches = parsed;
        changed = true;
      }
    }
    if (!cache.tabAnalyses) {
      cache.tabAnalyses = {};
    }
    const tabKeys = [
      { tab: "structure", file: LEGACY_PATHS.structure },
      { tab: "evolution", file: LEGACY_PATHS.evolution },
      { tab: "actions", file: LEGACY_PATHS.actions }
    ];
    for (const { tab, file } of tabKeys) {
      if (cache.tabAnalyses[tab]) {
        continue;
      }
      const parsed = await this.readLegacyJsonFile(app, `${base}/${file}`);
      if (parsed) {
        cache.tabAnalyses[tab] = parsed;
        changed = true;
      }
    }
    if (changed) {
      await this.write(cache);
    }
  }
  async readLegacyJsonFile(app, vaultPath) {
    const file = app.vault.getAbstractFileByPath(vaultPath);
    if (!(file instanceof import_obsidian17.TFile)) {
      return null;
    }
    try {
      return JSON.parse(await app.vault.read(file));
    } catch {
      return null;
    }
  }
};

// graph-analysis-wasm/pkg/graph_analysis_wasm_bg.wasm
var graph_analysis_wasm_bg_default = __toBinary(" ");

// src/wasm/embedded.ts
var embeddedWasmBytes = graph_analysis_wasm_bg_default;

// src/main.ts
function build_graph_from_vault(vault_data_json) {
  let deferred2_0;
  let deferred2_1;
  try {
    const ptr0 = passStringToWasm0(vault_data_json, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
    const len0 = WASM_VECTOR_LEN;
    const ret = wasm.build_graph_from_vault(ptr0, len0);
    deferred2_0 = ret[0];
    deferred2_1 = ret[1];
    return getStringFromWasm0(ret[0], ret[1]);
  } finally {
    wasm.__wbindgen_free(deferred2_0, deferred2_1, 1);
  }
}
function calculate_betweenness_centrality_cached() {
  let deferred1_0;
  let deferred1_1;
  try {
    const ret = wasm.calculate_betweenness_centrality_cached();
    deferred1_0 = ret[0];
    deferred1_1 = ret[1];
    return getStringFromWasm0(ret[0], ret[1]);
  } finally {
    wasm.__wbindgen_free(deferred1_0, deferred1_1, 1);
  }
}
function calculate_closeness_centrality_cached() {
  let deferred1_0;
  let deferred1_1;
  try {
    const ret = wasm.calculate_closeness_centrality_cached();
    deferred1_0 = ret[0];
    deferred1_1 = ret[1];
    return getStringFromWasm0(ret[0], ret[1]);
  } finally {
    wasm.__wbindgen_free(deferred1_0, deferred1_1, 1);
  }
}
function calculate_degree_centrality_cached() {
  let deferred1_0;
  let deferred1_1;
  try {
    const ret = wasm.calculate_degree_centrality_cached();
    deferred1_0 = ret[0];
    deferred1_1 = ret[1];
    return getStringFromWasm0(ret[0], ret[1]);
  } finally {
    wasm.__wbindgen_free(deferred1_0, deferred1_1, 1);
  }
}
function calculate_eigenvector_centrality_cached() {
  let deferred1_0;
  let deferred1_1;
  try {
    const ret = wasm.calculate_eigenvector_centrality_cached();
    deferred1_0 = ret[0];
    deferred1_1 = ret[1];
    return getStringFromWasm0(ret[0], ret[1]);
  } finally {
    wasm.__wbindgen_free(deferred1_0, deferred1_1, 1);
  }
}
function clear_graph() {
  let deferred1_0;
  let deferred1_1;
  try {
    const ret = wasm.clear_graph();
    deferred1_0 = ret[0];
    deferred1_1 = ret[1];
    return getStringFromWasm0(ret[0], ret[1]);
  } finally {
    wasm.__wbindgen_free(deferred1_0, deferred1_1, 1);
  }
}
function get_graph_metadata() {
  let deferred1_0;
  let deferred1_1;
  try {
    const ret = wasm.get_graph_metadata();
    deferred1_0 = ret[0];
    deferred1_1 = ret[1];
    return getStringFromWasm0(ret[0], ret[1]);
  } finally {
    wasm.__wbindgen_free(deferred1_0, deferred1_1, 1);
  }
}
function get_node_neighbors_cached(node_id) {
  let deferred1_0;
  let deferred1_1;
  try {
    const ret = wasm.get_node_neighbors_cached(node_id);
    deferred1_0 = ret[0];
    deferred1_1 = ret[1];
    return getStringFromWasm0(ret[0], ret[1]);
  } finally {
    wasm.__wbindgen_free(deferred1_0, deferred1_1, 1);
  }
}
function __wbg_get_imports() {
  const import0 = {
    __proto__: null,
    __wbg_alert_8f53169011290d0d: function(arg0, arg1) {
      alert(getStringFromWasm0(arg0, arg1));
    },
    __wbg_error_a6fa202b58aa1cd3: function(arg0, arg1) {
      let deferred0_0;
      let deferred0_1;
      try {
        deferred0_0 = arg0;
        deferred0_1 = arg1;
        console.error(getStringFromWasm0(arg0, arg1));
      } finally {
        wasm.__wbindgen_free(deferred0_0, deferred0_1, 1);
      }
    },
    __wbg_new_227d7c05414eb861: function() {
      const ret = new Error();
      return ret;
    },
    __wbg_random_0898d919bfb58a97: function() {
      const ret = Math.random();
      return ret;
    },
    __wbg_stack_3b0d974bbf31e44f: function(arg0, arg1) {
      const ret = arg1.stack;
      const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
      const len1 = WASM_VECTOR_LEN;
      getDataViewMemory0().setInt32(arg0 + 4 * 1, len1, true);
      getDataViewMemory0().setInt32(arg0 + 4 * 0, ptr1, true);
    },
    __wbg_warn_6ea513061cad2a94: function(arg0, arg1) {
      console.warn(getStringFromWasm0(arg0, arg1));
    },
    __wbindgen_init_externref_table: function() {
      const table = wasm.__wbindgen_externrefs;
      const offset = table.grow(4);
      table.set(0, void 0);
      table.set(offset + 0, void 0);
      table.set(offset + 1, null);
      table.set(offset + 2, true);
      table.set(offset + 3, false);
    }
  };
  return {
    __proto__: null,
    "./graph_analysis_wasm_bg.js": import0
  };
}
var cachedDataViewMemory0 = null;
function getDataViewMemory0() {
  if (cachedDataViewMemory0 === null || cachedDataViewMemory0.buffer.detached === true || cachedDataViewMemory0.buffer.detached === void 0 && cachedDataViewMemory0.buffer !== wasm.memory.buffer) {
    cachedDataViewMemory0 = new DataView(wasm.memory.buffer);
  }
  return cachedDataViewMemory0;
}
function getStringFromWasm0(ptr, len) {
  return decodeText(ptr >>> 0, len);
}
var cachedUint8ArrayMemory0 = null;
function getUint8ArrayMemory0() {
  if (cachedUint8ArrayMemory0 === null || cachedUint8ArrayMemory0.byteLength === 0) {
    cachedUint8ArrayMemory0 = new Uint8Array(wasm.memory.buffer);
  }
  return cachedUint8ArrayMemory0;
}
function passStringToWasm0(arg, malloc, realloc) {
  if (realloc === void 0) {
    const buf = cachedTextEncoder.encode(arg);
    const ptr2 = malloc(buf.length, 1) >>> 0;
    getUint8ArrayMemory0().subarray(ptr2, ptr2 + buf.length).set(buf);
    WASM_VECTOR_LEN = buf.length;
    return ptr2;
  }
  let len = arg.length;
  let ptr = malloc(len, 1) >>> 0;
  const mem = getUint8ArrayMemory0();
  let offset = 0;
  for (; offset < len; offset++) {
    const code = arg.charCodeAt(offset);
    if (code > 127) break;
    mem[ptr + offset] = code;
  }
  if (offset !== len) {
    if (offset !== 0) {
      arg = arg.slice(offset);
    }
    ptr = realloc(ptr, len, len = offset + arg.length * 3, 1) >>> 0;
    const view = getUint8ArrayMemory0().subarray(ptr + offset, ptr + len);
    const ret = cachedTextEncoder.encodeInto(arg, view);
    offset += ret.written;
    ptr = realloc(ptr, len, offset, 1) >>> 0;
  }
  WASM_VECTOR_LEN = offset;
  return ptr;
}
var cachedTextDecoder = new TextDecoder("utf-8", { ignoreBOM: true, fatal: true });
cachedTextDecoder.decode();
var MAX_SAFARI_DECODE_BYTES = 2146435072;
var numBytesDecoded = 0;
function decodeText(ptr, len) {
  numBytesDecoded += len;
  if (numBytesDecoded >= MAX_SAFARI_DECODE_BYTES) {
    cachedTextDecoder = new TextDecoder("utf-8", { ignoreBOM: true, fatal: true });
    cachedTextDecoder.decode();
    numBytesDecoded = len;
  }
  return cachedTextDecoder.decode(getUint8ArrayMemory0().subarray(ptr, ptr + len));
}
var cachedTextEncoder = new TextEncoder();
if (!("encodeInto" in cachedTextEncoder)) {
  cachedTextEncoder.encodeInto = function(arg, view) {
    const buf = cachedTextEncoder.encode(arg);
    view.set(buf);
    return {
      read: arg.length,
      written: buf.length
    };
  };
}
var WASM_VECTOR_LEN = 0;
var wasmModule;
var wasmInstance;
var wasm;
function __wbg_finalize_init(instance, module2) {
  wasmInstance = instance;
  wasm = instance.exports;
  wasmModule = module2;
  cachedDataViewMemory0 = null;
  cachedUint8ArrayMemory0 = null;
  wasm.__wbindgen_start();
  return wasm;
}
async function __wbg_load(module2, imports) {
  if (typeof Response === "function" && module2 instanceof Response) {
    if (typeof WebAssembly.instantiateStreaming === "function") {
      try {
        return await WebAssembly.instantiateStreaming(module2, imports);
      } catch (e) {
        const validResponse = module2.ok && expectedResponseType(module2.type);
        if (validResponse && module2.headers.get("Content-Type") !== "application/wasm") {
          console.warn("`WebAssembly.instantiateStreaming` failed because your server does not serve Wasm with `application/wasm` MIME type. Falling back to `WebAssembly.instantiate` which is slower. Original error:\n", e);
        } else {
          throw e;
        }
      }
    }
    const bytes = await module2.arrayBuffer();
    return await WebAssembly.instantiate(bytes, imports);
  } else {
    const instance = await WebAssembly.instantiate(module2, imports);
    if (instance instanceof WebAssembly.Instance) {
      return { instance, module: module2 };
    } else {
      return instance;
    }
  }
  function expectedResponseType(type2) {
    switch (type2) {
      case "basic":
      case "cors":
      case "default":
        return true;
    }
    return false;
  }
}
async function __wbg_init(module_or_path) {
  if (wasm !== void 0) return wasm;
  if (module_or_path !== void 0) {
    if (Object.getPrototypeOf(module_or_path) === Object.prototype) {
      ({ module_or_path } = module_or_path);
    } else {
      console.warn("using deprecated parameters for the initialization function; pass a single object instead");
    }
  }
  if (module_or_path === void 0) {
    module_or_path = void 0;
  }
  const imports = __wbg_get_imports();
  if (typeof module_or_path === "string" || typeof Request === "function" && module_or_path instanceof Request || typeof URL === "function" && module_or_path instanceof URL) {
    module_or_path = Promise.reject(new Error("WASM must be embedded bytes"));
  }
  const { instance, module: module2 } = await __wbg_load(await module_or_path, imports);
  return __wbg_finalize_init(instance, module2);
}
var GraphAnalysisPlugin = class extends import_obsidian18.Plugin {
  constructor() {
    super(...arguments);
    this.wasmInitialized = false;
    this.graphView = null;
    this.vaultAnalysisManager = null;
    this.dataStore = null;
    this.exclusionUtils = null;
    this.vaultScope = null;
    this.wasmLoadingPromise = null;
    this.wasmLoadingNotice = null;
    this.pluginIsLoaded = false;
  }
  async onload() {
    await this.loadSettings();
    this.exclusionUtils = new ExclusionUtils(this.app, this.settings);
    this.vaultScope = new VaultScope(this.app, this.exclusionUtils);
    void this.initializeWasmModule();
    this.app.workspace.onLayoutReady(() => {
      this.pluginIsLoaded = true;
    });
    this.registerView(
      GRAPH_ANALYSIS_VIEW_TYPE,
      (leaf) => new GraphAnalysisView(leaf, this)
    );
    this.registerView(
      CENTRALITY_RESULTS_VIEW_TYPE,
      (leaf) => new CentralityResultsView(leaf)
    );
    this.addSettingTab(new GraphAnalysisSettingTab(this.app, this));
    this.addCommand({
      id: "show-exclusion-stats",
      name: t("commands.showExclusionStats"),
      callback: () => this.showExclusionStats()
    });
    this.dataStore = new PluginDataStore(this);
    await this.dataStore.migrateLegacyCacheFromVaultFiles(this.app);
    this.vaultAnalysisManager = new VaultSemanticAnalysisManager(this.app, this.settings, this.dataStore);
    this.addCommand({
      id: "generate-vault-analysis",
      name: t("commands.generateVaultAnalysis"),
      callback: () => {
        if (this.vaultAnalysisManager) {
          void this.vaultAnalysisManager.generateVaultAnalysis();
        } else {
          new import_obsidian18.Notice(t("notices.vaultAnalysisNotInitialized"));
        }
      }
    });
    this.addCommand({
      id: "view-vault-analysis",
      name: t("commands.viewVaultAnalysis"),
      callback: () => {
        if (this.vaultAnalysisManager) {
          void this.vaultAnalysisManager.viewVaultAnalysisResults();
        } else {
          new import_obsidian18.Notice(t("notices.vaultAnalysisNotInitialized"));
        }
      }
    });
    this.addRibbonIcon("waypoints", t("ribbon.graphView"), () => {
      void (async () => {
        const existing = this.app.workspace.getLeavesOfType(GRAPH_ANALYSIS_VIEW_TYPE);
        if (existing.length > 0) {
          void this.app.workspace.revealLeaf(existing[0]);
          return;
        }
        await this.ensureWasmLoaded();
        const leaf = this.app.workspace.getLeaf(false);
        await leaf.setViewState({
          type: GRAPH_ANALYSIS_VIEW_TYPE,
          active: true
        });
        void this.app.workspace.revealLeaf(leaf);
      })();
    });
  }
  async loadSettings() {
    const data = await this.loadData();
    this.settings = Object.assign({}, DEFAULT_SETTINGS, data ?? {});
    configureI18n(this.settings.uiLanguage);
  }
  async saveSettings() {
    await this.saveData(this.settings);
    configureI18n(this.settings.uiLanguage);
    if (this.vaultAnalysisManager) {
      this.vaultAnalysisManager.updateSettings(this.settings);
    }
    if (this.exclusionUtils) {
      this.exclusionUtils.updateSettings(this.settings);
    }
    if (this.vaultScope && this.exclusionUtils) {
      this.vaultScope = new VaultScope(this.app, this.exclusionUtils);
    }
    const graphViews = this.app.workspace.getLeavesOfType(GRAPH_ANALYSIS_VIEW_TYPE);
    graphViews.forEach((leaf) => {
      if (leaf.view instanceof GraphAnalysisView) {
        leaf.view.updateSettings();
      }
    });
  }
  initializeWasmModule() {
    if (this.wasmLoadingPromise) return;
    this.wasmLoadingPromise = (async () => {
      try {
        this.wasmLoadingNotice = new import_obsidian18.Notice(t("notices.wasmInitializing"), 0);
        const wasmBinary = this.getWasmBinary();
        const wasmBinaryHash = await this.calculateBinaryHash(wasmBinary);
        await __wbg_init({ module_or_path: wasmBinary });
        const dataToSave = await this.loadData() || {};
        dataToSave.wasmHash = wasmBinaryHash;
        await this.saveData(dataToSave);
        this.wasmInitialized = true;
        if (this.wasmLoadingNotice) {
          this.wasmLoadingNotice.hide();
          this.wasmLoadingNotice = null;
        }
      } catch (error) {
        if (this.wasmLoadingNotice) {
          this.wasmLoadingNotice.hide();
          this.wasmLoadingNotice = null;
        }
        new import_obsidian18.Notice(t("notices.wasmInitFailed", { message: error.message }));
        this.wasmLoadingPromise = null;
      }
    })();
  }
  /** WASM binary embedded in main.js at build time (esbuild binary loader). */
  getWasmBinary() {
    const copy2 = embeddedWasmBytes.slice();
    return copy2.buffer.slice(copy2.byteOffset, copy2.byteOffset + copy2.byteLength);
  }
  calculateBinaryHash(buffer) {
    const array2 = new Uint8Array(buffer);
    const startBytes = array2.slice(0, Math.min(1024, array2.length));
    const endBytes = array2.slice(Math.max(0, array2.length - 1024));
    let hash = 0;
    for (let i = 0; i < startBytes.length; i++) {
      hash = (hash << 5) - hash + startBytes[i];
      hash |= 0;
    }
    for (let i = 0; i < endBytes.length; i++) {
      hash = (hash << 5) - hash + endBytes[i];
      hash |= 0;
    }
    return Promise.resolve(hash.toString(16));
  }
  async ensureWasmLoaded() {
    if (this.wasmInitialized) {
      return Promise.resolve();
    }
    if (this.wasmLoadingPromise) {
      return this.wasmLoadingPromise;
    }
    void this.initializeWasmModule();
    return this.wasmLoadingPromise;
  }
  onunload() {
    if (this.wasmLoadingNotice) {
      this.wasmLoadingNotice.hide();
      this.wasmLoadingNotice = null;
    }
    if (this.vaultAnalysisManager) {
      this.vaultAnalysisManager.destroy();
      this.vaultAnalysisManager = null;
    }
    this.wasmInitialized = false;
    this.wasmLoadingPromise = null;
    const doc = this.app.workspace.containerEl.ownerDocument;
    doc.body.removeClass("graph-analysis-hide-status-bar");
    doc.body.classList.remove("graph-view-dragging");
    doc.body.classList.remove("graph-analysis-active");
  }
  async analyzeCentrality(algorithm) {
    await this.ensureWasmLoaded();
    try {
      await this.buildGraphFromVault();
      let results;
      switch (algorithm) {
        case "degree":
          results = this.calculateDegreeCentralityCached();
          break;
        case "eigenvector":
          results = this.calculateEigenvectorCentralityCached();
          break;
        case "betweenness":
          results = this.calculateBetweennessCentralityCached();
          break;
        case "closeness":
          results = this.calculateClosenessCentralityCached();
          break;
      }
      this.displayResults(results, `${algorithm.charAt(0).toUpperCase() + algorithm.slice(1)} Centrality`);
    } catch (error) {
      new import_obsidian18.Notice(t("notices.analyzeCentralityFailed", {
        algorithm,
        message: error.message
      }));
    }
  }
  /**
   * Builds the graph from the vault files and links.
   * This is the main entry point for creating the graph from Obsidian notes.
   */
  async buildGraphFromVault() {
    await this.ensureWasmLoaded();
    const graphData = this.buildGraphDataFromVault();
    const vaultData = this.createVaultDataFromGraph(graphData);
    this.processJsonResult(
      build_graph_from_vault(JSON.stringify(vaultData)),
      "Graph Building"
    );
    return graphData;
  }
  /**
   * Creates the GraphData structure by analyzing vault files and their links.
   * This is extracted as a separate method to avoid code duplication.
   */
  buildGraphDataFromVault() {
    const files = this.getVaultFiles();
    const nodes = files.map((file) => file.path);
    const links = [];
    const pathToIndex = /* @__PURE__ */ new Map();
    nodes.forEach((path2, index2) => {
      pathToIndex.set(path2, index2);
    });
    for (const file of files) {
      const sourceIndex = pathToIndex.get(file.path);
      if (sourceIndex === void 0) continue;
      const abstractFile = this.app.vault.getAbstractFileByPath(file.path);
      const cache = abstractFile instanceof import_obsidian18.TFile ? this.app.metadataCache.getFileCache(abstractFile) : null;
      if (!cache) continue;
      const allLinks = [
        ...cache.links || [],
        ...cache.embeds || [],
        ...cache.frontmatterLinks || []
      ];
      for (const link of allLinks) {
        const resolvedFile = this.app.metadataCache.getFirstLinkpathDest(link.link, file.path);
        if (resolvedFile) {
          const targetIndex = pathToIndex.get(resolvedFile.path);
          if (targetIndex !== void 0) {
            const minIndex = Math.min(sourceIndex, targetIndex);
            const maxIndex = Math.max(sourceIndex, targetIndex);
            if (!links.some(([s, t2]) => s === minIndex && t2 === maxIndex)) {
              links.push([minIndex, maxIndex]);
            }
          }
        }
      }
    }
    return { nodes, edges: links };
  }
  getIncludedMarkdownFiles() {
    if (!this.vaultScope) {
      return this.app.vault.getMarkdownFiles();
    }
    return this.vaultScope.getIncludedMarkdownFiles();
  }
  getVaultFiles() {
    return this.getIncludedMarkdownFiles().map((file) => ({ path: file.path }));
  }
  /**
   * Helper method to process centrality calculation results.
   * This eliminates code duplication across the different centrality methods.
   * 
   * @param jsonResult The raw JSON result from WASM
   * @param centralityType The type of centrality being calculated
   * @returns Processed Node array with normalized centrality values
   */
  processCentralityResult(jsonResult, centralityType) {
    const parsed = JSON.parse(jsonResult);
    if (parsed && typeof parsed === "object" && "error" in parsed && typeof parsed.error === "string") {
      throw new Error(parsed.error);
    }
    if (!Array.isArray(parsed)) {
      throw new Error(`${centralityType} centrality result is not an array`);
    }
    const parsedResult = parsed;
    return parsedResult.map((node) => {
      const centralityScores = {
        degree: node.centrality?.degree,
        eigenvector: node.centrality?.eigenvector,
        betweenness: node.centrality?.betweenness,
        closeness: node.centrality?.closeness
      };
      centralityScores[centralityType] = centralityScores[centralityType] ?? 0;
      return {
        node_id: node.node_id ?? 0,
        node_name: node.node_name ?? "",
        centrality: centralityScores
      };
    });
  }
  calculateDegreeCentralityCached() {
    return this.processCentralityResult(calculate_degree_centrality_cached(), "degree");
  }
  calculateEigenvectorCentralityCached() {
    return this.processCentralityResult(calculate_eigenvector_centrality_cached(), "eigenvector");
  }
  calculateBetweennessCentralityCached() {
    return this.processCentralityResult(calculate_betweenness_centrality_cached(), "betweenness");
  }
  calculateClosenessCentralityCached() {
    return this.processCentralityResult(calculate_closeness_centrality_cached(), "closeness");
  }
  /**
   * Helper method to process JSON results from Rust WASM side.
   * This eliminates code duplication in methods that return JSON results.
   * 
   * @param jsonResult The raw JSON result from WASM
   * @param errorContext A descriptive context for error messages
   * @returns The parsed result
   */
  processJsonResult(jsonResult, errorContext) {
    const parsed = JSON.parse(jsonResult);
    if (parsed && typeof parsed === "object" && "error" in parsed && typeof parsed.error === "string") {
      throw new Error(parsed.error);
    }
    return parsed;
  }
  getNodeNeighborsCached(nodeId) {
    return this.processJsonResult(
      get_node_neighbors_cached(nodeId),
      "Get Node Neighbors"
    );
  }
  clearGraphCache() {
    this.processJsonResult(
      clear_graph(),
      "Clear Graph"
    );
  }
  getGraphMetadata() {
    return this.processJsonResult(
      get_graph_metadata(),
      "Get Graph Metadata"
    );
  }
  async initializeGraphAndCalculateCentrality() {
    if (!this.wasmInitialized) {
      throw new Error("WASM module not initialized");
    }
    try {
      const graphData = await this.buildGraphFromVault();
      return {
        graphData,
        degreeCentrality: this.calculateDegreeCentralityCached()
      };
    } catch (error) {
      throw new Error(`Failed to initialize graph and calculate centrality: ${error.message}`);
    }
  }
  isFileExcluded(file) {
    if (!this.exclusionUtils) {
      return false;
    }
    return this.exclusionUtils.isFileExcluded(file);
  }
  displayResults(results, algorithmName) {
    void this.activateCentralityView(results, algorithmName);
  }
  showExclusionStats() {
    if (!this.exclusionUtils) {
      new import_obsidian18.Notice(t("notices.exclusionUtilsNotInitialized"));
      return;
    }
    try {
      const allFiles = this.vaultScope?.getAllMarkdownFiles() ?? this.app.vault.getMarkdownFiles();
      const stats = this.exclusionUtils.getExclusionStats(allFiles);
      new import_obsidian18.Notice(t("notices.exclusionStatsConsole", { count: stats.totalExcluded }));
    } catch {
      new import_obsidian18.Notice(t("notices.exclusionStatsError"));
    }
  }
  async activateCentralityView(results, algorithmName) {
    let leaf = this.app.workspace.getLeavesOfType(CENTRALITY_RESULTS_VIEW_TYPE)[0];
    let isNewLeaf = false;
    if (!leaf) {
      isNewLeaf = true;
      const rightSplit = this.app.workspace.getRightLeaf(false);
      if (rightSplit) {
        await rightSplit.setViewState({
          type: CENTRALITY_RESULTS_VIEW_TYPE,
          active: true
        });
        leaf = rightSplit;
      } else {
        return;
      }
    }
    if (isNewLeaf) {
      void this.app.workspace.revealLeaf(leaf);
    }
    const view = leaf?.view instanceof CentralityResultsView ? leaf.view : null;
    if (view) {
      await view.setResults(results, algorithmName);
    }
  }
  /**
   * Creates a VaultData structure from GraphData
   * Internal helper method used by both buildGraphFromVault and initializeGraphWithData
   */
  createVaultDataFromGraph(graphData) {
    const notes = graphData.nodes.map((node) => ({ id: node }));
    return {
      notes,
      links: graphData.edges
    };
  }
  /**
   * Initialize the graph with provided graph data directly.
   * This method allows for direct initialization of the graph with externally constructed data.
   * 
   * @param graphData The graph data to initialize with
   * @returns A Promise that resolves when initialization is complete
   */
  async initializeGraphWithData(graphData) {
    await this.ensureWasmLoaded();
    const vaultData = this.createVaultDataFromGraph(graphData);
    this.processJsonResult(
      build_graph_from_vault(JSON.stringify(vaultData)),
      "Graph Initialization"
    );
  }
};
/*! Bundled license information:

chroma-js/src/utils/contrastAPCA.js:
  (**
   * @license
   *
   * The APCA contrast prediction algorithm is based of the formulas published
   * in the APCA-1.0.98G specification by Myndex. The specification is available at:
   * https://raw.githubusercontent.com/Myndex/apca-w3/master/images/APCAw3_0.1.17_APCA0.0.98G.svg
   *
   * Note that the APCA implementation is still beta, so please update to
   * future versions of chroma.js when they become available.
   *
   * You can read more about the APCA Readability Criterion at
   * https://readtech.org/ARC/
   *)
*/

/* nosourcemap */