Diagram Widgets

DAG layout

jsx
// generated by @readrun/widgets — edit .readrun/widgets/flow-dag-demo.tsx, then re-run rr
// @readrun/widgets@10f3ae2 — generated 2026-08-01T09:20:59Z
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __commonJS = (cb, mod) => function __require() {
  return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
};
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 __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
  // If the importer is in node compatibility mode or this is not an ESM
  // file that has been converted to a CommonJS file using a Babel-
  // compatible transform (i.e. "__esModule" has not been set), then set
  // "default" to the CommonJS "module.exports" for node compatibility.
  isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
  mod
));

// globals:react
var require_react = __commonJS({
  "globals:react"(exports, module) {
    module.exports = globalThis.React;
  }
});

// globals:react/jsx-runtime
var require_jsx_runtime = __commonJS({
  "globals:react/jsx-runtime"(exports, module) {
    var React8 = globalThis.React;
    function jsx9(type, props, key) {
      const nextProps = key === void 0 ? props : Object.assign({}, props, { key });
      return React8.createElement(type, nextProps);
    }
    module.exports = { Fragment: React8.Fragment, jsx: jsx9, jsxs: jsx9 };
  }
});

// docs/.readrun/widgets/flow-dag-demo.tsx
var import_react7 = __toESM(require_react(), 1);

// src/widgets/diagram/Flow.tsx
var import_react3 = __toESM(require_react(), 1);

// src/widgets/diagram/layout/dag.ts
function dag(nodes2, edges2, opts) {
  const rankSep = opts?.rankSeparation ?? 120;
  const nodeSep = opts?.nodeSeparation ?? 40;
  const defW = opts?.defaultWidth ?? 100;
  const defH = opts?.defaultHeight ?? 50;
  if (nodes2.length === 0) return [];
  const nodeIds = new Set(nodes2.map((n) => n.id));
  const outEdges = /* @__PURE__ */ new Map();
  const inDegree = /* @__PURE__ */ new Map();
  const edgeByTo = /* @__PURE__ */ new Map();
  for (const n of nodes2) {
    outEdges.set(n.id, []);
    inDegree.set(n.id, 0);
  }
  for (const e of edges2) {
    if (!nodeIds.has(e.from) || !nodeIds.has(e.to)) continue;
    outEdges.get(e.from).push(e.to);
    inDegree.set(e.to, (inDegree.get(e.to) ?? 0) + 1);
    if (!edgeByTo.has(e.to)) edgeByTo.set(e.to, e);
  }
  const rank = /* @__PURE__ */ new Map();
  const queue = [];
  for (const n of nodes2) {
    if ((inDegree.get(n.id) ?? 0) === 0) {
      queue.push(n.id);
      rank.set(n.id, 0);
    }
  }
  const sorted = [];
  while (queue.length > 0) {
    queue.sort();
    const id = queue.shift();
    sorted.push(id);
    for (const childId of outEdges.get(id) ?? []) {
      const newRank = (rank.get(id) ?? 0) + 1;
      if (!rank.has(childId) || rank.get(childId) < newRank) {
        rank.set(childId, newRank);
      }
      const newIn = (inDegree.get(childId) ?? 0) - 1;
      inDegree.set(childId, newIn);
      if (newIn === 0) {
        queue.push(childId);
      }
    }
  }
  if (sorted.length !== nodes2.length) {
    for (const e of edges2) {
      if ((rank.get(e.from) ?? -1) >= (rank.get(e.to) ?? -1) && sorted.includes(e.from)) {
      }
    }
    const unprocessed = new Set(nodes2.map((n) => n.id).filter((id) => !sorted.includes(id)));
    for (const e of edges2) {
      if (unprocessed.has(e.to) || unprocessed.has(e.from)) {
        throw new Error(
          `dag layout: cycle detected. Edge "${e.id}" (${e.from} \u2192 ${e.to}) is part of a cycle.`
        );
      }
    }
    throw new Error("dag layout: cycle detected in the graph.");
  }
  const rankGroups = /* @__PURE__ */ new Map();
  for (const [id, r] of rank.entries()) {
    if (!rankGroups.has(r)) rankGroups.set(r, []);
    rankGroups.get(r).push(id);
  }
  for (const group of rankGroups.values()) {
    group.sort();
  }
  const nodeById = new Map(nodes2.map((n) => [n.id, n]));
  const positioned = /* @__PURE__ */ new Map();
  for (const [r, group] of rankGroups.entries()) {
    const n = group.length;
    const totalWidth = n * defW + (n - 1) * nodeSep;
    const startX = -totalWidth / 2 + defW / 2;
    for (let i = 0; i < group.length; i++) {
      const id = group[i];
      const node = nodeById.get(id);
      const w = node.width ?? defW;
      const h = node.height ?? defH;
      positioned.set(id, {
        ...node,
        x: startX + i * (defW + nodeSep),
        y: r * rankSep,
        width: w,
        height: h
      });
    }
  }
  return nodes2.map((n) => positioned.get(n.id));
}

// src/widgets/diagram/layout/tree.ts
function tree(rootNode, childrenOf, opts) {
  const levelSep = opts?.levelSeparation ?? 100;
  const siblingSep = opts?.siblingSeparation ?? 40;
  const defW = opts?.defaultWidth ?? 100;
  const defH = opts?.defaultHeight ?? 50;
  const nextX = /* @__PURE__ */ new Map();
  function buildTree(node, depth) {
    const children = childrenOf(node).map((c) => buildTree(c, depth + 1));
    const internal = {
      source: node,
      children,
      depth,
      x: 0,
      y: depth * levelSep
    };
    if (children.length === 0) {
      const cur = nextX.get(depth) ?? 0;
      internal.x = cur;
      nextX.set(depth, cur + defW + siblingSep);
    } else {
      const leftX = children[0].x;
      const rightX = children[children.length - 1].x;
      internal.x = (leftX + rightX) / 2;
      const cur = nextX.get(depth) ?? 0;
      if (internal.x + defW / 2 > cur) {
        nextX.set(depth, internal.x + defW + siblingSep);
      }
    }
    return internal;
  }
  const root = buildTree(rootNode, 0);
  const result = [];
  function collect(n) {
    const node = n.source;
    result.push({
      ...node,
      x: n.x,
      y: n.y,
      width: node.width ?? defW,
      height: node.height ?? defH
    });
    for (const c of n.children) collect(c);
  }
  collect(root);
  return result;
}

// src/widgets/math/force.ts
function forceStep(nodes2, edges2, cfg) {
  const repulsion = cfg.repulsion ?? 4500;
  const springK = cfg.springK ?? 0.04;
  const springRest = cfg.springRest ?? 70;
  const damping = cfg.damping ?? 0.85;
  const centerPull = cfg.centerPull ?? 5e-3;
  const dt = cfg.dt ?? 1;
  const cx = cfg.width / 2;
  const cy = cfg.height / 2;
  for (let i = 0; i < nodes2.length; i++) {
    const ni = nodes2[i];
    if (ni.fixed) continue;
    let fx = 0;
    let fy = 0;
    for (let j = 0; j < nodes2.length; j++) {
      if (i === j) continue;
      const nj = nodes2[j];
      const dx = ni.x - nj.x;
      const dy = ni.y - nj.y;
      const d2 = dx * dx + dy * dy + 0.01;
      const f = repulsion / d2;
      const d = Math.sqrt(d2);
      fx += dx / d * f;
      fy += dy / d * f;
    }
    fx += (cx - ni.x) * centerPull;
    fy += (cy - ni.y) * centerPull;
    ni.vx = (ni.vx + fx * dt) * damping;
    ni.vy = (ni.vy + fy * dt) * damping;
  }
  for (const e of edges2) {
    const a = nodes2[e.s];
    const b = nodes2[e.t];
    if (!a || !b) continue;
    const dx = b.x - a.x;
    const dy = b.y - a.y;
    const d = Math.hypot(dx, dy) + 0.01;
    const f = springK * (d - springRest);
    const fx = dx / d * f;
    const fy = dy / d * f;
    if (!a.fixed) {
      a.vx += fx * dt;
      a.vy += fy * dt;
    }
    if (!b.fixed) {
      b.vx -= fx * dt;
      b.vy -= fy * dt;
    }
  }
  for (const n of nodes2) {
    if (n.fixed) continue;
    n.x += n.vx * dt;
    n.y += n.vy * dt;
    const m = 24;
    if (n.x < m) {
      n.x = m;
      n.vx *= -0.4;
    }
    if (n.x > cfg.width - m) {
      n.x = cfg.width - m;
      n.vx *= -0.4;
    }
    if (n.y < m) {
      n.y = m;
      n.vy *= -0.4;
    }
    if (n.y > cfg.height - m) {
      n.y = cfg.height - m;
      n.vy *= -0.4;
    }
  }
}

// src/widgets/math/random.ts
function mulberry32(seed) {
  let s = seed >>> 0;
  return () => {
    s = s + 1831565813 >>> 0;
    let t = s;
    t = Math.imul(t ^ t >>> 15, t | 1);
    t ^= t + Math.imul(t ^ t >>> 7, t | 61);
    return ((t ^ t >>> 14) >>> 0) / 4294967296;
  };
}

// src/widgets/diagram/layout/force.ts
function force(nodes2, edges2, opts) {
  if (nodes2.length === 0) return [];
  const iterations = opts?.iterations ?? 300;
  const width = opts?.width ?? 800;
  const height = opts?.height ?? 600;
  const seed = opts?.seed ?? 1;
  const defW = opts?.defaultWidth ?? 100;
  const defH = opts?.defaultHeight ?? 50;
  const rng = mulberry32(seed);
  const indexById = new Map(nodes2.map((n, i) => [n.id, i]));
  const forceNodes = nodes2.map((_n, i) => ({
    id: i,
    x: width / 2 + (rng() - 0.5) * 200,
    y: height / 2 + (rng() - 0.5) * 200,
    vx: 0,
    vy: 0
  }));
  const forceEdges = edges2.map((e) => {
    const s = indexById.get(e.from);
    const t = indexById.get(e.to);
    if (s === void 0 || t === void 0) return null;
    return { s, t };
  }).filter((e) => e !== null);
  const cfg = { width, height };
  for (let i = 0; i < iterations; i++) {
    forceStep(forceNodes, forceEdges, cfg);
  }
  return nodes2.map((node, i) => ({
    ...node,
    x: forceNodes[i].x,
    y: forceNodes[i].y,
    width: node.width ?? defW,
    height: node.height ?? defH
  }));
}

// src/widgets/diagram/edge/ports.ts
function nodePorts(node) {
  const { x: cx, y: cy, width, height } = node;
  const w2 = width / 2;
  const h2 = height / 2;
  return {
    top: { x: cx, y: cy - h2, dir: { dx: 0, dy: -1 } },
    right: { x: cx + w2, y: cy, dir: { dx: 1, dy: 0 } },
    bottom: { x: cx, y: cy + h2, dir: { dx: 0, dy: 1 } },
    left: { x: cx - w2, y: cy, dir: { dx: -1, dy: 0 } }
  };
}
function selectPort(ports, targetVec, exclude) {
  const len = Math.hypot(targetVec.x, targetVec.y) || 1;
  const tx = targetVec.x / len;
  const ty = targetVec.y / len;
  const ranked = Object.keys(ports).map((name) => ({
    name,
    port: ports[name],
    score: ports[name].dir.dx * tx + ports[name].dir.dy * ty
  })).sort((a, b) => b.score - a.score);
  if (exclude && exclude.size > 0) {
    const free = ranked.find((r) => !exclude.has(r.name));
    if (free) return { name: free.name, port: free.port };
  }
  const top = ranked[0];
  return { name: top.name, port: top.port };
}
function selectEdgePorts(fromNode, toNode, opts) {
  const dx = toNode.x - fromNode.x;
  const dy = toNode.y - fromNode.y;
  const fromPorts = nodePorts(fromNode);
  const toPorts = nodePorts(toNode);
  const fromSel = selectPort(fromPorts, { x: dx, y: dy }, opts?.excludeFrom);
  const toSel = selectPort(toPorts, { x: -dx, y: -dy }, opts?.excludeTo);
  return { from: fromSel.port, to: toSel.port, fromName: fromSel.name, toName: toSel.name };
}

// src/widgets/diagram/edge/router.ts
function straightWithPorts(from, to) {
  return `M ${num(from.x)} ${num(from.y)} L ${num(to.x)} ${num(to.y)}`;
}
function curveWithPorts(from, to) {
  const dist = Math.hypot(to.x - from.x, to.y - from.y);
  const offset = Math.max(20, 0.4 * dist);
  const c1x = from.x + from.dir.dx * offset;
  const c1y = from.y + from.dir.dy * offset;
  const c2x = to.x + to.dir.dx * offset;
  const c2y = to.y + to.dir.dy * offset;
  return `M ${num(from.x)} ${num(from.y)} C ${num(c1x)} ${num(c1y)} ${num(c2x)} ${num(c2y)} ${num(to.x)} ${num(to.y)}`;
}
function orthogonalWithPorts(from, to, opts) {
  const buffer = opts?.buffer ?? 20;
  const sx = from.x;
  const sy = from.y;
  const tx = to.x;
  const ty = to.y;
  const sgx = sx + from.dir.dx * buffer;
  const sgy = sy + from.dir.dy * buffer;
  const tgx = tx + to.dir.dx * buffer;
  const tgy = ty + to.dir.dy * buffer;
  const srcHoriz = from.dir.dx !== 0;
  const tgtHoriz = to.dir.dx !== 0;
  let mid;
  if (srcHoriz && tgtHoriz) {
    const midX = (sgx + tgx) / 2;
    mid = `L ${num(midX)} ${num(sgy)} L ${num(midX)} ${num(tgy)}`;
  } else if (!srcHoriz && !tgtHoriz) {
    const midY = (sgy + tgy) / 2;
    mid = `L ${num(sgx)} ${num(midY)} L ${num(tgx)} ${num(midY)}`;
  } else if (srcHoriz && !tgtHoriz) {
    mid = `L ${num(tgx)} ${num(sgy)}`;
  } else {
    mid = `L ${num(sgx)} ${num(tgy)}`;
  }
  return `M ${num(sx)} ${num(sy)} L ${num(sgx)} ${num(sgy)} ${mid} L ${num(tgx)} ${num(tgy)} L ${num(tx)} ${num(ty)}`;
}
function num(n) {
  return n.toFixed(2).replace(/\.?0+$/, "");
}

// src/widgets/diagram/FlowNode.tsx
var import_react2 = __toESM(require_react(), 1);

// src/widgets/diagram/viewport.ts
var import_react = __toESM(require_react(), 1);

// src/widgets/interaction/coords.ts
function applyMatrix(m, x, y) {
  return {
    x: m.a * x + m.c * y + m.e,
    y: m.b * x + m.d * y + m.f
  };
}
function screenToViewBox(target, clientX, clientY) {
  const ctm = target.getScreenCTM();
  if (!ctm) return null;
  const inv = ctm.inverse();
  return applyMatrix(inv, clientX, clientY);
}

// src/widgets/diagram/viewport.ts
var MIN_ZOOM = 0.25;
var MAX_ZOOM = 3;
function clientToFlow(target, clientX, clientY, innerDx, innerDy, view) {
  const point = screenToViewBox(target, clientX, clientY);
  if (!point) return null;
  return {
    x: (point.x - innerDx - view.panX) / view.zoom,
    y: (point.y - innerDy - view.panY) / view.zoom
  };
}
function panFromPointer(startView, startPointer, currentPointer) {
  return {
    ...startView,
    panX: startView.panX + currentPointer.x - startPointer.x,
    panY: startView.panY + currentPointer.y - startPointer.y
  };
}
function zoomFromWheel(zoom, deltaY) {
  const factor = 1 - deltaY * 1e-3;
  return Math.max(MIN_ZOOM, Math.min(MAX_ZOOM, zoom * factor));
}
function useFlowViewport(svgRef) {
  const [view, setView] = import_react.default.useState({
    panX: 0,
    panY: 0,
    zoom: 1
  });
  const panStateRef = import_react.default.useRef(null);
  const onPointerDown = import_react.default.useCallback(
    (event) => {
      if (event.target !== svgRef.current) return;
      const point = screenToViewBox(event.currentTarget, event.clientX, event.clientY);
      if (!point) return;
      event.currentTarget.setPointerCapture(event.pointerId);
      panStateRef.current = { startPointer: point, startView: view };
    },
    [svgRef, view]
  );
  const onPointerMove = import_react.default.useCallback(
    (event) => {
      const panState = panStateRef.current;
      if (!panState) return;
      const point = screenToViewBox(event.currentTarget, event.clientX, event.clientY);
      if (!point) return;
      setView(panFromPointer(panState.startView, panState.startPointer, point));
    },
    []
  );
  const onPointerUp = import_react.default.useCallback(
    (event) => {
      if (event.currentTarget.hasPointerCapture(event.pointerId)) {
        event.currentTarget.releasePointerCapture(event.pointerId);
      }
      panStateRef.current = null;
    },
    []
  );
  const onWheel = import_react.default.useCallback((event) => {
    event.preventDefault();
    setView((current) => ({
      ...current,
      zoom: zoomFromWheel(current.zoom, event.deltaY)
    }));
  }, []);
  return { view, onPointerDown, onPointerMove, onPointerUp, onWheel };
}

// src/widgets/diagram/FlowNode.tsx
var import_jsx_runtime = __toESM(require_jsx_runtime(), 1);
var NODE_FILL = "var(--bg, #ffffff)";
var NODE_STROKE = "var(--text, #1f2328)";
function NodeShape({
  shape,
  width,
  height
}) {
  const sharedProps = {
    fill: NODE_FILL,
    stroke: NODE_STROKE,
    strokeWidth: 1
  };
  if (shape === "circle") {
    return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
      "circle",
      {
        cx: width / 2,
        cy: height / 2,
        r: Math.min(width, height) / 2,
        ...sharedProps
      }
    );
  }
  if (shape === "ellipse") {
    return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
      "ellipse",
      {
        cx: width / 2,
        cy: height / 2,
        rx: width / 2,
        ry: height / 2,
        ...sharedProps
      }
    );
  }
  if (shape === "diamond") {
    return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
      "polygon",
      {
        points: `${width / 2},0 ${width},${height / 2} ${width / 2},${height} 0,${height / 2}`,
        ...sharedProps
      }
    );
  }
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
    "rect",
    {
      width,
      height,
      x: 0,
      y: 0,
      ...sharedProps,
      rx: 0
    }
  );
}
function FlowNode({
  node,
  svgRef,
  innerDx,
  innerDy,
  view,
  onClick,
  onHover,
  onDragMove,
  draggable
}) {
  const offsetRef = import_react2.default.useRef(null);
  const movedRef = import_react2.default.useRef(false);
  const onPointerDown = (event) => {
    if (!draggable || !svgRef.current) return;
    event.stopPropagation();
    event.preventDefault();
    event.currentTarget.setPointerCapture(event.pointerId);
    const point = clientToFlow(
      svgRef.current,
      event.clientX,
      event.clientY,
      innerDx,
      innerDy,
      view
    );
    if (!point) return;
    offsetRef.current = { x: point.x - node.x, y: point.y - node.y };
    movedRef.current = false;
  };
  const onPointerMove = (event) => {
    const offset = offsetRef.current;
    if (!offset || !svgRef.current) return;
    const point = clientToFlow(
      svgRef.current,
      event.clientX,
      event.clientY,
      innerDx,
      innerDy,
      view
    );
    if (!point) return;
    onDragMove(point.x - offset.x, point.y - offset.y);
    movedRef.current = true;
  };
  const onPointerUp = (event) => {
    if (event.currentTarget.hasPointerCapture(event.pointerId)) {
      event.currentTarget.releasePointerCapture(event.pointerId);
    }
    offsetRef.current = null;
    if (!movedRef.current && onClick) {
      onClick(node);
    }
  };
  const { x, y, width, height, id } = node;
  const label = typeof node["label"] === "string" ? node["label"] : id;
  const shape = node.shape ?? "rect";
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
    "g",
    {
      transform: `translate(${x - width / 2}, ${y - height / 2})`,
      style: {
        cursor: draggable ? "grab" : onClick ? "pointer" : "default",
        touchAction: "none"
      },
      onPointerDown,
      onPointerMove,
      onPointerUp,
      onPointerCancel: onPointerUp,
      onMouseEnter: onHover ? () => onHover(node) : void 0,
      onMouseLeave: onHover ? () => onHover(null) : void 0,
      children: [
        /* @__PURE__ */ (0, import_jsx_runtime.jsx)(NodeShape, { shape, width, height }),
        /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
          "text",
          {
            x: width / 2,
            y: height / 2,
            dominantBaseline: "middle",
            textAnchor: "middle",
            fontSize: 11,
            fill: "var(--text, #1f2328)",
            fontFamily: "var(--font-body, ui-sans-serif, system-ui, sans-serif)",
            style: { userSelect: "none", pointerEvents: "none" },
            children: label
          }
        )
      ]
    }
  );
}

// src/widgets/diagram/Flow.tsx
var import_jsx_runtime2 = __toESM(require_jsx_runtime(), 1);
var ARROW_ID = "readrun-widget-flow-arrow";
var DEF_W = 100;
var DEF_H = 50;
var EDGE_STROKE = "var(--text-muted, #656d76)";
var INNER_DX_FACTOR = 0.5;
var INNER_DY = 20;
function defaultRenderEdge(pathStr, edge2) {
  return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
    "path",
    {
      d: pathStr,
      stroke: EDGE_STROKE,
      strokeWidth: 1.5,
      fill: "none",
      markerEnd: `url(#${ARROW_ID})`
    },
    edge2.id
  );
}
function pathFromPorts(router, from, to) {
  switch (router) {
    case "straight":
      return straightWithPorts(from, to);
    case "curve":
      return curveWithPorts(from, to);
    case "orthogonal":
    default:
      return orthogonalWithPorts(from, to);
  }
}
function Flow({
  nodes: nodes2,
  edges: edges2,
  layout: layoutMode,
  childrenOf,
  rootId,
  edgeRouter,
  renderNode,
  renderEdge,
  width,
  height,
  onNodeClick,
  onNodeHover,
  draggable = true
}) {
  const svgRef = import_react3.default.useRef(null);
  const innerDx = width * INNER_DX_FACTOR;
  const innerDy = INNER_DY;
  const [overrides, setOverrides] = import_react3.default.useState({});
  const viewport = useFlowViewport(svgRef);
  const { view } = viewport;
  const updateOverride = import_react3.default.useCallback((id, x, y) => {
    setOverrides((prev) => ({ ...prev, [id]: { x, y } }));
  }, []);
  const layoutNodes = import_react3.default.useMemo(() => {
    if (layoutMode === "manual") {
      return nodes2.map((node) => ({
        ...node,
        x: node.x ?? 0,
        y: node.y ?? 0,
        width: node.width ?? DEF_W,
        height: node.height ?? DEF_H
      }));
    }
    if (layoutMode === "dag") return dag(nodes2, edges2);
    if (layoutMode === "tree") {
      const root = nodes2.find((node) => node.id === rootId) ?? nodes2[0];
      return root ? tree(root, childrenOf ?? (() => []), {
        levelSeparation: height / Math.max(4, nodes2.length)
      }) : [];
    }
    return force(nodes2, edges2, { width, height });
  }, [childrenOf, edges2, height, layoutMode, nodes2, rootId, width]);
  const positioned = import_react3.default.useMemo(
    () => layoutNodes.map((node) => {
      const override = overrides[node.id];
      return override ? { ...node, ...override } : node;
    }),
    [layoutNodes, overrides]
  );
  const posById = import_react3.default.useMemo(
    () => new Map(positioned.map((node) => [node.id, node])),
    [positioned]
  );
  const router = edgeRouter ?? (layoutMode === "force" ? "curve" : layoutMode === "manual" ? "straight" : "orthogonal");
  const edgeElements = import_react3.default.useMemo(() => {
    const usedPorts = /* @__PURE__ */ new Map();
    return edges2.map((edge2) => {
      const fromNode = posById.get(edge2.from);
      const toNode = posById.get(edge2.to);
      if (!fromNode || !toNode) return null;
      const fromUsed = usedPorts.get(edge2.from) ?? /* @__PURE__ */ new Set();
      const toUsed = usedPorts.get(edge2.to) ?? /* @__PURE__ */ new Set();
      const { from, to, fromName, toName } = selectEdgePorts(fromNode, toNode, {
        excludeFrom: fromUsed,
        excludeTo: toUsed
      });
      fromUsed.add(fromName);
      toUsed.add(toName);
      usedPorts.set(edge2.from, fromUsed);
      usedPorts.set(edge2.to, toUsed);
      const path = pathFromPorts(router, from, to);
      return renderEdge ? renderEdge(path, edge2, fromNode, toNode) : defaultRenderEdge(path, edge2);
    }).filter(Boolean);
  }, [edges2, posById, renderEdge, router]);
  const nodeElements = positioned.map((n) => {
    if (renderNode) return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react3.default.Fragment, { children: renderNode(n) }, n.id);
    return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
      FlowNode,
      {
        node: n,
        svgRef,
        innerDx,
        innerDy,
        view,
        draggable,
        onClick: onNodeClick,
        onHover: onNodeHover,
        onDragMove: (x, y) => updateOverride(n.id, x, y)
      },
      n.id
    );
  });
  const innerTransform = `translate(${innerDx + view.panX}, ${innerDy + view.panY}) scale(${view.zoom})`;
  return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
    "div",
    {
      style: {
        position: "relative",
        background: "var(--card-bg, #ffffff)",
        border: "1px solid var(--border, #d0d7de)",
        overflow: "hidden"
      },
      children: [
        /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
          "svg",
          {
            ref: svgRef,
            viewBox: `0 0 ${width} ${height}`,
            width,
            height,
            style: { display: "block", maxWidth: "100%", touchAction: "none" },
            onPointerDown: viewport.onPointerDown,
            onPointerMove: viewport.onPointerMove,
            onPointerUp: viewport.onPointerUp,
            onPointerCancel: viewport.onPointerUp,
            onWheel: viewport.onWheel,
            children: [
              /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("defs", { children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
                "marker",
                {
                  id: ARROW_ID,
                  viewBox: "0 0 10 10",
                  refX: 10,
                  refY: 5,
                  markerWidth: 6,
                  markerHeight: 6,
                  orient: "auto-start-reverse",
                  children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M 0 0 L 10 5 L 0 10 z", fill: EDGE_STROKE })
                }
              ) }),
              /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("g", { transform: innerTransform, children: [
                edgeElements,
                nodeElements
              ] })
            ]
          }
        ),
        draggable && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
          "div",
          {
            style: {
              position: "absolute",
              bottom: 6,
              right: 8,
              fontSize: 11,
              color: "var(--text-muted, #656d76)",
              fontFamily: "var(--font-mono, ui-monospace, monospace)",
              letterSpacing: "0.04em",
              pointerEvents: "none"
            },
            children: "drag nodes \u2022 drag empty \u2022 scroll to zoom"
          }
        )
      ]
    }
  );
}

// src/widgets/primitives/index.tsx
var import_react6 = __toESM(require_react());

// src/presentation/components/ui/Label.tsx
var import_jsx_runtime3 = __toESM(require_jsx_runtime(), 1);

// src/presentation/components/ui/Slider.tsx
var import_jsx_runtime4 = __toESM(require_jsx_runtime(), 1);

// src/presentation/components/ui/Switch.tsx
var import_jsx_runtime5 = __toESM(require_jsx_runtime(), 1);

// src/widgets/primitives/WidgetLayout.tsx
var import_react4 = __toESM(require_react(), 1);
var import_jsx_runtime6 = __toESM(require_jsx_runtime(), 1);
function VisualSlot({ children }) {
  return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_jsx_runtime6.Fragment, { children });
}
function ControlsSlot({ children }) {
  return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_jsx_runtime6.Fragment, { children });
}
function AsideSlot({ children }) {
  return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_jsx_runtime6.Fragment, { children });
}
VisualSlot.__widgetSlot = "visual";
ControlsSlot.__widgetSlot = "controls";
AsideSlot.__widgetSlot = "aside";
function extractSlots(children) {
  const slots = {};
  import_react4.default.Children.forEach(children, (child) => {
    if (import_react4.default.isValidElement(child)) {
      const t = child.type;
      if (t?.__widgetSlot) {
        slots[t.__widgetSlot] = child;
      }
    }
  });
  return slots;
}
function WidgetLayoutImpl(props) {
  const arrangement = props.arrangement ?? "visual-left";
  const slots = extractSlots(props.children);
  return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: `readrun-widget readrun-widget--${arrangement}`, children: [
    (props.title || props.subtitle || props.headMeta) && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
      "div",
      {
        className: "readrun-widget__head",
        style: { display: "flex", justifyContent: "space-between" },
        children: [
          /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { children: [
            props.title && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("h2", { className: "readrun-widget__title", children: props.title }),
            props.subtitle && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "readrun-widget__subtitle", children: props.subtitle })
          ] }),
          props.headMeta && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { children: props.headMeta })
        ]
      }
    ),
    /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "readrun-widget__body", children: [
      slots["visual"] && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "readrun-widget__visual", children: slots["visual"] }),
      (slots["controls"] || slots["aside"]) && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "readrun-widget__sidebar", children: [
        slots["controls"] && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "readrun-widget__controls", children: slots["controls"] }),
        slots["aside"] && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "readrun-widget__aside", children: [
          /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "readrun-widget__aside-label", children: "What to notice" }),
          slots["aside"]
        ] })
      ] })
    ] })
  ] });
}
var WidgetLayout = Object.assign(WidgetLayoutImpl, {
  Visual: VisualSlot,
  Controls: ControlsSlot,
  Aside: AsideSlot
});

// src/widgets/primitives/FormulaSteps.tsx
var import_react5 = __toESM(require_react(), 1);
var import_jsx_runtime7 = __toESM(require_jsx_runtime(), 1);

// src/widgets/primitives/index.tsx
function Shell({
  title,
  meta,
  children
}) {
  return /* @__PURE__ */ import_react6.default.createElement("div", { className: "viz-shell" }, (title || meta) && /* @__PURE__ */ import_react6.default.createElement("div", { className: "viz-shell-head" }, title && /* @__PURE__ */ import_react6.default.createElement("h2", null, title), meta && /* @__PURE__ */ import_react6.default.createElement("div", { className: "viz-shell-meta" }, meta)), children);
}
function Sub({ children }) {
  return /* @__PURE__ */ import_react6.default.createElement("p", { className: "viz-sub" }, children);
}
function Stage({
  children,
  style
}) {
  return /* @__PURE__ */ import_react6.default.createElement("div", { className: "viz-stage", style }, children);
}

// docs/.readrun/widgets/flow-dag-demo.tsx
var import_jsx_runtime8 = __toESM(require_jsx_runtime(), 1);
var nodes = [
  { id: "input", label: "Input", shape: "circle", width: 70, height: 70 },
  { id: "parse", label: "Parse" },
  { id: "validate", label: "Validate", shape: "diamond", width: 110, height: 60 },
  { id: "transform", label: "Transform" },
  { id: "filter", label: "Filter", shape: "ellipse", width: 110, height: 50 },
  { id: "output", label: "Output", shape: "circle", width: 70, height: 70 }
];
var edges = [
  { id: "e1", from: "input", to: "parse" },
  { id: "e2", from: "parse", to: "validate" },
  { id: "e3", from: "parse", to: "transform" },
  { id: "e4", from: "validate", to: "filter" },
  { id: "e5", from: "transform", to: "filter" },
  { id: "e6", from: "filter", to: "output" }
];
function FlowDagDemo() {
  return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(Shell, { title: "Flow / dag layout", children: [
    /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Sub, { children: "DAG layout with orthogonal edges. Mixed shapes: circle / rect / diamond / ellipse. Drag nodes, drag empty space to pan, scroll to zoom." }),
    /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Stage, { children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
      Flow,
      {
        nodes,
        edges,
        layout: "dag",
        edgeRouter: "orthogonal",
        width: 700,
        height: 520
      }
    ) })
  ] });
}

// docs/.readrun/widgets/flow-dag-demo.readrun-entry.ts
render(<FlowDagDemo />);

Tree layout

jsx
// generated by @readrun/widgets — edit .readrun/widgets/flow-tree-demo.tsx, then re-run rr
// @readrun/widgets@10f3ae2 — generated 2026-08-01T09:20:59Z
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __commonJS = (cb, mod) => function __require() {
  return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
};
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 __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
  // If the importer is in node compatibility mode or this is not an ESM
  // file that has been converted to a CommonJS file using a Babel-
  // compatible transform (i.e. "__esModule" has not been set), then set
  // "default" to the CommonJS "module.exports" for node compatibility.
  isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
  mod
));

// globals:react
var require_react = __commonJS({
  "globals:react"(exports, module) {
    module.exports = globalThis.React;
  }
});

// globals:react/jsx-runtime
var require_jsx_runtime = __commonJS({
  "globals:react/jsx-runtime"(exports, module) {
    var React8 = globalThis.React;
    function jsx9(type, props, key) {
      const nextProps = key === void 0 ? props : Object.assign({}, props, { key });
      return React8.createElement(type, nextProps);
    }
    module.exports = { Fragment: React8.Fragment, jsx: jsx9, jsxs: jsx9 };
  }
});

// docs/.readrun/widgets/flow-tree-demo.tsx
var import_react7 = __toESM(require_react(), 1);

// src/widgets/diagram/Flow.tsx
var import_react3 = __toESM(require_react(), 1);

// src/widgets/diagram/layout/dag.ts
function dag(nodes2, edges2, opts) {
  const rankSep = opts?.rankSeparation ?? 120;
  const nodeSep = opts?.nodeSeparation ?? 40;
  const defW = opts?.defaultWidth ?? 100;
  const defH = opts?.defaultHeight ?? 50;
  if (nodes2.length === 0) return [];
  const nodeIds = new Set(nodes2.map((n) => n.id));
  const outEdges = /* @__PURE__ */ new Map();
  const inDegree = /* @__PURE__ */ new Map();
  const edgeByTo = /* @__PURE__ */ new Map();
  for (const n of nodes2) {
    outEdges.set(n.id, []);
    inDegree.set(n.id, 0);
  }
  for (const e of edges2) {
    if (!nodeIds.has(e.from) || !nodeIds.has(e.to)) continue;
    outEdges.get(e.from).push(e.to);
    inDegree.set(e.to, (inDegree.get(e.to) ?? 0) + 1);
    if (!edgeByTo.has(e.to)) edgeByTo.set(e.to, e);
  }
  const rank = /* @__PURE__ */ new Map();
  const queue = [];
  for (const n of nodes2) {
    if ((inDegree.get(n.id) ?? 0) === 0) {
      queue.push(n.id);
      rank.set(n.id, 0);
    }
  }
  const sorted = [];
  while (queue.length > 0) {
    queue.sort();
    const id = queue.shift();
    sorted.push(id);
    for (const childId of outEdges.get(id) ?? []) {
      const newRank = (rank.get(id) ?? 0) + 1;
      if (!rank.has(childId) || rank.get(childId) < newRank) {
        rank.set(childId, newRank);
      }
      const newIn = (inDegree.get(childId) ?? 0) - 1;
      inDegree.set(childId, newIn);
      if (newIn === 0) {
        queue.push(childId);
      }
    }
  }
  if (sorted.length !== nodes2.length) {
    for (const e of edges2) {
      if ((rank.get(e.from) ?? -1) >= (rank.get(e.to) ?? -1) && sorted.includes(e.from)) {
      }
    }
    const unprocessed = new Set(nodes2.map((n) => n.id).filter((id) => !sorted.includes(id)));
    for (const e of edges2) {
      if (unprocessed.has(e.to) || unprocessed.has(e.from)) {
        throw new Error(
          `dag layout: cycle detected. Edge "${e.id}" (${e.from} \u2192 ${e.to}) is part of a cycle.`
        );
      }
    }
    throw new Error("dag layout: cycle detected in the graph.");
  }
  const rankGroups = /* @__PURE__ */ new Map();
  for (const [id, r] of rank.entries()) {
    if (!rankGroups.has(r)) rankGroups.set(r, []);
    rankGroups.get(r).push(id);
  }
  for (const group of rankGroups.values()) {
    group.sort();
  }
  const nodeById2 = new Map(nodes2.map((n) => [n.id, n]));
  const positioned = /* @__PURE__ */ new Map();
  for (const [r, group] of rankGroups.entries()) {
    const n = group.length;
    const totalWidth = n * defW + (n - 1) * nodeSep;
    const startX = -totalWidth / 2 + defW / 2;
    for (let i = 0; i < group.length; i++) {
      const id = group[i];
      const node = nodeById2.get(id);
      const w = node.width ?? defW;
      const h = node.height ?? defH;
      positioned.set(id, {
        ...node,
        x: startX + i * (defW + nodeSep),
        y: r * rankSep,
        width: w,
        height: h
      });
    }
  }
  return nodes2.map((n) => positioned.get(n.id));
}

// src/widgets/diagram/layout/tree.ts
function tree(rootNode, childrenOf2, opts) {
  const levelSep = opts?.levelSeparation ?? 100;
  const siblingSep = opts?.siblingSeparation ?? 40;
  const defW = opts?.defaultWidth ?? 100;
  const defH = opts?.defaultHeight ?? 50;
  const nextX = /* @__PURE__ */ new Map();
  function buildTree(node, depth) {
    const children = childrenOf2(node).map((c) => buildTree(c, depth + 1));
    const internal = {
      source: node,
      children,
      depth,
      x: 0,
      y: depth * levelSep
    };
    if (children.length === 0) {
      const cur = nextX.get(depth) ?? 0;
      internal.x = cur;
      nextX.set(depth, cur + defW + siblingSep);
    } else {
      const leftX = children[0].x;
      const rightX = children[children.length - 1].x;
      internal.x = (leftX + rightX) / 2;
      const cur = nextX.get(depth) ?? 0;
      if (internal.x + defW / 2 > cur) {
        nextX.set(depth, internal.x + defW + siblingSep);
      }
    }
    return internal;
  }
  const root = buildTree(rootNode, 0);
  const result = [];
  function collect(n) {
    const node = n.source;
    result.push({
      ...node,
      x: n.x,
      y: n.y,
      width: node.width ?? defW,
      height: node.height ?? defH
    });
    for (const c of n.children) collect(c);
  }
  collect(root);
  return result;
}

// src/widgets/math/force.ts
function forceStep(nodes2, edges2, cfg) {
  const repulsion = cfg.repulsion ?? 4500;
  const springK = cfg.springK ?? 0.04;
  const springRest = cfg.springRest ?? 70;
  const damping = cfg.damping ?? 0.85;
  const centerPull = cfg.centerPull ?? 5e-3;
  const dt = cfg.dt ?? 1;
  const cx = cfg.width / 2;
  const cy = cfg.height / 2;
  for (let i = 0; i < nodes2.length; i++) {
    const ni = nodes2[i];
    if (ni.fixed) continue;
    let fx = 0;
    let fy = 0;
    for (let j = 0; j < nodes2.length; j++) {
      if (i === j) continue;
      const nj = nodes2[j];
      const dx = ni.x - nj.x;
      const dy = ni.y - nj.y;
      const d2 = dx * dx + dy * dy + 0.01;
      const f = repulsion / d2;
      const d = Math.sqrt(d2);
      fx += dx / d * f;
      fy += dy / d * f;
    }
    fx += (cx - ni.x) * centerPull;
    fy += (cy - ni.y) * centerPull;
    ni.vx = (ni.vx + fx * dt) * damping;
    ni.vy = (ni.vy + fy * dt) * damping;
  }
  for (const e of edges2) {
    const a = nodes2[e.s];
    const b = nodes2[e.t];
    if (!a || !b) continue;
    const dx = b.x - a.x;
    const dy = b.y - a.y;
    const d = Math.hypot(dx, dy) + 0.01;
    const f = springK * (d - springRest);
    const fx = dx / d * f;
    const fy = dy / d * f;
    if (!a.fixed) {
      a.vx += fx * dt;
      a.vy += fy * dt;
    }
    if (!b.fixed) {
      b.vx -= fx * dt;
      b.vy -= fy * dt;
    }
  }
  for (const n of nodes2) {
    if (n.fixed) continue;
    n.x += n.vx * dt;
    n.y += n.vy * dt;
    const m = 24;
    if (n.x < m) {
      n.x = m;
      n.vx *= -0.4;
    }
    if (n.x > cfg.width - m) {
      n.x = cfg.width - m;
      n.vx *= -0.4;
    }
    if (n.y < m) {
      n.y = m;
      n.vy *= -0.4;
    }
    if (n.y > cfg.height - m) {
      n.y = cfg.height - m;
      n.vy *= -0.4;
    }
  }
}

// src/widgets/math/random.ts
function mulberry32(seed) {
  let s = seed >>> 0;
  return () => {
    s = s + 1831565813 >>> 0;
    let t = s;
    t = Math.imul(t ^ t >>> 15, t | 1);
    t ^= t + Math.imul(t ^ t >>> 7, t | 61);
    return ((t ^ t >>> 14) >>> 0) / 4294967296;
  };
}

// src/widgets/diagram/layout/force.ts
function force(nodes2, edges2, opts) {
  if (nodes2.length === 0) return [];
  const iterations = opts?.iterations ?? 300;
  const width = opts?.width ?? 800;
  const height = opts?.height ?? 600;
  const seed = opts?.seed ?? 1;
  const defW = opts?.defaultWidth ?? 100;
  const defH = opts?.defaultHeight ?? 50;
  const rng = mulberry32(seed);
  const indexById = new Map(nodes2.map((n, i) => [n.id, i]));
  const forceNodes = nodes2.map((_n, i) => ({
    id: i,
    x: width / 2 + (rng() - 0.5) * 200,
    y: height / 2 + (rng() - 0.5) * 200,
    vx: 0,
    vy: 0
  }));
  const forceEdges = edges2.map((e) => {
    const s = indexById.get(e.from);
    const t = indexById.get(e.to);
    if (s === void 0 || t === void 0) return null;
    return { s, t };
  }).filter((e) => e !== null);
  const cfg = { width, height };
  for (let i = 0; i < iterations; i++) {
    forceStep(forceNodes, forceEdges, cfg);
  }
  return nodes2.map((node, i) => ({
    ...node,
    x: forceNodes[i].x,
    y: forceNodes[i].y,
    width: node.width ?? defW,
    height: node.height ?? defH
  }));
}

// src/widgets/diagram/edge/ports.ts
function nodePorts(node) {
  const { x: cx, y: cy, width, height } = node;
  const w2 = width / 2;
  const h2 = height / 2;
  return {
    top: { x: cx, y: cy - h2, dir: { dx: 0, dy: -1 } },
    right: { x: cx + w2, y: cy, dir: { dx: 1, dy: 0 } },
    bottom: { x: cx, y: cy + h2, dir: { dx: 0, dy: 1 } },
    left: { x: cx - w2, y: cy, dir: { dx: -1, dy: 0 } }
  };
}
function selectPort(ports, targetVec, exclude) {
  const len = Math.hypot(targetVec.x, targetVec.y) || 1;
  const tx = targetVec.x / len;
  const ty = targetVec.y / len;
  const ranked = Object.keys(ports).map((name) => ({
    name,
    port: ports[name],
    score: ports[name].dir.dx * tx + ports[name].dir.dy * ty
  })).sort((a, b) => b.score - a.score);
  if (exclude && exclude.size > 0) {
    const free = ranked.find((r) => !exclude.has(r.name));
    if (free) return { name: free.name, port: free.port };
  }
  const top = ranked[0];
  return { name: top.name, port: top.port };
}
function selectEdgePorts(fromNode, toNode, opts) {
  const dx = toNode.x - fromNode.x;
  const dy = toNode.y - fromNode.y;
  const fromPorts = nodePorts(fromNode);
  const toPorts = nodePorts(toNode);
  const fromSel = selectPort(fromPorts, { x: dx, y: dy }, opts?.excludeFrom);
  const toSel = selectPort(toPorts, { x: -dx, y: -dy }, opts?.excludeTo);
  return { from: fromSel.port, to: toSel.port, fromName: fromSel.name, toName: toSel.name };
}

// src/widgets/diagram/edge/router.ts
function straightWithPorts(from, to) {
  return `M ${num(from.x)} ${num(from.y)} L ${num(to.x)} ${num(to.y)}`;
}
function curveWithPorts(from, to) {
  const dist = Math.hypot(to.x - from.x, to.y - from.y);
  const offset = Math.max(20, 0.4 * dist);
  const c1x = from.x + from.dir.dx * offset;
  const c1y = from.y + from.dir.dy * offset;
  const c2x = to.x + to.dir.dx * offset;
  const c2y = to.y + to.dir.dy * offset;
  return `M ${num(from.x)} ${num(from.y)} C ${num(c1x)} ${num(c1y)} ${num(c2x)} ${num(c2y)} ${num(to.x)} ${num(to.y)}`;
}
function orthogonalWithPorts(from, to, opts) {
  const buffer = opts?.buffer ?? 20;
  const sx = from.x;
  const sy = from.y;
  const tx = to.x;
  const ty = to.y;
  const sgx = sx + from.dir.dx * buffer;
  const sgy = sy + from.dir.dy * buffer;
  const tgx = tx + to.dir.dx * buffer;
  const tgy = ty + to.dir.dy * buffer;
  const srcHoriz = from.dir.dx !== 0;
  const tgtHoriz = to.dir.dx !== 0;
  let mid;
  if (srcHoriz && tgtHoriz) {
    const midX = (sgx + tgx) / 2;
    mid = `L ${num(midX)} ${num(sgy)} L ${num(midX)} ${num(tgy)}`;
  } else if (!srcHoriz && !tgtHoriz) {
    const midY = (sgy + tgy) / 2;
    mid = `L ${num(sgx)} ${num(midY)} L ${num(tgx)} ${num(midY)}`;
  } else if (srcHoriz && !tgtHoriz) {
    mid = `L ${num(tgx)} ${num(sgy)}`;
  } else {
    mid = `L ${num(sgx)} ${num(tgy)}`;
  }
  return `M ${num(sx)} ${num(sy)} L ${num(sgx)} ${num(sgy)} ${mid} L ${num(tgx)} ${num(tgy)} L ${num(tx)} ${num(ty)}`;
}
function num(n) {
  return n.toFixed(2).replace(/\.?0+$/, "");
}

// src/widgets/diagram/FlowNode.tsx
var import_react2 = __toESM(require_react(), 1);

// src/widgets/diagram/viewport.ts
var import_react = __toESM(require_react(), 1);

// src/widgets/interaction/coords.ts
function applyMatrix(m, x, y) {
  return {
    x: m.a * x + m.c * y + m.e,
    y: m.b * x + m.d * y + m.f
  };
}
function screenToViewBox(target, clientX, clientY) {
  const ctm = target.getScreenCTM();
  if (!ctm) return null;
  const inv = ctm.inverse();
  return applyMatrix(inv, clientX, clientY);
}

// src/widgets/diagram/viewport.ts
var MIN_ZOOM = 0.25;
var MAX_ZOOM = 3;
function clientToFlow(target, clientX, clientY, innerDx, innerDy, view) {
  const point = screenToViewBox(target, clientX, clientY);
  if (!point) return null;
  return {
    x: (point.x - innerDx - view.panX) / view.zoom,
    y: (point.y - innerDy - view.panY) / view.zoom
  };
}
function panFromPointer(startView, startPointer, currentPointer) {
  return {
    ...startView,
    panX: startView.panX + currentPointer.x - startPointer.x,
    panY: startView.panY + currentPointer.y - startPointer.y
  };
}
function zoomFromWheel(zoom, deltaY) {
  const factor = 1 - deltaY * 1e-3;
  return Math.max(MIN_ZOOM, Math.min(MAX_ZOOM, zoom * factor));
}
function useFlowViewport(svgRef) {
  const [view, setView] = import_react.default.useState({
    panX: 0,
    panY: 0,
    zoom: 1
  });
  const panStateRef = import_react.default.useRef(null);
  const onPointerDown = import_react.default.useCallback(
    (event) => {
      if (event.target !== svgRef.current) return;
      const point = screenToViewBox(event.currentTarget, event.clientX, event.clientY);
      if (!point) return;
      event.currentTarget.setPointerCapture(event.pointerId);
      panStateRef.current = { startPointer: point, startView: view };
    },
    [svgRef, view]
  );
  const onPointerMove = import_react.default.useCallback(
    (event) => {
      const panState = panStateRef.current;
      if (!panState) return;
      const point = screenToViewBox(event.currentTarget, event.clientX, event.clientY);
      if (!point) return;
      setView(panFromPointer(panState.startView, panState.startPointer, point));
    },
    []
  );
  const onPointerUp = import_react.default.useCallback(
    (event) => {
      if (event.currentTarget.hasPointerCapture(event.pointerId)) {
        event.currentTarget.releasePointerCapture(event.pointerId);
      }
      panStateRef.current = null;
    },
    []
  );
  const onWheel = import_react.default.useCallback((event) => {
    event.preventDefault();
    setView((current) => ({
      ...current,
      zoom: zoomFromWheel(current.zoom, event.deltaY)
    }));
  }, []);
  return { view, onPointerDown, onPointerMove, onPointerUp, onWheel };
}

// src/widgets/diagram/FlowNode.tsx
var import_jsx_runtime = __toESM(require_jsx_runtime(), 1);
var NODE_FILL = "var(--bg, #ffffff)";
var NODE_STROKE = "var(--text, #1f2328)";
function NodeShape({
  shape,
  width,
  height
}) {
  const sharedProps = {
    fill: NODE_FILL,
    stroke: NODE_STROKE,
    strokeWidth: 1
  };
  if (shape === "circle") {
    return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
      "circle",
      {
        cx: width / 2,
        cy: height / 2,
        r: Math.min(width, height) / 2,
        ...sharedProps
      }
    );
  }
  if (shape === "ellipse") {
    return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
      "ellipse",
      {
        cx: width / 2,
        cy: height / 2,
        rx: width / 2,
        ry: height / 2,
        ...sharedProps
      }
    );
  }
  if (shape === "diamond") {
    return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
      "polygon",
      {
        points: `${width / 2},0 ${width},${height / 2} ${width / 2},${height} 0,${height / 2}`,
        ...sharedProps
      }
    );
  }
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
    "rect",
    {
      width,
      height,
      x: 0,
      y: 0,
      ...sharedProps,
      rx: 0
    }
  );
}
function FlowNode({
  node,
  svgRef,
  innerDx,
  innerDy,
  view,
  onClick,
  onHover,
  onDragMove,
  draggable
}) {
  const offsetRef = import_react2.default.useRef(null);
  const movedRef = import_react2.default.useRef(false);
  const onPointerDown = (event) => {
    if (!draggable || !svgRef.current) return;
    event.stopPropagation();
    event.preventDefault();
    event.currentTarget.setPointerCapture(event.pointerId);
    const point = clientToFlow(
      svgRef.current,
      event.clientX,
      event.clientY,
      innerDx,
      innerDy,
      view
    );
    if (!point) return;
    offsetRef.current = { x: point.x - node.x, y: point.y - node.y };
    movedRef.current = false;
  };
  const onPointerMove = (event) => {
    const offset = offsetRef.current;
    if (!offset || !svgRef.current) return;
    const point = clientToFlow(
      svgRef.current,
      event.clientX,
      event.clientY,
      innerDx,
      innerDy,
      view
    );
    if (!point) return;
    onDragMove(point.x - offset.x, point.y - offset.y);
    movedRef.current = true;
  };
  const onPointerUp = (event) => {
    if (event.currentTarget.hasPointerCapture(event.pointerId)) {
      event.currentTarget.releasePointerCapture(event.pointerId);
    }
    offsetRef.current = null;
    if (!movedRef.current && onClick) {
      onClick(node);
    }
  };
  const { x, y, width, height, id } = node;
  const label = typeof node["label"] === "string" ? node["label"] : id;
  const shape = node.shape ?? "rect";
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
    "g",
    {
      transform: `translate(${x - width / 2}, ${y - height / 2})`,
      style: {
        cursor: draggable ? "grab" : onClick ? "pointer" : "default",
        touchAction: "none"
      },
      onPointerDown,
      onPointerMove,
      onPointerUp,
      onPointerCancel: onPointerUp,
      onMouseEnter: onHover ? () => onHover(node) : void 0,
      onMouseLeave: onHover ? () => onHover(null) : void 0,
      children: [
        /* @__PURE__ */ (0, import_jsx_runtime.jsx)(NodeShape, { shape, width, height }),
        /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
          "text",
          {
            x: width / 2,
            y: height / 2,
            dominantBaseline: "middle",
            textAnchor: "middle",
            fontSize: 11,
            fill: "var(--text, #1f2328)",
            fontFamily: "var(--font-body, ui-sans-serif, system-ui, sans-serif)",
            style: { userSelect: "none", pointerEvents: "none" },
            children: label
          }
        )
      ]
    }
  );
}

// src/widgets/diagram/Flow.tsx
var import_jsx_runtime2 = __toESM(require_jsx_runtime(), 1);
var ARROW_ID = "readrun-widget-flow-arrow";
var DEF_W = 100;
var DEF_H = 50;
var EDGE_STROKE = "var(--text-muted, #656d76)";
var INNER_DX_FACTOR = 0.5;
var INNER_DY = 20;
function defaultRenderEdge(pathStr, edge2) {
  return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
    "path",
    {
      d: pathStr,
      stroke: EDGE_STROKE,
      strokeWidth: 1.5,
      fill: "none",
      markerEnd: `url(#${ARROW_ID})`
    },
    edge2.id
  );
}
function pathFromPorts(router, from, to) {
  switch (router) {
    case "straight":
      return straightWithPorts(from, to);
    case "curve":
      return curveWithPorts(from, to);
    case "orthogonal":
    default:
      return orthogonalWithPorts(from, to);
  }
}
function Flow({
  nodes: nodes2,
  edges: edges2,
  layout: layoutMode,
  childrenOf: childrenOf2,
  rootId,
  edgeRouter,
  renderNode,
  renderEdge,
  width,
  height,
  onNodeClick,
  onNodeHover,
  draggable = true
}) {
  const svgRef = import_react3.default.useRef(null);
  const innerDx = width * INNER_DX_FACTOR;
  const innerDy = INNER_DY;
  const [overrides, setOverrides] = import_react3.default.useState({});
  const viewport = useFlowViewport(svgRef);
  const { view } = viewport;
  const updateOverride = import_react3.default.useCallback((id, x, y) => {
    setOverrides((prev) => ({ ...prev, [id]: { x, y } }));
  }, []);
  const layoutNodes = import_react3.default.useMemo(() => {
    if (layoutMode === "manual") {
      return nodes2.map((node) => ({
        ...node,
        x: node.x ?? 0,
        y: node.y ?? 0,
        width: node.width ?? DEF_W,
        height: node.height ?? DEF_H
      }));
    }
    if (layoutMode === "dag") return dag(nodes2, edges2);
    if (layoutMode === "tree") {
      const root = nodes2.find((node) => node.id === rootId) ?? nodes2[0];
      return root ? tree(root, childrenOf2 ?? (() => []), {
        levelSeparation: height / Math.max(4, nodes2.length)
      }) : [];
    }
    return force(nodes2, edges2, { width, height });
  }, [childrenOf2, edges2, height, layoutMode, nodes2, rootId, width]);
  const positioned = import_react3.default.useMemo(
    () => layoutNodes.map((node) => {
      const override = overrides[node.id];
      return override ? { ...node, ...override } : node;
    }),
    [layoutNodes, overrides]
  );
  const posById = import_react3.default.useMemo(
    () => new Map(positioned.map((node) => [node.id, node])),
    [positioned]
  );
  const router = edgeRouter ?? (layoutMode === "force" ? "curve" : layoutMode === "manual" ? "straight" : "orthogonal");
  const edgeElements = import_react3.default.useMemo(() => {
    const usedPorts = /* @__PURE__ */ new Map();
    return edges2.map((edge2) => {
      const fromNode = posById.get(edge2.from);
      const toNode = posById.get(edge2.to);
      if (!fromNode || !toNode) return null;
      const fromUsed = usedPorts.get(edge2.from) ?? /* @__PURE__ */ new Set();
      const toUsed = usedPorts.get(edge2.to) ?? /* @__PURE__ */ new Set();
      const { from, to, fromName, toName } = selectEdgePorts(fromNode, toNode, {
        excludeFrom: fromUsed,
        excludeTo: toUsed
      });
      fromUsed.add(fromName);
      toUsed.add(toName);
      usedPorts.set(edge2.from, fromUsed);
      usedPorts.set(edge2.to, toUsed);
      const path = pathFromPorts(router, from, to);
      return renderEdge ? renderEdge(path, edge2, fromNode, toNode) : defaultRenderEdge(path, edge2);
    }).filter(Boolean);
  }, [edges2, posById, renderEdge, router]);
  const nodeElements = positioned.map((n) => {
    if (renderNode) return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react3.default.Fragment, { children: renderNode(n) }, n.id);
    return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
      FlowNode,
      {
        node: n,
        svgRef,
        innerDx,
        innerDy,
        view,
        draggable,
        onClick: onNodeClick,
        onHover: onNodeHover,
        onDragMove: (x, y) => updateOverride(n.id, x, y)
      },
      n.id
    );
  });
  const innerTransform = `translate(${innerDx + view.panX}, ${innerDy + view.panY}) scale(${view.zoom})`;
  return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
    "div",
    {
      style: {
        position: "relative",
        background: "var(--card-bg, #ffffff)",
        border: "1px solid var(--border, #d0d7de)",
        overflow: "hidden"
      },
      children: [
        /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
          "svg",
          {
            ref: svgRef,
            viewBox: `0 0 ${width} ${height}`,
            width,
            height,
            style: { display: "block", maxWidth: "100%", touchAction: "none" },
            onPointerDown: viewport.onPointerDown,
            onPointerMove: viewport.onPointerMove,
            onPointerUp: viewport.onPointerUp,
            onPointerCancel: viewport.onPointerUp,
            onWheel: viewport.onWheel,
            children: [
              /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("defs", { children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
                "marker",
                {
                  id: ARROW_ID,
                  viewBox: "0 0 10 10",
                  refX: 10,
                  refY: 5,
                  markerWidth: 6,
                  markerHeight: 6,
                  orient: "auto-start-reverse",
                  children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M 0 0 L 10 5 L 0 10 z", fill: EDGE_STROKE })
                }
              ) }),
              /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("g", { transform: innerTransform, children: [
                edgeElements,
                nodeElements
              ] })
            ]
          }
        ),
        draggable && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
          "div",
          {
            style: {
              position: "absolute",
              bottom: 6,
              right: 8,
              fontSize: 11,
              color: "var(--text-muted, #656d76)",
              fontFamily: "var(--font-mono, ui-monospace, monospace)",
              letterSpacing: "0.04em",
              pointerEvents: "none"
            },
            children: "drag nodes \u2022 drag empty \u2022 scroll to zoom"
          }
        )
      ]
    }
  );
}

// src/widgets/primitives/index.tsx
var import_react6 = __toESM(require_react());

// src/presentation/components/ui/Label.tsx
var import_jsx_runtime3 = __toESM(require_jsx_runtime(), 1);

// src/presentation/components/ui/Slider.tsx
var import_jsx_runtime4 = __toESM(require_jsx_runtime(), 1);

// src/presentation/components/ui/Switch.tsx
var import_jsx_runtime5 = __toESM(require_jsx_runtime(), 1);

// src/widgets/primitives/WidgetLayout.tsx
var import_react4 = __toESM(require_react(), 1);
var import_jsx_runtime6 = __toESM(require_jsx_runtime(), 1);
function VisualSlot({ children }) {
  return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_jsx_runtime6.Fragment, { children });
}
function ControlsSlot({ children }) {
  return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_jsx_runtime6.Fragment, { children });
}
function AsideSlot({ children }) {
  return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_jsx_runtime6.Fragment, { children });
}
VisualSlot.__widgetSlot = "visual";
ControlsSlot.__widgetSlot = "controls";
AsideSlot.__widgetSlot = "aside";
function extractSlots(children) {
  const slots = {};
  import_react4.default.Children.forEach(children, (child) => {
    if (import_react4.default.isValidElement(child)) {
      const t = child.type;
      if (t?.__widgetSlot) {
        slots[t.__widgetSlot] = child;
      }
    }
  });
  return slots;
}
function WidgetLayoutImpl(props) {
  const arrangement = props.arrangement ?? "visual-left";
  const slots = extractSlots(props.children);
  return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: `readrun-widget readrun-widget--${arrangement}`, children: [
    (props.title || props.subtitle || props.headMeta) && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
      "div",
      {
        className: "readrun-widget__head",
        style: { display: "flex", justifyContent: "space-between" },
        children: [
          /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { children: [
            props.title && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("h2", { className: "readrun-widget__title", children: props.title }),
            props.subtitle && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "readrun-widget__subtitle", children: props.subtitle })
          ] }),
          props.headMeta && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { children: props.headMeta })
        ]
      }
    ),
    /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "readrun-widget__body", children: [
      slots["visual"] && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "readrun-widget__visual", children: slots["visual"] }),
      (slots["controls"] || slots["aside"]) && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "readrun-widget__sidebar", children: [
        slots["controls"] && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "readrun-widget__controls", children: slots["controls"] }),
        slots["aside"] && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "readrun-widget__aside", children: [
          /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "readrun-widget__aside-label", children: "What to notice" }),
          slots["aside"]
        ] })
      ] })
    ] })
  ] });
}
var WidgetLayout = Object.assign(WidgetLayoutImpl, {
  Visual: VisualSlot,
  Controls: ControlsSlot,
  Aside: AsideSlot
});

// src/widgets/primitives/FormulaSteps.tsx
var import_react5 = __toESM(require_react(), 1);
var import_jsx_runtime7 = __toESM(require_jsx_runtime(), 1);

// src/widgets/primitives/index.tsx
function Shell({
  title,
  meta,
  children
}) {
  return /* @__PURE__ */ import_react6.default.createElement("div", { className: "viz-shell" }, (title || meta) && /* @__PURE__ */ import_react6.default.createElement("div", { className: "viz-shell-head" }, title && /* @__PURE__ */ import_react6.default.createElement("h2", null, title), meta && /* @__PURE__ */ import_react6.default.createElement("div", { className: "viz-shell-meta" }, meta)), children);
}
function Sub({ children }) {
  return /* @__PURE__ */ import_react6.default.createElement("p", { className: "viz-sub" }, children);
}
function Stage({
  children,
  style
}) {
  return /* @__PURE__ */ import_react6.default.createElement("div", { className: "viz-stage", style }, children);
}

// docs/.readrun/widgets/flow-tree-demo.tsx
var import_jsx_runtime8 = __toESM(require_jsx_runtime(), 1);
var nodes = [
  { id: "root", label: "Root" },
  { id: "a", label: "Node A" },
  { id: "b", label: "Node B" },
  { id: "c", label: "Node C" },
  { id: "a1", label: "A.1" },
  { id: "a2", label: "A.2" },
  { id: "b1", label: "B.1" },
  { id: "c1", label: "C.1" },
  { id: "c2", label: "C.2" }
];
var edges = [
  { id: "e1", from: "root", to: "a" },
  { id: "e2", from: "root", to: "b" },
  { id: "e3", from: "root", to: "c" },
  { id: "e4", from: "a", to: "a1" },
  { id: "e5", from: "a", to: "a2" },
  { id: "e6", from: "b", to: "b1" },
  { id: "e7", from: "c", to: "c1" },
  { id: "e8", from: "c", to: "c2" }
];
var childMap = {
  root: ["a", "b", "c"],
  a: ["a1", "a2"],
  b: ["b1"],
  c: ["c1", "c2"]
};
var nodeById = new Map(nodes.map((n) => [n.id, n]));
function childrenOf(node) {
  return (childMap[node.id] ?? []).map((id) => nodeById.get(id)).filter(Boolean);
}
function FlowTreeDemo() {
  return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(Shell, { title: "Flow / tree layout", children: [
    /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Sub, { children: "Tree layout using Reingold-Tilford. Pass rootId and childrenOf to define the hierarchy." }),
    /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Stage, { children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
      Flow,
      {
        nodes,
        edges,
        layout: "tree",
        rootId: "root",
        childrenOf,
        edgeRouter: "orthogonal",
        width: 700,
        height: 380
      }
    ) })
  ] });
}

// docs/.readrun/widgets/flow-tree-demo.readrun-entry.ts
render(<FlowTreeDemo />);

Force layout

jsx
// generated by @readrun/widgets — edit .readrun/widgets/flow-force-demo.tsx, then re-run rr
// @readrun/widgets@10f3ae2 — generated 2026-08-01T09:20:59Z
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __commonJS = (cb, mod) => function __require() {
  return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
};
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 __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
  // If the importer is in node compatibility mode or this is not an ESM
  // file that has been converted to a CommonJS file using a Babel-
  // compatible transform (i.e. "__esModule" has not been set), then set
  // "default" to the CommonJS "module.exports" for node compatibility.
  isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
  mod
));

// globals:react
var require_react = __commonJS({
  "globals:react"(exports, module) {
    module.exports = globalThis.React;
  }
});

// globals:react/jsx-runtime
var require_jsx_runtime = __commonJS({
  "globals:react/jsx-runtime"(exports, module) {
    var React8 = globalThis.React;
    function jsx9(type, props, key) {
      const nextProps = key === void 0 ? props : Object.assign({}, props, { key });
      return React8.createElement(type, nextProps);
    }
    module.exports = { Fragment: React8.Fragment, jsx: jsx9, jsxs: jsx9 };
  }
});

// docs/.readrun/widgets/flow-force-demo.tsx
var import_react7 = __toESM(require_react(), 1);

// src/widgets/diagram/Flow.tsx
var import_react3 = __toESM(require_react(), 1);

// src/widgets/diagram/layout/dag.ts
function dag(nodes2, edges2, opts) {
  const rankSep = opts?.rankSeparation ?? 120;
  const nodeSep = opts?.nodeSeparation ?? 40;
  const defW = opts?.defaultWidth ?? 100;
  const defH = opts?.defaultHeight ?? 50;
  if (nodes2.length === 0) return [];
  const nodeIds = new Set(nodes2.map((n) => n.id));
  const outEdges = /* @__PURE__ */ new Map();
  const inDegree = /* @__PURE__ */ new Map();
  const edgeByTo = /* @__PURE__ */ new Map();
  for (const n of nodes2) {
    outEdges.set(n.id, []);
    inDegree.set(n.id, 0);
  }
  for (const e of edges2) {
    if (!nodeIds.has(e.from) || !nodeIds.has(e.to)) continue;
    outEdges.get(e.from).push(e.to);
    inDegree.set(e.to, (inDegree.get(e.to) ?? 0) + 1);
    if (!edgeByTo.has(e.to)) edgeByTo.set(e.to, e);
  }
  const rank = /* @__PURE__ */ new Map();
  const queue = [];
  for (const n of nodes2) {
    if ((inDegree.get(n.id) ?? 0) === 0) {
      queue.push(n.id);
      rank.set(n.id, 0);
    }
  }
  const sorted = [];
  while (queue.length > 0) {
    queue.sort();
    const id = queue.shift();
    sorted.push(id);
    for (const childId of outEdges.get(id) ?? []) {
      const newRank = (rank.get(id) ?? 0) + 1;
      if (!rank.has(childId) || rank.get(childId) < newRank) {
        rank.set(childId, newRank);
      }
      const newIn = (inDegree.get(childId) ?? 0) - 1;
      inDegree.set(childId, newIn);
      if (newIn === 0) {
        queue.push(childId);
      }
    }
  }
  if (sorted.length !== nodes2.length) {
    for (const e of edges2) {
      if ((rank.get(e.from) ?? -1) >= (rank.get(e.to) ?? -1) && sorted.includes(e.from)) {
      }
    }
    const unprocessed = new Set(nodes2.map((n) => n.id).filter((id) => !sorted.includes(id)));
    for (const e of edges2) {
      if (unprocessed.has(e.to) || unprocessed.has(e.from)) {
        throw new Error(
          `dag layout: cycle detected. Edge "${e.id}" (${e.from} \u2192 ${e.to}) is part of a cycle.`
        );
      }
    }
    throw new Error("dag layout: cycle detected in the graph.");
  }
  const rankGroups = /* @__PURE__ */ new Map();
  for (const [id, r] of rank.entries()) {
    if (!rankGroups.has(r)) rankGroups.set(r, []);
    rankGroups.get(r).push(id);
  }
  for (const group of rankGroups.values()) {
    group.sort();
  }
  const nodeById = new Map(nodes2.map((n) => [n.id, n]));
  const positioned = /* @__PURE__ */ new Map();
  for (const [r, group] of rankGroups.entries()) {
    const n = group.length;
    const totalWidth = n * defW + (n - 1) * nodeSep;
    const startX = -totalWidth / 2 + defW / 2;
    for (let i = 0; i < group.length; i++) {
      const id = group[i];
      const node = nodeById.get(id);
      const w = node.width ?? defW;
      const h = node.height ?? defH;
      positioned.set(id, {
        ...node,
        x: startX + i * (defW + nodeSep),
        y: r * rankSep,
        width: w,
        height: h
      });
    }
  }
  return nodes2.map((n) => positioned.get(n.id));
}

// src/widgets/diagram/layout/tree.ts
function tree(rootNode, childrenOf, opts) {
  const levelSep = opts?.levelSeparation ?? 100;
  const siblingSep = opts?.siblingSeparation ?? 40;
  const defW = opts?.defaultWidth ?? 100;
  const defH = opts?.defaultHeight ?? 50;
  const nextX = /* @__PURE__ */ new Map();
  function buildTree(node, depth) {
    const children = childrenOf(node).map((c) => buildTree(c, depth + 1));
    const internal = {
      source: node,
      children,
      depth,
      x: 0,
      y: depth * levelSep
    };
    if (children.length === 0) {
      const cur = nextX.get(depth) ?? 0;
      internal.x = cur;
      nextX.set(depth, cur + defW + siblingSep);
    } else {
      const leftX = children[0].x;
      const rightX = children[children.length - 1].x;
      internal.x = (leftX + rightX) / 2;
      const cur = nextX.get(depth) ?? 0;
      if (internal.x + defW / 2 > cur) {
        nextX.set(depth, internal.x + defW + siblingSep);
      }
    }
    return internal;
  }
  const root = buildTree(rootNode, 0);
  const result = [];
  function collect(n) {
    const node = n.source;
    result.push({
      ...node,
      x: n.x,
      y: n.y,
      width: node.width ?? defW,
      height: node.height ?? defH
    });
    for (const c of n.children) collect(c);
  }
  collect(root);
  return result;
}

// src/widgets/math/force.ts
function forceStep(nodes2, edges2, cfg) {
  const repulsion = cfg.repulsion ?? 4500;
  const springK = cfg.springK ?? 0.04;
  const springRest = cfg.springRest ?? 70;
  const damping = cfg.damping ?? 0.85;
  const centerPull = cfg.centerPull ?? 5e-3;
  const dt = cfg.dt ?? 1;
  const cx = cfg.width / 2;
  const cy = cfg.height / 2;
  for (let i = 0; i < nodes2.length; i++) {
    const ni = nodes2[i];
    if (ni.fixed) continue;
    let fx = 0;
    let fy = 0;
    for (let j = 0; j < nodes2.length; j++) {
      if (i === j) continue;
      const nj = nodes2[j];
      const dx = ni.x - nj.x;
      const dy = ni.y - nj.y;
      const d2 = dx * dx + dy * dy + 0.01;
      const f = repulsion / d2;
      const d = Math.sqrt(d2);
      fx += dx / d * f;
      fy += dy / d * f;
    }
    fx += (cx - ni.x) * centerPull;
    fy += (cy - ni.y) * centerPull;
    ni.vx = (ni.vx + fx * dt) * damping;
    ni.vy = (ni.vy + fy * dt) * damping;
  }
  for (const e of edges2) {
    const a = nodes2[e.s];
    const b = nodes2[e.t];
    if (!a || !b) continue;
    const dx = b.x - a.x;
    const dy = b.y - a.y;
    const d = Math.hypot(dx, dy) + 0.01;
    const f = springK * (d - springRest);
    const fx = dx / d * f;
    const fy = dy / d * f;
    if (!a.fixed) {
      a.vx += fx * dt;
      a.vy += fy * dt;
    }
    if (!b.fixed) {
      b.vx -= fx * dt;
      b.vy -= fy * dt;
    }
  }
  for (const n of nodes2) {
    if (n.fixed) continue;
    n.x += n.vx * dt;
    n.y += n.vy * dt;
    const m = 24;
    if (n.x < m) {
      n.x = m;
      n.vx *= -0.4;
    }
    if (n.x > cfg.width - m) {
      n.x = cfg.width - m;
      n.vx *= -0.4;
    }
    if (n.y < m) {
      n.y = m;
      n.vy *= -0.4;
    }
    if (n.y > cfg.height - m) {
      n.y = cfg.height - m;
      n.vy *= -0.4;
    }
  }
}

// src/widgets/math/random.ts
function mulberry32(seed) {
  let s = seed >>> 0;
  return () => {
    s = s + 1831565813 >>> 0;
    let t = s;
    t = Math.imul(t ^ t >>> 15, t | 1);
    t ^= t + Math.imul(t ^ t >>> 7, t | 61);
    return ((t ^ t >>> 14) >>> 0) / 4294967296;
  };
}

// src/widgets/diagram/layout/force.ts
function force(nodes2, edges2, opts) {
  if (nodes2.length === 0) return [];
  const iterations = opts?.iterations ?? 300;
  const width = opts?.width ?? 800;
  const height = opts?.height ?? 600;
  const seed = opts?.seed ?? 1;
  const defW = opts?.defaultWidth ?? 100;
  const defH = opts?.defaultHeight ?? 50;
  const rng = mulberry32(seed);
  const indexById = new Map(nodes2.map((n, i) => [n.id, i]));
  const forceNodes = nodes2.map((_n, i) => ({
    id: i,
    x: width / 2 + (rng() - 0.5) * 200,
    y: height / 2 + (rng() - 0.5) * 200,
    vx: 0,
    vy: 0
  }));
  const forceEdges = edges2.map((e) => {
    const s = indexById.get(e.from);
    const t = indexById.get(e.to);
    if (s === void 0 || t === void 0) return null;
    return { s, t };
  }).filter((e) => e !== null);
  const cfg = { width, height };
  for (let i = 0; i < iterations; i++) {
    forceStep(forceNodes, forceEdges, cfg);
  }
  return nodes2.map((node, i) => ({
    ...node,
    x: forceNodes[i].x,
    y: forceNodes[i].y,
    width: node.width ?? defW,
    height: node.height ?? defH
  }));
}

// src/widgets/diagram/edge/ports.ts
function nodePorts(node) {
  const { x: cx, y: cy, width, height } = node;
  const w2 = width / 2;
  const h2 = height / 2;
  return {
    top: { x: cx, y: cy - h2, dir: { dx: 0, dy: -1 } },
    right: { x: cx + w2, y: cy, dir: { dx: 1, dy: 0 } },
    bottom: { x: cx, y: cy + h2, dir: { dx: 0, dy: 1 } },
    left: { x: cx - w2, y: cy, dir: { dx: -1, dy: 0 } }
  };
}
function selectPort(ports, targetVec, exclude) {
  const len = Math.hypot(targetVec.x, targetVec.y) || 1;
  const tx = targetVec.x / len;
  const ty = targetVec.y / len;
  const ranked = Object.keys(ports).map((name) => ({
    name,
    port: ports[name],
    score: ports[name].dir.dx * tx + ports[name].dir.dy * ty
  })).sort((a, b) => b.score - a.score);
  if (exclude && exclude.size > 0) {
    const free = ranked.find((r) => !exclude.has(r.name));
    if (free) return { name: free.name, port: free.port };
  }
  const top = ranked[0];
  return { name: top.name, port: top.port };
}
function selectEdgePorts(fromNode, toNode, opts) {
  const dx = toNode.x - fromNode.x;
  const dy = toNode.y - fromNode.y;
  const fromPorts = nodePorts(fromNode);
  const toPorts = nodePorts(toNode);
  const fromSel = selectPort(fromPorts, { x: dx, y: dy }, opts?.excludeFrom);
  const toSel = selectPort(toPorts, { x: -dx, y: -dy }, opts?.excludeTo);
  return { from: fromSel.port, to: toSel.port, fromName: fromSel.name, toName: toSel.name };
}

// src/widgets/diagram/edge/router.ts
function straightWithPorts(from, to) {
  return `M ${num(from.x)} ${num(from.y)} L ${num(to.x)} ${num(to.y)}`;
}
function curveWithPorts(from, to) {
  const dist = Math.hypot(to.x - from.x, to.y - from.y);
  const offset = Math.max(20, 0.4 * dist);
  const c1x = from.x + from.dir.dx * offset;
  const c1y = from.y + from.dir.dy * offset;
  const c2x = to.x + to.dir.dx * offset;
  const c2y = to.y + to.dir.dy * offset;
  return `M ${num(from.x)} ${num(from.y)} C ${num(c1x)} ${num(c1y)} ${num(c2x)} ${num(c2y)} ${num(to.x)} ${num(to.y)}`;
}
function orthogonalWithPorts(from, to, opts) {
  const buffer = opts?.buffer ?? 20;
  const sx = from.x;
  const sy = from.y;
  const tx = to.x;
  const ty = to.y;
  const sgx = sx + from.dir.dx * buffer;
  const sgy = sy + from.dir.dy * buffer;
  const tgx = tx + to.dir.dx * buffer;
  const tgy = ty + to.dir.dy * buffer;
  const srcHoriz = from.dir.dx !== 0;
  const tgtHoriz = to.dir.dx !== 0;
  let mid;
  if (srcHoriz && tgtHoriz) {
    const midX = (sgx + tgx) / 2;
    mid = `L ${num(midX)} ${num(sgy)} L ${num(midX)} ${num(tgy)}`;
  } else if (!srcHoriz && !tgtHoriz) {
    const midY = (sgy + tgy) / 2;
    mid = `L ${num(sgx)} ${num(midY)} L ${num(tgx)} ${num(midY)}`;
  } else if (srcHoriz && !tgtHoriz) {
    mid = `L ${num(tgx)} ${num(sgy)}`;
  } else {
    mid = `L ${num(sgx)} ${num(tgy)}`;
  }
  return `M ${num(sx)} ${num(sy)} L ${num(sgx)} ${num(sgy)} ${mid} L ${num(tgx)} ${num(tgy)} L ${num(tx)} ${num(ty)}`;
}
function num(n) {
  return n.toFixed(2).replace(/\.?0+$/, "");
}

// src/widgets/diagram/FlowNode.tsx
var import_react2 = __toESM(require_react(), 1);

// src/widgets/diagram/viewport.ts
var import_react = __toESM(require_react(), 1);

// src/widgets/interaction/coords.ts
function applyMatrix(m, x, y) {
  return {
    x: m.a * x + m.c * y + m.e,
    y: m.b * x + m.d * y + m.f
  };
}
function screenToViewBox(target, clientX, clientY) {
  const ctm = target.getScreenCTM();
  if (!ctm) return null;
  const inv = ctm.inverse();
  return applyMatrix(inv, clientX, clientY);
}

// src/widgets/diagram/viewport.ts
var MIN_ZOOM = 0.25;
var MAX_ZOOM = 3;
function clientToFlow(target, clientX, clientY, innerDx, innerDy, view) {
  const point = screenToViewBox(target, clientX, clientY);
  if (!point) return null;
  return {
    x: (point.x - innerDx - view.panX) / view.zoom,
    y: (point.y - innerDy - view.panY) / view.zoom
  };
}
function panFromPointer(startView, startPointer, currentPointer) {
  return {
    ...startView,
    panX: startView.panX + currentPointer.x - startPointer.x,
    panY: startView.panY + currentPointer.y - startPointer.y
  };
}
function zoomFromWheel(zoom, deltaY) {
  const factor = 1 - deltaY * 1e-3;
  return Math.max(MIN_ZOOM, Math.min(MAX_ZOOM, zoom * factor));
}
function useFlowViewport(svgRef) {
  const [view, setView] = import_react.default.useState({
    panX: 0,
    panY: 0,
    zoom: 1
  });
  const panStateRef = import_react.default.useRef(null);
  const onPointerDown = import_react.default.useCallback(
    (event) => {
      if (event.target !== svgRef.current) return;
      const point = screenToViewBox(event.currentTarget, event.clientX, event.clientY);
      if (!point) return;
      event.currentTarget.setPointerCapture(event.pointerId);
      panStateRef.current = { startPointer: point, startView: view };
    },
    [svgRef, view]
  );
  const onPointerMove = import_react.default.useCallback(
    (event) => {
      const panState = panStateRef.current;
      if (!panState) return;
      const point = screenToViewBox(event.currentTarget, event.clientX, event.clientY);
      if (!point) return;
      setView(panFromPointer(panState.startView, panState.startPointer, point));
    },
    []
  );
  const onPointerUp = import_react.default.useCallback(
    (event) => {
      if (event.currentTarget.hasPointerCapture(event.pointerId)) {
        event.currentTarget.releasePointerCapture(event.pointerId);
      }
      panStateRef.current = null;
    },
    []
  );
  const onWheel = import_react.default.useCallback((event) => {
    event.preventDefault();
    setView((current) => ({
      ...current,
      zoom: zoomFromWheel(current.zoom, event.deltaY)
    }));
  }, []);
  return { view, onPointerDown, onPointerMove, onPointerUp, onWheel };
}

// src/widgets/diagram/FlowNode.tsx
var import_jsx_runtime = __toESM(require_jsx_runtime(), 1);
var NODE_FILL = "var(--bg, #ffffff)";
var NODE_STROKE = "var(--text, #1f2328)";
function NodeShape({
  shape,
  width,
  height
}) {
  const sharedProps = {
    fill: NODE_FILL,
    stroke: NODE_STROKE,
    strokeWidth: 1
  };
  if (shape === "circle") {
    return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
      "circle",
      {
        cx: width / 2,
        cy: height / 2,
        r: Math.min(width, height) / 2,
        ...sharedProps
      }
    );
  }
  if (shape === "ellipse") {
    return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
      "ellipse",
      {
        cx: width / 2,
        cy: height / 2,
        rx: width / 2,
        ry: height / 2,
        ...sharedProps
      }
    );
  }
  if (shape === "diamond") {
    return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
      "polygon",
      {
        points: `${width / 2},0 ${width},${height / 2} ${width / 2},${height} 0,${height / 2}`,
        ...sharedProps
      }
    );
  }
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
    "rect",
    {
      width,
      height,
      x: 0,
      y: 0,
      ...sharedProps,
      rx: 0
    }
  );
}
function FlowNode({
  node,
  svgRef,
  innerDx,
  innerDy,
  view,
  onClick,
  onHover,
  onDragMove,
  draggable
}) {
  const offsetRef = import_react2.default.useRef(null);
  const movedRef = import_react2.default.useRef(false);
  const onPointerDown = (event) => {
    if (!draggable || !svgRef.current) return;
    event.stopPropagation();
    event.preventDefault();
    event.currentTarget.setPointerCapture(event.pointerId);
    const point = clientToFlow(
      svgRef.current,
      event.clientX,
      event.clientY,
      innerDx,
      innerDy,
      view
    );
    if (!point) return;
    offsetRef.current = { x: point.x - node.x, y: point.y - node.y };
    movedRef.current = false;
  };
  const onPointerMove = (event) => {
    const offset = offsetRef.current;
    if (!offset || !svgRef.current) return;
    const point = clientToFlow(
      svgRef.current,
      event.clientX,
      event.clientY,
      innerDx,
      innerDy,
      view
    );
    if (!point) return;
    onDragMove(point.x - offset.x, point.y - offset.y);
    movedRef.current = true;
  };
  const onPointerUp = (event) => {
    if (event.currentTarget.hasPointerCapture(event.pointerId)) {
      event.currentTarget.releasePointerCapture(event.pointerId);
    }
    offsetRef.current = null;
    if (!movedRef.current && onClick) {
      onClick(node);
    }
  };
  const { x, y, width, height, id } = node;
  const label = typeof node["label"] === "string" ? node["label"] : id;
  const shape = node.shape ?? "rect";
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
    "g",
    {
      transform: `translate(${x - width / 2}, ${y - height / 2})`,
      style: {
        cursor: draggable ? "grab" : onClick ? "pointer" : "default",
        touchAction: "none"
      },
      onPointerDown,
      onPointerMove,
      onPointerUp,
      onPointerCancel: onPointerUp,
      onMouseEnter: onHover ? () => onHover(node) : void 0,
      onMouseLeave: onHover ? () => onHover(null) : void 0,
      children: [
        /* @__PURE__ */ (0, import_jsx_runtime.jsx)(NodeShape, { shape, width, height }),
        /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
          "text",
          {
            x: width / 2,
            y: height / 2,
            dominantBaseline: "middle",
            textAnchor: "middle",
            fontSize: 11,
            fill: "var(--text, #1f2328)",
            fontFamily: "var(--font-body, ui-sans-serif, system-ui, sans-serif)",
            style: { userSelect: "none", pointerEvents: "none" },
            children: label
          }
        )
      ]
    }
  );
}

// src/widgets/diagram/Flow.tsx
var import_jsx_runtime2 = __toESM(require_jsx_runtime(), 1);
var ARROW_ID = "readrun-widget-flow-arrow";
var DEF_W = 100;
var DEF_H = 50;
var EDGE_STROKE = "var(--text-muted, #656d76)";
var INNER_DX_FACTOR = 0.5;
var INNER_DY = 20;
function defaultRenderEdge(pathStr, edge2) {
  return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
    "path",
    {
      d: pathStr,
      stroke: EDGE_STROKE,
      strokeWidth: 1.5,
      fill: "none",
      markerEnd: `url(#${ARROW_ID})`
    },
    edge2.id
  );
}
function pathFromPorts(router, from, to) {
  switch (router) {
    case "straight":
      return straightWithPorts(from, to);
    case "curve":
      return curveWithPorts(from, to);
    case "orthogonal":
    default:
      return orthogonalWithPorts(from, to);
  }
}
function Flow({
  nodes: nodes2,
  edges: edges2,
  layout: layoutMode,
  childrenOf,
  rootId,
  edgeRouter,
  renderNode,
  renderEdge,
  width,
  height,
  onNodeClick,
  onNodeHover,
  draggable = true
}) {
  const svgRef = import_react3.default.useRef(null);
  const innerDx = width * INNER_DX_FACTOR;
  const innerDy = INNER_DY;
  const [overrides, setOverrides] = import_react3.default.useState({});
  const viewport = useFlowViewport(svgRef);
  const { view } = viewport;
  const updateOverride = import_react3.default.useCallback((id, x, y) => {
    setOverrides((prev) => ({ ...prev, [id]: { x, y } }));
  }, []);
  const layoutNodes = import_react3.default.useMemo(() => {
    if (layoutMode === "manual") {
      return nodes2.map((node) => ({
        ...node,
        x: node.x ?? 0,
        y: node.y ?? 0,
        width: node.width ?? DEF_W,
        height: node.height ?? DEF_H
      }));
    }
    if (layoutMode === "dag") return dag(nodes2, edges2);
    if (layoutMode === "tree") {
      const root = nodes2.find((node) => node.id === rootId) ?? nodes2[0];
      return root ? tree(root, childrenOf ?? (() => []), {
        levelSeparation: height / Math.max(4, nodes2.length)
      }) : [];
    }
    return force(nodes2, edges2, { width, height });
  }, [childrenOf, edges2, height, layoutMode, nodes2, rootId, width]);
  const positioned = import_react3.default.useMemo(
    () => layoutNodes.map((node) => {
      const override = overrides[node.id];
      return override ? { ...node, ...override } : node;
    }),
    [layoutNodes, overrides]
  );
  const posById = import_react3.default.useMemo(
    () => new Map(positioned.map((node) => [node.id, node])),
    [positioned]
  );
  const router = edgeRouter ?? (layoutMode === "force" ? "curve" : layoutMode === "manual" ? "straight" : "orthogonal");
  const edgeElements = import_react3.default.useMemo(() => {
    const usedPorts = /* @__PURE__ */ new Map();
    return edges2.map((edge2) => {
      const fromNode = posById.get(edge2.from);
      const toNode = posById.get(edge2.to);
      if (!fromNode || !toNode) return null;
      const fromUsed = usedPorts.get(edge2.from) ?? /* @__PURE__ */ new Set();
      const toUsed = usedPorts.get(edge2.to) ?? /* @__PURE__ */ new Set();
      const { from, to, fromName, toName } = selectEdgePorts(fromNode, toNode, {
        excludeFrom: fromUsed,
        excludeTo: toUsed
      });
      fromUsed.add(fromName);
      toUsed.add(toName);
      usedPorts.set(edge2.from, fromUsed);
      usedPorts.set(edge2.to, toUsed);
      const path = pathFromPorts(router, from, to);
      return renderEdge ? renderEdge(path, edge2, fromNode, toNode) : defaultRenderEdge(path, edge2);
    }).filter(Boolean);
  }, [edges2, posById, renderEdge, router]);
  const nodeElements = positioned.map((n) => {
    if (renderNode) return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react3.default.Fragment, { children: renderNode(n) }, n.id);
    return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
      FlowNode,
      {
        node: n,
        svgRef,
        innerDx,
        innerDy,
        view,
        draggable,
        onClick: onNodeClick,
        onHover: onNodeHover,
        onDragMove: (x, y) => updateOverride(n.id, x, y)
      },
      n.id
    );
  });
  const innerTransform = `translate(${innerDx + view.panX}, ${innerDy + view.panY}) scale(${view.zoom})`;
  return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
    "div",
    {
      style: {
        position: "relative",
        background: "var(--card-bg, #ffffff)",
        border: "1px solid var(--border, #d0d7de)",
        overflow: "hidden"
      },
      children: [
        /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
          "svg",
          {
            ref: svgRef,
            viewBox: `0 0 ${width} ${height}`,
            width,
            height,
            style: { display: "block", maxWidth: "100%", touchAction: "none" },
            onPointerDown: viewport.onPointerDown,
            onPointerMove: viewport.onPointerMove,
            onPointerUp: viewport.onPointerUp,
            onPointerCancel: viewport.onPointerUp,
            onWheel: viewport.onWheel,
            children: [
              /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("defs", { children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
                "marker",
                {
                  id: ARROW_ID,
                  viewBox: "0 0 10 10",
                  refX: 10,
                  refY: 5,
                  markerWidth: 6,
                  markerHeight: 6,
                  orient: "auto-start-reverse",
                  children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M 0 0 L 10 5 L 0 10 z", fill: EDGE_STROKE })
                }
              ) }),
              /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("g", { transform: innerTransform, children: [
                edgeElements,
                nodeElements
              ] })
            ]
          }
        ),
        draggable && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
          "div",
          {
            style: {
              position: "absolute",
              bottom: 6,
              right: 8,
              fontSize: 11,
              color: "var(--text-muted, #656d76)",
              fontFamily: "var(--font-mono, ui-monospace, monospace)",
              letterSpacing: "0.04em",
              pointerEvents: "none"
            },
            children: "drag nodes \u2022 drag empty \u2022 scroll to zoom"
          }
        )
      ]
    }
  );
}

// src/widgets/primitives/index.tsx
var import_react6 = __toESM(require_react());

// src/presentation/components/ui/Label.tsx
var import_jsx_runtime3 = __toESM(require_jsx_runtime(), 1);

// src/presentation/components/ui/Slider.tsx
var import_jsx_runtime4 = __toESM(require_jsx_runtime(), 1);

// src/presentation/components/ui/Switch.tsx
var import_jsx_runtime5 = __toESM(require_jsx_runtime(), 1);

// src/widgets/primitives/WidgetLayout.tsx
var import_react4 = __toESM(require_react(), 1);
var import_jsx_runtime6 = __toESM(require_jsx_runtime(), 1);
function VisualSlot({ children }) {
  return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_jsx_runtime6.Fragment, { children });
}
function ControlsSlot({ children }) {
  return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_jsx_runtime6.Fragment, { children });
}
function AsideSlot({ children }) {
  return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_jsx_runtime6.Fragment, { children });
}
VisualSlot.__widgetSlot = "visual";
ControlsSlot.__widgetSlot = "controls";
AsideSlot.__widgetSlot = "aside";
function extractSlots(children) {
  const slots = {};
  import_react4.default.Children.forEach(children, (child) => {
    if (import_react4.default.isValidElement(child)) {
      const t = child.type;
      if (t?.__widgetSlot) {
        slots[t.__widgetSlot] = child;
      }
    }
  });
  return slots;
}
function WidgetLayoutImpl(props) {
  const arrangement = props.arrangement ?? "visual-left";
  const slots = extractSlots(props.children);
  return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: `readrun-widget readrun-widget--${arrangement}`, children: [
    (props.title || props.subtitle || props.headMeta) && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
      "div",
      {
        className: "readrun-widget__head",
        style: { display: "flex", justifyContent: "space-between" },
        children: [
          /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { children: [
            props.title && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("h2", { className: "readrun-widget__title", children: props.title }),
            props.subtitle && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "readrun-widget__subtitle", children: props.subtitle })
          ] }),
          props.headMeta && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { children: props.headMeta })
        ]
      }
    ),
    /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "readrun-widget__body", children: [
      slots["visual"] && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "readrun-widget__visual", children: slots["visual"] }),
      (slots["controls"] || slots["aside"]) && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "readrun-widget__sidebar", children: [
        slots["controls"] && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "readrun-widget__controls", children: slots["controls"] }),
        slots["aside"] && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "readrun-widget__aside", children: [
          /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "readrun-widget__aside-label", children: "What to notice" }),
          slots["aside"]
        ] })
      ] })
    ] })
  ] });
}
var WidgetLayout = Object.assign(WidgetLayoutImpl, {
  Visual: VisualSlot,
  Controls: ControlsSlot,
  Aside: AsideSlot
});

// src/widgets/primitives/FormulaSteps.tsx
var import_react5 = __toESM(require_react(), 1);
var import_jsx_runtime7 = __toESM(require_jsx_runtime(), 1);

// src/widgets/primitives/index.tsx
function Shell({
  title,
  meta,
  children
}) {
  return /* @__PURE__ */ import_react6.default.createElement("div", { className: "viz-shell" }, (title || meta) && /* @__PURE__ */ import_react6.default.createElement("div", { className: "viz-shell-head" }, title && /* @__PURE__ */ import_react6.default.createElement("h2", null, title), meta && /* @__PURE__ */ import_react6.default.createElement("div", { className: "viz-shell-meta" }, meta)), children);
}
function Sub({ children }) {
  return /* @__PURE__ */ import_react6.default.createElement("p", { className: "viz-sub" }, children);
}
function Stage({
  children,
  style
}) {
  return /* @__PURE__ */ import_react6.default.createElement("div", { className: "viz-stage", style }, children);
}

// docs/.readrun/widgets/flow-force-demo.tsx
var import_jsx_runtime8 = __toESM(require_jsx_runtime(), 1);
var nodes = [
  { id: "n1", label: "Alpha" },
  { id: "n2", label: "Beta" },
  { id: "n3", label: "Gamma" },
  { id: "n4", label: "Delta" },
  { id: "n5", label: "Epsilon" },
  { id: "n6", label: "Zeta" }
];
var edges = [
  { id: "e1", from: "n1", to: "n2" },
  { id: "e2", from: "n1", to: "n3" },
  { id: "e3", from: "n2", to: "n4" },
  { id: "e4", from: "n3", to: "n4" },
  { id: "e5", from: "n4", to: "n5" },
  { id: "e6", from: "n5", to: "n6" },
  { id: "e7", from: "n6", to: "n1" }
];
function FlowForceDemo() {
  return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(Shell, { title: "Flow / force layout", children: [
    /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Sub, { children: "Force-directed layout. Nodes repel each other; edges act as springs." }),
    /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Stage, { children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
      Flow,
      {
        nodes,
        edges,
        layout: "force",
        edgeRouter: "curve",
        width: 700,
        height: 380
      }
    ) })
  ] });
}

// docs/.readrun/widgets/flow-force-demo.readrun-entry.ts
render(<FlowForceDemo />);

Force graph

jsx
// generated by @readrun/widgets — edit .readrun/widgets/force-graph.tsx, then re-run rr
// @readrun/widgets@10f3ae2 — generated 2026-08-01T09:20:59Z
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __commonJS = (cb, mod) => function __require() {
  return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
};
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 __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
  // If the importer is in node compatibility mode or this is not an ESM
  // file that has been converted to a CommonJS file using a Babel-
  // compatible transform (i.e. "__esModule" has not been set), then set
  // "default" to the CommonJS "module.exports" for node compatibility.
  isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
  mod
));

// globals:react
var require_react = __commonJS({
  "globals:react"(exports, module) {
    module.exports = globalThis.React;
  }
});

// globals:react/jsx-runtime
var require_jsx_runtime = __commonJS({
  "globals:react/jsx-runtime"(exports, module) {
    var React5 = globalThis.React;
    function jsx7(type, props, key) {
      const nextProps = key === void 0 ? props : Object.assign({}, props, { key });
      return React5.createElement(type, nextProps);
    }
    module.exports = { Fragment: React5.Fragment, jsx: jsx7, jsxs: jsx7 };
  }
});

// docs/.readrun/widgets/force-graph.tsx
var import_react4 = __toESM(require_react(), 1);

// src/widgets/primitives/index.tsx
var import_react3 = __toESM(require_react());

// src/presentation/components/ui/Label.tsx
var import_jsx_runtime = __toESM(require_jsx_runtime(), 1);

// src/presentation/components/ui/Slider.tsx
var import_jsx_runtime2 = __toESM(require_jsx_runtime(), 1);

// src/presentation/components/ui/Switch.tsx
var import_jsx_runtime3 = __toESM(require_jsx_runtime(), 1);

// src/widgets/primitives/WidgetLayout.tsx
var import_react = __toESM(require_react(), 1);
var import_jsx_runtime4 = __toESM(require_jsx_runtime(), 1);
function VisualSlot({ children }) {
  return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_jsx_runtime4.Fragment, { children });
}
function ControlsSlot({ children }) {
  return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_jsx_runtime4.Fragment, { children });
}
function AsideSlot({ children }) {
  return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_jsx_runtime4.Fragment, { children });
}
VisualSlot.__widgetSlot = "visual";
ControlsSlot.__widgetSlot = "controls";
AsideSlot.__widgetSlot = "aside";
function extractSlots(children) {
  const slots = {};
  import_react.default.Children.forEach(children, (child) => {
    if (import_react.default.isValidElement(child)) {
      const t = child.type;
      if (t?.__widgetSlot) {
        slots[t.__widgetSlot] = child;
      }
    }
  });
  return slots;
}
function WidgetLayoutImpl(props) {
  const arrangement = props.arrangement ?? "visual-left";
  const slots = extractSlots(props.children);
  return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: `readrun-widget readrun-widget--${arrangement}`, children: [
    (props.title || props.subtitle || props.headMeta) && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
      "div",
      {
        className: "readrun-widget__head",
        style: { display: "flex", justifyContent: "space-between" },
        children: [
          /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { children: [
            props.title && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("h2", { className: "readrun-widget__title", children: props.title }),
            props.subtitle && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "readrun-widget__subtitle", children: props.subtitle })
          ] }),
          props.headMeta && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { children: props.headMeta })
        ]
      }
    ),
    /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "readrun-widget__body", children: [
      slots["visual"] && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "readrun-widget__visual", children: slots["visual"] }),
      (slots["controls"] || slots["aside"]) && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "readrun-widget__sidebar", children: [
        slots["controls"] && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "readrun-widget__controls", children: slots["controls"] }),
        slots["aside"] && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "readrun-widget__aside", children: [
          /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "readrun-widget__aside-label", children: "What to notice" }),
          slots["aside"]
        ] })
      ] })
    ] })
  ] });
}
var WidgetLayout = Object.assign(WidgetLayoutImpl, {
  Visual: VisualSlot,
  Controls: ControlsSlot,
  Aside: AsideSlot
});

// src/widgets/primitives/FormulaSteps.tsx
var import_react2 = __toESM(require_react(), 1);
var import_jsx_runtime5 = __toESM(require_jsx_runtime(), 1);

// src/widgets/primitives/index.tsx
function Shell({
  title,
  meta,
  children
}) {
  return /* @__PURE__ */ import_react3.default.createElement("div", { className: "viz-shell" }, (title || meta) && /* @__PURE__ */ import_react3.default.createElement("div", { className: "viz-shell-head" }, title && /* @__PURE__ */ import_react3.default.createElement("h2", null, title), meta && /* @__PURE__ */ import_react3.default.createElement("div", { className: "viz-shell-meta" }, meta)), children);
}
function Sub({ children }) {
  return /* @__PURE__ */ import_react3.default.createElement("p", { className: "viz-sub" }, children);
}
function SectionLabel({
  children,
  style
}) {
  return /* @__PURE__ */ import_react3.default.createElement("div", { className: "viz-section-label", style }, children);
}
function Stage({
  children,
  style
}) {
  return /* @__PURE__ */ import_react3.default.createElement("div", { className: "viz-stage", style }, children);
}
function Panel({
  children,
  minWidth = 240,
  style
}) {
  return /* @__PURE__ */ import_react3.default.createElement("div", { className: "viz-panel", style: { minWidth, ...style } }, children);
}
function Btn({
  kind = "ghost",
  active,
  children,
  ...rest
}) {
  const cls = `viz-btn viz-btn-${kind}${active ? " viz-btn-active" : ""}`;
  return /* @__PURE__ */ import_react3.default.createElement("button", { className: cls, ...rest }, children);
}
function Tabs({
  value,
  onChange,
  items
}) {
  return /* @__PURE__ */ import_react3.default.createElement("div", { className: "viz-tabs" }, items.map((it) => /* @__PURE__ */ import_react3.default.createElement(
    "button",
    {
      key: it.id,
      className: `viz-tab${value === it.id ? " active" : ""}`,
      onClick: () => onChange(it.id)
    },
    it.label
  )));
}
function Stat({
  label,
  value,
  color
}) {
  return /* @__PURE__ */ import_react3.default.createElement("span", { className: "viz-stat" }, /* @__PURE__ */ import_react3.default.createElement("span", null, label), /* @__PURE__ */ import_react3.default.createElement("strong", { className: "viz-stat-value", style: color ? { color } : void 0 }, value));
}
function Notice({ children }) {
  return /* @__PURE__ */ import_react3.default.createElement("div", { className: "viz-notice" }, children);
}

// src/widgets/math/force.ts
function forceStep(nodes, edges, cfg) {
  const repulsion = cfg.repulsion ?? 4500;
  const springK = cfg.springK ?? 0.04;
  const springRest = cfg.springRest ?? 70;
  const damping = cfg.damping ?? 0.85;
  const centerPull = cfg.centerPull ?? 5e-3;
  const dt = cfg.dt ?? 1;
  const cx = cfg.width / 2;
  const cy = cfg.height / 2;
  for (let i = 0; i < nodes.length; i++) {
    const ni = nodes[i];
    if (ni.fixed) continue;
    let fx = 0;
    let fy = 0;
    for (let j = 0; j < nodes.length; j++) {
      if (i === j) continue;
      const nj = nodes[j];
      const dx = ni.x - nj.x;
      const dy = ni.y - nj.y;
      const d2 = dx * dx + dy * dy + 0.01;
      const f = repulsion / d2;
      const d = Math.sqrt(d2);
      fx += dx / d * f;
      fy += dy / d * f;
    }
    fx += (cx - ni.x) * centerPull;
    fy += (cy - ni.y) * centerPull;
    ni.vx = (ni.vx + fx * dt) * damping;
    ni.vy = (ni.vy + fy * dt) * damping;
  }
  for (const e of edges) {
    const a = nodes[e.s];
    const b = nodes[e.t];
    if (!a || !b) continue;
    const dx = b.x - a.x;
    const dy = b.y - a.y;
    const d = Math.hypot(dx, dy) + 0.01;
    const f = springK * (d - springRest);
    const fx = dx / d * f;
    const fy = dy / d * f;
    if (!a.fixed) {
      a.vx += fx * dt;
      a.vy += fy * dt;
    }
    if (!b.fixed) {
      b.vx -= fx * dt;
      b.vy -= fy * dt;
    }
  }
  for (const n of nodes) {
    if (n.fixed) continue;
    n.x += n.vx * dt;
    n.y += n.vy * dt;
    const m = 24;
    if (n.x < m) {
      n.x = m;
      n.vx *= -0.4;
    }
    if (n.x > cfg.width - m) {
      n.x = cfg.width - m;
      n.vx *= -0.4;
    }
    if (n.y < m) {
      n.y = m;
      n.vy *= -0.4;
    }
    if (n.y > cfg.height - m) {
      n.y = cfg.height - m;
      n.vy *= -0.4;
    }
  }
}
function makeRandomGraph(n, edgeProb, width, height, seed = 1) {
  let s = seed >>> 0;
  const rng = () => {
    s = s + 1831565813 >>> 0;
    let t = s;
    t = Math.imul(t ^ t >>> 15, t | 1);
    t ^= t + Math.imul(t ^ t >>> 7, t | 61);
    return ((t ^ t >>> 14) >>> 0) / 4294967296;
  };
  const nodes = [];
  for (let i = 0; i < n; i++) {
    nodes.push({
      id: i,
      x: width / 2 + (rng() - 0.5) * 200,
      y: height / 2 + (rng() - 0.5) * 200,
      vx: 0,
      vy: 0
    });
  }
  const edges = [];
  for (let i = 0; i < n; i++) {
    for (let j = i + 1; j < n; j++) {
      if (rng() < edgeProb) edges.push({ s: i, t: j });
    }
  }
  return { nodes, edges };
}
function makeRingGraph(n, width, height) {
  const nodes = [];
  const cx = width / 2;
  const cy = height / 2;
  const r = Math.min(width, height) * 0.32;
  for (let i = 0; i < n; i++) {
    const a = i / n * Math.PI * 2;
    nodes.push({ id: i, x: cx + Math.cos(a) * r, y: cy + Math.sin(a) * r, vx: 0, vy: 0 });
  }
  const edges = [];
  for (let i = 0; i < n; i++) edges.push({ s: i, t: (i + 1) % n });
  return { nodes, edges };
}
function makeSmallWorld(n, rewireProb, width, height, seed = 1) {
  let s = seed >>> 0;
  const rng = () => {
    s = s + 1831565813 >>> 0;
    let t = s;
    t = Math.imul(t ^ t >>> 15, t | 1);
    t ^= t + Math.imul(t ^ t >>> 7, t | 61);
    return ((t ^ t >>> 14) >>> 0) / 4294967296;
  };
  const { nodes, edges } = makeRingGraph(n, width, height);
  for (let i = 0; i < n; i++) edges.push({ s: i, t: (i + 2) % n });
  for (const e of edges) {
    if (rng() < rewireProb) {
      let nt = Math.floor(rng() * n);
      if (nt === e.s) nt = (nt + 1) % n;
      e.t = nt;
    }
  }
  return { nodes, edges };
}
function makeScaleFree(n, width, height, seed = 1) {
  let s = seed >>> 0;
  const rng = () => {
    s = s + 1831565813 >>> 0;
    let t = s;
    t = Math.imul(t ^ t >>> 15, t | 1);
    t ^= t + Math.imul(t ^ t >>> 7, t | 61);
    return ((t ^ t >>> 14) >>> 0) / 4294967296;
  };
  const nodes = [];
  for (let i = 0; i < n; i++) {
    nodes.push({
      id: i,
      x: width / 2 + (rng() - 0.5) * 200,
      y: height / 2 + (rng() - 0.5) * 200,
      vx: 0,
      vy: 0
    });
  }
  const edges = [];
  edges.push({ s: 0, t: 1 });
  edges.push({ s: 1, t: 2 });
  edges.push({ s: 2, t: 0 });
  const degree = new Array(n).fill(0);
  degree[0] = 2;
  degree[1] = 2;
  degree[2] = 2;
  for (let i = 3; i < n; i++) {
    const totalDeg = degree.reduce((a, b) => a + b, 0);
    const targets = /* @__PURE__ */ new Set();
    while (targets.size < Math.min(2, i)) {
      let r = rng() * totalDeg;
      for (let j = 0; j < i; j++) {
        r -= degree[j];
        if (r <= 0) {
          targets.add(j);
          break;
        }
      }
    }
    for (const t of targets) {
      edges.push({ s: i, t });
      degree[i]++;
      degree[t]++;
    }
  }
  return { nodes, edges };
}
function degreeOf(nodes, edges) {
  const d = new Array(nodes.length).fill(0);
  for (const e of edges) {
    d[e.s]++;
    d[e.t]++;
  }
  return d;
}

// docs/.readrun/widgets/force-graph.tsx
var import_jsx_runtime6 = __toESM(require_jsx_runtime(), 1);
var TOPOS = [
  { id: "random", label: "Random" },
  { id: "ring", label: "Ring" },
  { id: "smallWorld", label: "Small-world" },
  { id: "scaleFree", label: "Scale-free" }
];
function ForceGraph() {
  const W = 540;
  const H = 420;
  const [topo, setTopo] = (0, import_react4.useState)("scaleFree");
  const [n, setN] = (0, import_react4.useState)(28);
  const [seed, setSeed] = (0, import_react4.useState)(7);
  const [freeze, setFreeze] = (0, import_react4.useState)(false);
  const [hover, setHover] = (0, import_react4.useState)(null);
  const [, force] = (0, import_react4.useState)(0);
  const stateRef = (0, import_react4.useRef)({ nodes: [], edges: [] });
  const dragRef = (0, import_react4.useRef)({ id: null, offX: 0, offY: 0 });
  const svgRef = (0, import_react4.useRef)(null);
  const rafRef = (0, import_react4.useRef)(0);
  (0, import_react4.useEffect)(() => {
    let g;
    if (topo === "random") g = makeRandomGraph(n, 0.12, W, H, seed);
    else if (topo === "ring") g = makeRingGraph(n, W, H);
    else if (topo === "smallWorld") g = makeSmallWorld(n, 0.15, W, H, seed);
    else g = makeScaleFree(n, W, H, seed);
    stateRef.current = g;
    force((x) => x + 1);
  }, [topo, n, seed]);
  (0, import_react4.useEffect)(() => {
    if (freeze) return;
    const tick = () => {
      forceStep(stateRef.current.nodes, stateRef.current.edges, { width: W, height: H });
      force((x) => x + 1);
      rafRef.current = requestAnimationFrame(tick);
    };
    rafRef.current = requestAnimationFrame(tick);
    return () => cancelAnimationFrame(rafRef.current);
  }, [freeze]);
  const degree = degreeOf(stateRef.current.nodes, stateRef.current.edges);
  const maxDeg = Math.max(...degree, 1);
  const histBins = 10;
  const hist = new Array(histBins).fill(0);
  for (const d of degree) {
    const i = Math.min(histBins - 1, Math.floor(d / (maxDeg + 1) * histBins));
    hist[i]++;
  }
  const histMax = Math.max(...hist, 1);
  function pos(e) {
    const rect = svgRef.current.getBoundingClientRect();
    return [(e.clientX - rect.left) * (W / rect.width), (e.clientY - rect.top) * (H / rect.height)];
  }
  function down(e) {
    const [x, y] = pos(e);
    let best = -1;
    let bd = 30;
    for (const node of stateRef.current.nodes) {
      const d = Math.hypot(node.x - x, node.y - y);
      if (d < bd) {
        bd = d;
        best = node.id;
      }
    }
    if (best >= 0) {
      dragRef.current = { id: best, offX: stateRef.current.nodes[best].x - x, offY: stateRef.current.nodes[best].y - y };
      stateRef.current.nodes[best].fixed = true;
    }
  }
  function move(e) {
    const [x, y] = pos(e);
    if (dragRef.current.id !== null) {
      const node = stateRef.current.nodes[dragRef.current.id];
      if (node) {
        node.x = x + dragRef.current.offX;
        node.y = y + dragRef.current.offY;
        node.vx = 0;
        node.vy = 0;
      }
      return;
    }
    let h = null;
    let bd = 24;
    for (const node of stateRef.current.nodes) {
      const d = Math.hypot(node.x - x, node.y - y);
      if (d < bd) {
        bd = d;
        h = node.id;
      }
    }
    setHover(h);
  }
  function up() {
    if (dragRef.current.id !== null) {
      const node = stateRef.current.nodes[dragRef.current.id];
      if (node) node.fixed = false;
    }
    dragRef.current.id = null;
  }
  const highlightSet = (0, import_react4.useMemo)(() => {
    if (hover === null) return /* @__PURE__ */ new Set();
    const s = /* @__PURE__ */ new Set([hover]);
    for (const e of stateRef.current.edges) {
      if (e.s === hover) s.add(e.t);
      if (e.t === hover) s.add(e.s);
    }
    return s;
  }, [hover]);
  return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
    Shell,
    {
      title: "Force-Directed Graph",
      meta: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
        /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Stat, { label: "nodes", value: stateRef.current.nodes.length }),
        /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Stat, { label: "edges", value: stateRef.current.edges.length }),
        /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Stat, { label: "max deg", value: maxDeg, color: "var(--viz-warn)" })
      ] }),
      children: [
        /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Sub, { children: "Four classic topologies. Drag a node to fix it (and let the rest settle around it). Hover to highlight neighbours; the histogram on the right shows the degree distribution." }),
        /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Tabs, { value: topo, onChange: (id) => setTopo(id), items: TOPOS }),
        /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "viz-row", children: [
          /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Stage, { children: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
            "svg",
            {
              ref: svgRef,
              viewBox: `0 0 ${W} ${H}`,
              width: W,
              height: H,
              style: { display: "block", maxWidth: "100%", touchAction: "none" },
              onPointerDown: down,
              onPointerMove: move,
              onPointerUp: up,
              onPointerLeave: up,
              children: [
                stateRef.current.edges.map((e, i) => {
                  const a = stateRef.current.nodes[e.s];
                  const b = stateRef.current.nodes[e.t];
                  if (!a || !b) return null;
                  const dim = hover !== null && !(highlightSet.has(e.s) && highlightSet.has(e.t));
                  return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
                    "line",
                    {
                      x1: a.x,
                      y1: a.y,
                      x2: b.x,
                      y2: b.y,
                      stroke: "var(--viz-axis)",
                      strokeWidth: dim ? 0.6 : 1.2,
                      opacity: dim ? 0.18 : 0.7
                    },
                    i
                  );
                }),
                stateRef.current.nodes.map((node) => {
                  const d = degree[node.id];
                  const r = 4 + d / (maxDeg + 1) * 8;
                  const isHover = hover === node.id;
                  const inHL = highlightSet.has(node.id);
                  const fill = hover !== null && !inHL ? "var(--text-muted)" : "var(--viz-trace)";
                  return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
                    "circle",
                    {
                      cx: node.x,
                      cy: node.y,
                      r,
                      fill,
                      stroke: "var(--bg)",
                      strokeWidth: isHover ? 2.5 : 1.5,
                      opacity: hover !== null && !inHL ? 0.35 : 1,
                      style: { cursor: "grab" }
                    },
                    node.id
                  );
                })
              ]
            }
          ) }),
          /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(Panel, { minWidth: 220, children: [
            /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(SectionLabel, { children: "Controls" }),
            /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: { display: "flex", gap: 6, flexWrap: "wrap", marginBottom: 12 }, children: [
              /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Btn, { kind: "primary", onClick: () => setSeed((s) => s + 1), children: "Regenerate" }),
              /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Btn, { kind: "ghost", onClick: () => setFreeze((f) => !f), children: freeze ? "Unfreeze" : "Freeze" })
            ] }),
            /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: { display: "flex", gap: 6, flexWrap: "wrap", marginBottom: 12 }, children: [12, 20, 28, 40, 60].map((v) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Btn, { kind: "tag", active: n === v, onClick: () => setN(v), children: v }, v)) }),
            /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(SectionLabel, { children: "Degree distribution" }),
            /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("svg", { viewBox: "0 0 200 80", width: "100%", height: 80, style: { display: "block" }, children: [
              hist.map((c, i) => {
                const bw = 200 / histBins;
                const h = c / histMax * 70;
                return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("rect", { x: i * bw + 2, y: 75 - h, width: bw - 4, height: h, fill: "var(--viz-warn)" }, i);
              }),
              /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("line", { x1: 0, y1: 75, x2: 200, y2: 75, stroke: "var(--viz-axis)", strokeWidth: "1" })
            ] }),
            /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(Notice, { children: [
              /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("strong", { children: "What to notice." }),
              " Random graphs have Poisson-shaped degree distributions. Scale-free graphs (preferential attachment) produce hubs \u2014 a long-tailed distribution visible in the histogram. Small-world keeps short paths despite local clustering."
            ] })
          ] })
        ] })
      ]
    }
  );
}

// docs/.readrun/widgets/force-graph.readrun-entry.ts
render(<ForceGraph />);

Git graph explorer

jsx
// generated by @readrun/widgets — edit .readrun/widgets/git-graph-explorer.tsx, then re-run rr
// @readrun/widgets@10f3ae2 — generated 2026-08-01T09:21:00Z
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __commonJS = (cb, mod) => function __require() {
  return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
};
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 __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
  // If the importer is in node compatibility mode or this is not an ESM
  // file that has been converted to a CommonJS file using a Babel-
  // compatible transform (i.e. "__esModule" has not been set), then set
  // "default" to the CommonJS "module.exports" for node compatibility.
  isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
  mod
));
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);

// globals:react
var require_react = __commonJS({
  "globals:react"(exports, module) {
    module.exports = globalThis.React;
  }
});

// globals:react/jsx-runtime
var require_jsx_runtime = __commonJS({
  "globals:react/jsx-runtime"(exports, module) {
    var React36 = globalThis.React;
    function jsx9(type, props, key) {
      const nextProps = key === void 0 ? props : Object.assign({}, props, { key });
      return React36.createElement(type, nextProps);
    }
    module.exports = { Fragment: React36.Fragment, jsx: jsx9, jsxs: jsx9 };
  }
});

// node_modules/use-sync-external-store/cjs/use-sync-external-store-shim.development.js
var require_use_sync_external_store_shim_development = __commonJS({
  "node_modules/use-sync-external-store/cjs/use-sync-external-store-shim.development.js"(exports) {
    "use strict";
    (function() {
      function is(x, y) {
        return x === y && (0 !== x || 1 / x === 1 / y) || x !== x && y !== y;
      }
      function useSyncExternalStore$2(subscribe2, getSnapshot2) {
        didWarnOld18Alpha || void 0 === React36.startTransition || (didWarnOld18Alpha = true, console.error(
          "You are using an outdated, pre-release alpha of React 18 that does not support useSyncExternalStore. The use-sync-external-store shim will not work correctly. Upgrade to a newer pre-release."
        ));
        var value = getSnapshot2();
        if (!didWarnUncachedGetSnapshot) {
          var cachedValue = getSnapshot2();
          objectIs(value, cachedValue) || (console.error(
            "The result of getSnapshot should be cached to avoid an infinite loop"
          ), didWarnUncachedGetSnapshot = true);
        }
        cachedValue = useState8({
          inst: { value, getSnapshot: getSnapshot2 }
        });
        var inst = cachedValue[0].inst, forceUpdate = cachedValue[1];
        useLayoutEffect2(
          function() {
            inst.value = value;
            inst.getSnapshot = getSnapshot2;
            checkIfSnapshotChanged(inst) && forceUpdate({ inst });
          },
          [subscribe2, value, getSnapshot2]
        );
        useEffect6(
          function() {
            checkIfSnapshotChanged(inst) && forceUpdate({ inst });
            return subscribe2(function() {
              checkIfSnapshotChanged(inst) && forceUpdate({ inst });
            });
          },
          [subscribe2]
        );
        useDebugValue(value);
        return value;
      }
      function checkIfSnapshotChanged(inst) {
        var latestGetSnapshot = inst.getSnapshot;
        inst = inst.value;
        try {
          var nextValue = latestGetSnapshot();
          return !objectIs(inst, nextValue);
        } catch (error2) {
          return true;
        }
      }
      function useSyncExternalStore$1(subscribe2, getSnapshot2) {
        return getSnapshot2();
      }
      "undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ && "function" === typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStart && __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStart(Error());
      var React36 = require_react(), objectIs = "function" === typeof Object.is ? Object.is : is, useState8 = React36.useState, useEffect6 = React36.useEffect, useLayoutEffect2 = React36.useLayoutEffect, useDebugValue = React36.useDebugValue, didWarnOld18Alpha = false, didWarnUncachedGetSnapshot = false, shim = "undefined" === typeof window || "undefined" === typeof window.document || "undefined" === typeof window.document.createElement ? useSyncExternalStore$1 : useSyncExternalStore$2;
      exports.useSyncExternalStore = void 0 !== React36.useSyncExternalStore ? React36.useSyncExternalStore : shim;
      "undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ && "function" === typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop && __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop(Error());
    })();
  }
});

// node_modules/use-sync-external-store/shim/index.js
var require_shim = __commonJS({
  "node_modules/use-sync-external-store/shim/index.js"(exports, module) {
    "use strict";
    if (false) {
      module.exports = null;
    } else {
      module.exports = require_use_sync_external_store_shim_development();
    }
  }
});

// docs/.readrun/widgets/git-graph-explorer.tsx
var import_react8 = __toESM(require_react(), 1);

// src/widgets/diagram/Flow.tsx
var import_react3 = __toESM(require_react(), 1);

// src/widgets/diagram/layout/dag.ts
function dag(nodes, edges, opts) {
  const rankSep = opts?.rankSeparation ?? 120;
  const nodeSep = opts?.nodeSeparation ?? 40;
  const defW = opts?.defaultWidth ?? 100;
  const defH = opts?.defaultHeight ?? 50;
  if (nodes.length === 0) return [];
  const nodeIds = new Set(nodes.map((n) => n.id));
  const outEdges = /* @__PURE__ */ new Map();
  const inDegree = /* @__PURE__ */ new Map();
  const edgeByTo = /* @__PURE__ */ new Map();
  for (const n of nodes) {
    outEdges.set(n.id, []);
    inDegree.set(n.id, 0);
  }
  for (const e of edges) {
    if (!nodeIds.has(e.from) || !nodeIds.has(e.to)) continue;
    outEdges.get(e.from).push(e.to);
    inDegree.set(e.to, (inDegree.get(e.to) ?? 0) + 1);
    if (!edgeByTo.has(e.to)) edgeByTo.set(e.to, e);
  }
  const rank = /* @__PURE__ */ new Map();
  const queue = [];
  for (const n of nodes) {
    if ((inDegree.get(n.id) ?? 0) === 0) {
      queue.push(n.id);
      rank.set(n.id, 0);
    }
  }
  const sorted = [];
  while (queue.length > 0) {
    queue.sort();
    const id = queue.shift();
    sorted.push(id);
    for (const childId of outEdges.get(id) ?? []) {
      const newRank = (rank.get(id) ?? 0) + 1;
      if (!rank.has(childId) || rank.get(childId) < newRank) {
        rank.set(childId, newRank);
      }
      const newIn = (inDegree.get(childId) ?? 0) - 1;
      inDegree.set(childId, newIn);
      if (newIn === 0) {
        queue.push(childId);
      }
    }
  }
  if (sorted.length !== nodes.length) {
    for (const e of edges) {
      if ((rank.get(e.from) ?? -1) >= (rank.get(e.to) ?? -1) && sorted.includes(e.from)) {
      }
    }
    const unprocessed = new Set(nodes.map((n) => n.id).filter((id) => !sorted.includes(id)));
    for (const e of edges) {
      if (unprocessed.has(e.to) || unprocessed.has(e.from)) {
        throw new Error(
          `dag layout: cycle detected. Edge "${e.id}" (${e.from} \u2192 ${e.to}) is part of a cycle.`
        );
      }
    }
    throw new Error("dag layout: cycle detected in the graph.");
  }
  const rankGroups = /* @__PURE__ */ new Map();
  for (const [id, r2] of rank.entries()) {
    if (!rankGroups.has(r2)) rankGroups.set(r2, []);
    rankGroups.get(r2).push(id);
  }
  for (const group of rankGroups.values()) {
    group.sort();
  }
  const nodeById = new Map(nodes.map((n) => [n.id, n]));
  const positioned = /* @__PURE__ */ new Map();
  for (const [r2, group] of rankGroups.entries()) {
    const n = group.length;
    const totalWidth = n * defW + (n - 1) * nodeSep;
    const startX = -totalWidth / 2 + defW / 2;
    for (let i = 0; i < group.length; i++) {
      const id = group[i];
      const node = nodeById.get(id);
      const w = node.width ?? defW;
      const h = node.height ?? defH;
      positioned.set(id, {
        ...node,
        x: startX + i * (defW + nodeSep),
        y: r2 * rankSep,
        width: w,
        height: h
      });
    }
  }
  return nodes.map((n) => positioned.get(n.id));
}

// src/widgets/diagram/layout/tree.ts
function tree(rootNode, childrenOf, opts) {
  const levelSep = opts?.levelSeparation ?? 100;
  const siblingSep = opts?.siblingSeparation ?? 40;
  const defW = opts?.defaultWidth ?? 100;
  const defH = opts?.defaultHeight ?? 50;
  const nextX = /* @__PURE__ */ new Map();
  function buildTree(node, depth) {
    const children = childrenOf(node).map((c) => buildTree(c, depth + 1));
    const internal = {
      source: node,
      children,
      depth,
      x: 0,
      y: depth * levelSep
    };
    if (children.length === 0) {
      const cur = nextX.get(depth) ?? 0;
      internal.x = cur;
      nextX.set(depth, cur + defW + siblingSep);
    } else {
      const leftX = children[0].x;
      const rightX = children[children.length - 1].x;
      internal.x = (leftX + rightX) / 2;
      const cur = nextX.get(depth) ?? 0;
      if (internal.x + defW / 2 > cur) {
        nextX.set(depth, internal.x + defW + siblingSep);
      }
    }
    return internal;
  }
  const root = buildTree(rootNode, 0);
  const result = [];
  function collect(n) {
    const node = n.source;
    result.push({
      ...node,
      x: n.x,
      y: n.y,
      width: node.width ?? defW,
      height: node.height ?? defH
    });
    for (const c of n.children) collect(c);
  }
  collect(root);
  return result;
}

// src/widgets/math/force.ts
function forceStep(nodes, edges, cfg) {
  const repulsion = cfg.repulsion ?? 4500;
  const springK = cfg.springK ?? 0.04;
  const springRest = cfg.springRest ?? 70;
  const damping = cfg.damping ?? 0.85;
  const centerPull = cfg.centerPull ?? 5e-3;
  const dt = cfg.dt ?? 1;
  const cx = cfg.width / 2;
  const cy = cfg.height / 2;
  for (let i = 0; i < nodes.length; i++) {
    const ni = nodes[i];
    if (ni.fixed) continue;
    let fx = 0;
    let fy = 0;
    for (let j = 0; j < nodes.length; j++) {
      if (i === j) continue;
      const nj = nodes[j];
      const dx = ni.x - nj.x;
      const dy = ni.y - nj.y;
      const d2 = dx * dx + dy * dy + 0.01;
      const f = repulsion / d2;
      const d = Math.sqrt(d2);
      fx += dx / d * f;
      fy += dy / d * f;
    }
    fx += (cx - ni.x) * centerPull;
    fy += (cy - ni.y) * centerPull;
    ni.vx = (ni.vx + fx * dt) * damping;
    ni.vy = (ni.vy + fy * dt) * damping;
  }
  for (const e of edges) {
    const a = nodes[e.s];
    const b = nodes[e.t];
    if (!a || !b) continue;
    const dx = b.x - a.x;
    const dy = b.y - a.y;
    const d = Math.hypot(dx, dy) + 0.01;
    const f = springK * (d - springRest);
    const fx = dx / d * f;
    const fy = dy / d * f;
    if (!a.fixed) {
      a.vx += fx * dt;
      a.vy += fy * dt;
    }
    if (!b.fixed) {
      b.vx -= fx * dt;
      b.vy -= fy * dt;
    }
  }
  for (const n of nodes) {
    if (n.fixed) continue;
    n.x += n.vx * dt;
    n.y += n.vy * dt;
    const m = 24;
    if (n.x < m) {
      n.x = m;
      n.vx *= -0.4;
    }
    if (n.x > cfg.width - m) {
      n.x = cfg.width - m;
      n.vx *= -0.4;
    }
    if (n.y < m) {
      n.y = m;
      n.vy *= -0.4;
    }
    if (n.y > cfg.height - m) {
      n.y = cfg.height - m;
      n.vy *= -0.4;
    }
  }
}

// src/widgets/math/random.ts
function mulberry32(seed) {
  let s = seed >>> 0;
  return () => {
    s = s + 1831565813 >>> 0;
    let t = s;
    t = Math.imul(t ^ t >>> 15, t | 1);
    t ^= t + Math.imul(t ^ t >>> 7, t | 61);
    return ((t ^ t >>> 14) >>> 0) / 4294967296;
  };
}

// src/widgets/diagram/layout/force.ts
function force(nodes, edges, opts) {
  if (nodes.length === 0) return [];
  const iterations = opts?.iterations ?? 300;
  const width = opts?.width ?? 800;
  const height = opts?.height ?? 600;
  const seed = opts?.seed ?? 1;
  const defW = opts?.defaultWidth ?? 100;
  const defH = opts?.defaultHeight ?? 50;
  const rng = mulberry32(seed);
  const indexById = new Map(nodes.map((n, i) => [n.id, i]));
  const forceNodes = nodes.map((_n, i) => ({
    id: i,
    x: width / 2 + (rng() - 0.5) * 200,
    y: height / 2 + (rng() - 0.5) * 200,
    vx: 0,
    vy: 0
  }));
  const forceEdges = edges.map((e) => {
    const s = indexById.get(e.from);
    const t = indexById.get(e.to);
    if (s === void 0 || t === void 0) return null;
    return { s, t };
  }).filter((e) => e !== null);
  const cfg = { width, height };
  for (let i = 0; i < iterations; i++) {
    forceStep(forceNodes, forceEdges, cfg);
  }
  return nodes.map((node, i) => ({
    ...node,
    x: forceNodes[i].x,
    y: forceNodes[i].y,
    width: node.width ?? defW,
    height: node.height ?? defH
  }));
}

// src/widgets/diagram/edge/ports.ts
function nodePorts(node) {
  const { x: cx, y: cy, width, height } = node;
  const w2 = width / 2;
  const h2 = height / 2;
  return {
    top: { x: cx, y: cy - h2, dir: { dx: 0, dy: -1 } },
    right: { x: cx + w2, y: cy, dir: { dx: 1, dy: 0 } },
    bottom: { x: cx, y: cy + h2, dir: { dx: 0, dy: 1 } },
    left: { x: cx - w2, y: cy, dir: { dx: -1, dy: 0 } }
  };
}
function selectPort(ports, targetVec, exclude) {
  const len = Math.hypot(targetVec.x, targetVec.y) || 1;
  const tx = targetVec.x / len;
  const ty = targetVec.y / len;
  const ranked = Object.keys(ports).map((name) => ({
    name,
    port: ports[name],
    score: ports[name].dir.dx * tx + ports[name].dir.dy * ty
  })).sort((a, b) => b.score - a.score);
  if (exclude && exclude.size > 0) {
    const free = ranked.find((r2) => !exclude.has(r2.name));
    if (free) return { name: free.name, port: free.port };
  }
  const top = ranked[0];
  return { name: top.name, port: top.port };
}
function selectEdgePorts(fromNode, toNode, opts) {
  const dx = toNode.x - fromNode.x;
  const dy = toNode.y - fromNode.y;
  const fromPorts = nodePorts(fromNode);
  const toPorts = nodePorts(toNode);
  const fromSel = selectPort(fromPorts, { x: dx, y: dy }, opts?.excludeFrom);
  const toSel = selectPort(toPorts, { x: -dx, y: -dy }, opts?.excludeTo);
  return { from: fromSel.port, to: toSel.port, fromName: fromSel.name, toName: toSel.name };
}

// src/widgets/diagram/edge/router.ts
function straightWithPorts(from, to) {
  return `M ${num(from.x)} ${num(from.y)} L ${num(to.x)} ${num(to.y)}`;
}
function curveWithPorts(from, to) {
  const dist = Math.hypot(to.x - from.x, to.y - from.y);
  const offset = Math.max(20, 0.4 * dist);
  const c1x = from.x + from.dir.dx * offset;
  const c1y = from.y + from.dir.dy * offset;
  const c2x = to.x + to.dir.dx * offset;
  const c2y = to.y + to.dir.dy * offset;
  return `M ${num(from.x)} ${num(from.y)} C ${num(c1x)} ${num(c1y)} ${num(c2x)} ${num(c2y)} ${num(to.x)} ${num(to.y)}`;
}
function orthogonalWithPorts(from, to, opts) {
  const buffer = opts?.buffer ?? 20;
  const sx = from.x;
  const sy = from.y;
  const tx = to.x;
  const ty = to.y;
  const sgx = sx + from.dir.dx * buffer;
  const sgy = sy + from.dir.dy * buffer;
  const tgx = tx + to.dir.dx * buffer;
  const tgy = ty + to.dir.dy * buffer;
  const srcHoriz = from.dir.dx !== 0;
  const tgtHoriz = to.dir.dx !== 0;
  let mid;
  if (srcHoriz && tgtHoriz) {
    const midX = (sgx + tgx) / 2;
    mid = `L ${num(midX)} ${num(sgy)} L ${num(midX)} ${num(tgy)}`;
  } else if (!srcHoriz && !tgtHoriz) {
    const midY = (sgy + tgy) / 2;
    mid = `L ${num(sgx)} ${num(midY)} L ${num(tgx)} ${num(midY)}`;
  } else if (srcHoriz && !tgtHoriz) {
    mid = `L ${num(tgx)} ${num(sgy)}`;
  } else {
    mid = `L ${num(sgx)} ${num(tgy)}`;
  }
  return `M ${num(sx)} ${num(sy)} L ${num(sgx)} ${num(sgy)} ${mid} L ${num(tgx)} ${num(tgy)} L ${num(tx)} ${num(ty)}`;
}
function num(n) {
  return n.toFixed(2).replace(/\.?0+$/, "");
}

// src/widgets/diagram/FlowNode.tsx
var import_react2 = __toESM(require_react(), 1);

// src/widgets/diagram/viewport.ts
var import_react = __toESM(require_react(), 1);

// src/widgets/interaction/coords.ts
function applyMatrix(m, x, y) {
  return {
    x: m.a * x + m.c * y + m.e,
    y: m.b * x + m.d * y + m.f
  };
}
function screenToViewBox(target, clientX, clientY) {
  const ctm = target.getScreenCTM();
  if (!ctm) return null;
  const inv = ctm.inverse();
  return applyMatrix(inv, clientX, clientY);
}

// src/widgets/diagram/viewport.ts
var MIN_ZOOM = 0.25;
var MAX_ZOOM = 3;
function clientToFlow(target, clientX, clientY, innerDx, innerDy, view) {
  const point = screenToViewBox(target, clientX, clientY);
  if (!point) return null;
  return {
    x: (point.x - innerDx - view.panX) / view.zoom,
    y: (point.y - innerDy - view.panY) / view.zoom
  };
}
function panFromPointer(startView, startPointer, currentPointer) {
  return {
    ...startView,
    panX: startView.panX + currentPointer.x - startPointer.x,
    panY: startView.panY + currentPointer.y - startPointer.y
  };
}
function zoomFromWheel(zoom, deltaY) {
  const factor = 1 - deltaY * 1e-3;
  return Math.max(MIN_ZOOM, Math.min(MAX_ZOOM, zoom * factor));
}
function useFlowViewport(svgRef) {
  const [view, setView] = import_react.default.useState({
    panX: 0,
    panY: 0,
    zoom: 1
  });
  const panStateRef = import_react.default.useRef(null);
  const onPointerDown = import_react.default.useCallback(
    (event) => {
      if (event.target !== svgRef.current) return;
      const point = screenToViewBox(event.currentTarget, event.clientX, event.clientY);
      if (!point) return;
      event.currentTarget.setPointerCapture(event.pointerId);
      panStateRef.current = { startPointer: point, startView: view };
    },
    [svgRef, view]
  );
  const onPointerMove = import_react.default.useCallback(
    (event) => {
      const panState = panStateRef.current;
      if (!panState) return;
      const point = screenToViewBox(event.currentTarget, event.clientX, event.clientY);
      if (!point) return;
      setView(panFromPointer(panState.startView, panState.startPointer, point));
    },
    []
  );
  const onPointerUp = import_react.default.useCallback(
    (event) => {
      if (event.currentTarget.hasPointerCapture(event.pointerId)) {
        event.currentTarget.releasePointerCapture(event.pointerId);
      }
      panStateRef.current = null;
    },
    []
  );
  const onWheel = import_react.default.useCallback((event) => {
    event.preventDefault();
    setView((current) => ({
      ...current,
      zoom: zoomFromWheel(current.zoom, event.deltaY)
    }));
  }, []);
  return { view, onPointerDown, onPointerMove, onPointerUp, onWheel };
}

// src/widgets/diagram/FlowNode.tsx
var import_jsx_runtime = __toESM(require_jsx_runtime(), 1);
var NODE_FILL = "var(--bg, #ffffff)";
var NODE_STROKE = "var(--text, #1f2328)";
function NodeShape({
  shape,
  width,
  height
}) {
  const sharedProps = {
    fill: NODE_FILL,
    stroke: NODE_STROKE,
    strokeWidth: 1
  };
  if (shape === "circle") {
    return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
      "circle",
      {
        cx: width / 2,
        cy: height / 2,
        r: Math.min(width, height) / 2,
        ...sharedProps
      }
    );
  }
  if (shape === "ellipse") {
    return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
      "ellipse",
      {
        cx: width / 2,
        cy: height / 2,
        rx: width / 2,
        ry: height / 2,
        ...sharedProps
      }
    );
  }
  if (shape === "diamond") {
    return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
      "polygon",
      {
        points: `${width / 2},0 ${width},${height / 2} ${width / 2},${height} 0,${height / 2}`,
        ...sharedProps
      }
    );
  }
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
    "rect",
    {
      width,
      height,
      x: 0,
      y: 0,
      ...sharedProps,
      rx: 0
    }
  );
}
function FlowNode({
  node,
  svgRef,
  innerDx,
  innerDy,
  view,
  onClick,
  onHover,
  onDragMove,
  draggable
}) {
  const offsetRef = import_react2.default.useRef(null);
  const movedRef = import_react2.default.useRef(false);
  const onPointerDown = (event) => {
    if (!draggable || !svgRef.current) return;
    event.stopPropagation();
    event.preventDefault();
    event.currentTarget.setPointerCapture(event.pointerId);
    const point = clientToFlow(
      svgRef.current,
      event.clientX,
      event.clientY,
      innerDx,
      innerDy,
      view
    );
    if (!point) return;
    offsetRef.current = { x: point.x - node.x, y: point.y - node.y };
    movedRef.current = false;
  };
  const onPointerMove = (event) => {
    const offset = offsetRef.current;
    if (!offset || !svgRef.current) return;
    const point = clientToFlow(
      svgRef.current,
      event.clientX,
      event.clientY,
      innerDx,
      innerDy,
      view
    );
    if (!point) return;
    onDragMove(point.x - offset.x, point.y - offset.y);
    movedRef.current = true;
  };
  const onPointerUp = (event) => {
    if (event.currentTarget.hasPointerCapture(event.pointerId)) {
      event.currentTarget.releasePointerCapture(event.pointerId);
    }
    offsetRef.current = null;
    if (!movedRef.current && onClick) {
      onClick(node);
    }
  };
  const { x, y, width, height, id } = node;
  const label = typeof node["label"] === "string" ? node["label"] : id;
  const shape = node.shape ?? "rect";
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
    "g",
    {
      transform: `translate(${x - width / 2}, ${y - height / 2})`,
      style: {
        cursor: draggable ? "grab" : onClick ? "pointer" : "default",
        touchAction: "none"
      },
      onPointerDown,
      onPointerMove,
      onPointerUp,
      onPointerCancel: onPointerUp,
      onMouseEnter: onHover ? () => onHover(node) : void 0,
      onMouseLeave: onHover ? () => onHover(null) : void 0,
      children: [
        /* @__PURE__ */ (0, import_jsx_runtime.jsx)(NodeShape, { shape, width, height }),
        /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
          "text",
          {
            x: width / 2,
            y: height / 2,
            dominantBaseline: "middle",
            textAnchor: "middle",
            fontSize: 11,
            fill: "var(--text, #1f2328)",
            fontFamily: "var(--font-body, ui-sans-serif, system-ui, sans-serif)",
            style: { userSelect: "none", pointerEvents: "none" },
            children: label
          }
        )
      ]
    }
  );
}

// src/widgets/diagram/Flow.tsx
var import_jsx_runtime2 = __toESM(require_jsx_runtime(), 1);
var ARROW_ID = "readrun-widget-flow-arrow";
var DEF_W = 100;
var DEF_H = 50;
var EDGE_STROKE = "var(--text-muted, #656d76)";
var INNER_DX_FACTOR = 0.5;
var INNER_DY = 20;
function defaultRenderEdge(pathStr, edge2) {
  return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
    "path",
    {
      d: pathStr,
      stroke: EDGE_STROKE,
      strokeWidth: 1.5,
      fill: "none",
      markerEnd: `url(#${ARROW_ID})`
    },
    edge2.id
  );
}
function pathFromPorts(router, from, to) {
  switch (router) {
    case "straight":
      return straightWithPorts(from, to);
    case "curve":
      return curveWithPorts(from, to);
    case "orthogonal":
    default:
      return orthogonalWithPorts(from, to);
  }
}
function Flow({
  nodes,
  edges,
  layout: layoutMode,
  childrenOf,
  rootId,
  edgeRouter,
  renderNode,
  renderEdge,
  width,
  height,
  onNodeClick,
  onNodeHover,
  draggable = true
}) {
  const svgRef = import_react3.default.useRef(null);
  const innerDx = width * INNER_DX_FACTOR;
  const innerDy = INNER_DY;
  const [overrides, setOverrides] = import_react3.default.useState({});
  const viewport = useFlowViewport(svgRef);
  const { view } = viewport;
  const updateOverride = import_react3.default.useCallback((id, x, y) => {
    setOverrides((prev) => ({ ...prev, [id]: { x, y } }));
  }, []);
  const layoutNodes = import_react3.default.useMemo(() => {
    if (layoutMode === "manual") {
      return nodes.map((node) => ({
        ...node,
        x: node.x ?? 0,
        y: node.y ?? 0,
        width: node.width ?? DEF_W,
        height: node.height ?? DEF_H
      }));
    }
    if (layoutMode === "dag") return dag(nodes, edges);
    if (layoutMode === "tree") {
      const root = nodes.find((node) => node.id === rootId) ?? nodes[0];
      return root ? tree(root, childrenOf ?? (() => []), {
        levelSeparation: height / Math.max(4, nodes.length)
      }) : [];
    }
    return force(nodes, edges, { width, height });
  }, [childrenOf, edges, height, layoutMode, nodes, rootId, width]);
  const positioned = import_react3.default.useMemo(
    () => layoutNodes.map((node) => {
      const override = overrides[node.id];
      return override ? { ...node, ...override } : node;
    }),
    [layoutNodes, overrides]
  );
  const posById = import_react3.default.useMemo(
    () => new Map(positioned.map((node) => [node.id, node])),
    [positioned]
  );
  const router = edgeRouter ?? (layoutMode === "force" ? "curve" : layoutMode === "manual" ? "straight" : "orthogonal");
  const edgeElements = import_react3.default.useMemo(() => {
    const usedPorts = /* @__PURE__ */ new Map();
    return edges.map((edge2) => {
      const fromNode = posById.get(edge2.from);
      const toNode = posById.get(edge2.to);
      if (!fromNode || !toNode) return null;
      const fromUsed = usedPorts.get(edge2.from) ?? /* @__PURE__ */ new Set();
      const toUsed = usedPorts.get(edge2.to) ?? /* @__PURE__ */ new Set();
      const { from, to, fromName, toName } = selectEdgePorts(fromNode, toNode, {
        excludeFrom: fromUsed,
        excludeTo: toUsed
      });
      fromUsed.add(fromName);
      toUsed.add(toName);
      usedPorts.set(edge2.from, fromUsed);
      usedPorts.set(edge2.to, toUsed);
      const path = pathFromPorts(router, from, to);
      return renderEdge ? renderEdge(path, edge2, fromNode, toNode) : defaultRenderEdge(path, edge2);
    }).filter(Boolean);
  }, [edges, posById, renderEdge, router]);
  const nodeElements = positioned.map((n) => {
    if (renderNode) return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react3.default.Fragment, { children: renderNode(n) }, n.id);
    return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
      FlowNode,
      {
        node: n,
        svgRef,
        innerDx,
        innerDy,
        view,
        draggable,
        onClick: onNodeClick,
        onHover: onNodeHover,
        onDragMove: (x, y) => updateOverride(n.id, x, y)
      },
      n.id
    );
  });
  const innerTransform = `translate(${innerDx + view.panX}, ${innerDy + view.panY}) scale(${view.zoom})`;
  return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
    "div",
    {
      style: {
        position: "relative",
        background: "var(--card-bg, #ffffff)",
        border: "1px solid var(--border, #d0d7de)",
        overflow: "hidden"
      },
      children: [
        /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
          "svg",
          {
            ref: svgRef,
            viewBox: `0 0 ${width} ${height}`,
            width,
            height,
            style: { display: "block", maxWidth: "100%", touchAction: "none" },
            onPointerDown: viewport.onPointerDown,
            onPointerMove: viewport.onPointerMove,
            onPointerUp: viewport.onPointerUp,
            onPointerCancel: viewport.onPointerUp,
            onWheel: viewport.onWheel,
            children: [
              /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("defs", { children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
                "marker",
                {
                  id: ARROW_ID,
                  viewBox: "0 0 10 10",
                  refX: 10,
                  refY: 5,
                  markerWidth: 6,
                  markerHeight: 6,
                  orient: "auto-start-reverse",
                  children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M 0 0 L 10 5 L 0 10 z", fill: EDGE_STROKE })
                }
              ) }),
              /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("g", { transform: innerTransform, children: [
                edgeElements,
                nodeElements
              ] })
            ]
          }
        ),
        draggable && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
          "div",
          {
            style: {
              position: "absolute",
              bottom: 6,
              right: 8,
              fontSize: 11,
              color: "var(--text-muted, #656d76)",
              fontFamily: "var(--font-mono, ui-monospace, monospace)",
              letterSpacing: "0.04em",
              pointerEvents: "none"
            },
            children: "drag nodes \u2022 drag empty \u2022 scroll to zoom"
          }
        )
      ]
    }
  );
}

// src/widgets/primitives/index.tsx
var import_react7 = __toESM(require_react());

// node_modules/clsx/dist/clsx.mjs
function r(e) {
  var t, f, n = "";
  if ("string" == typeof e || "number" == typeof e) n += e;
  else if ("object" == typeof e) if (Array.isArray(e)) {
    var o = e.length;
    for (t = 0; t < o; t++) e[t] && (f = r(e[t])) && (n && (n += " "), n += f);
  } else for (f in e) e[f] && (n && (n += " "), n += f);
  return n;
}
function clsx() {
  for (var e, t, f = 0, n = "", o = arguments.length; f < o; f++) (e = arguments[f]) && (t = r(e)) && (n && (n += " "), n += t);
  return n;
}

// node_modules/tailwind-merge/dist/bundle-mjs.mjs
var concatArrays = (array1, array2) => {
  const combinedArray = new Array(array1.length + array2.length);
  for (let i = 0; i < array1.length; i++) {
    combinedArray[i] = array1[i];
  }
  for (let i = 0; i < array2.length; i++) {
    combinedArray[array1.length + i] = array2[i];
  }
  return combinedArray;
};
var createClassValidatorObject = (classGroupId, validator) => ({
  classGroupId,
  validator
});
var createClassPartObject = (nextPart = /* @__PURE__ */ new Map(), validators = null, classGroupId) => ({
  nextPart,
  validators,
  classGroupId
});
var CLASS_PART_SEPARATOR = "-";
var EMPTY_CONFLICTS = [];
var ARBITRARY_PROPERTY_PREFIX = "arbitrary..";
var createClassGroupUtils = (config) => {
  const classMap = createClassMap(config);
  const {
    conflictingClassGroups,
    conflictingClassGroupModifiers
  } = config;
  const getClassGroupId = (className) => {
    if (className.startsWith("[") && className.endsWith("]")) {
      return getGroupIdForArbitraryProperty(className);
    }
    const classParts = className.split(CLASS_PART_SEPARATOR);
    const startIndex = classParts[0] === "" && classParts.length > 1 ? 1 : 0;
    return getGroupRecursive(classParts, startIndex, classMap);
  };
  const getConflictingClassGroupIds = (classGroupId, hasPostfixModifier) => {
    if (hasPostfixModifier) {
      const modifierConflicts = conflictingClassGroupModifiers[classGroupId];
      const baseConflicts = conflictingClassGroups[classGroupId];
      if (modifierConflicts) {
        if (baseConflicts) {
          return concatArrays(baseConflicts, modifierConflicts);
        }
        return modifierConflicts;
      }
      return baseConflicts || EMPTY_CONFLICTS;
    }
    return conflictingClassGroups[classGroupId] || EMPTY_CONFLICTS;
  };
  return {
    getClassGroupId,
    getConflictingClassGroupIds
  };
};
var getGroupRecursive = (classParts, startIndex, classPartObject) => {
  const classPathsLength = classParts.length - startIndex;
  if (classPathsLength === 0) {
    return classPartObject.classGroupId;
  }
  const currentClassPart = classParts[startIndex];
  const nextClassPartObject = classPartObject.nextPart.get(currentClassPart);
  if (nextClassPartObject) {
    const result = getGroupRecursive(classParts, startIndex + 1, nextClassPartObject);
    if (result) return result;
  }
  const validators = classPartObject.validators;
  if (validators === null) {
    return void 0;
  }
  const classRest = startIndex === 0 ? classParts.join(CLASS_PART_SEPARATOR) : classParts.slice(startIndex).join(CLASS_PART_SEPARATOR);
  const validatorsLength = validators.length;
  for (let i = 0; i < validatorsLength; i++) {
    const validatorObj = validators[i];
    if (validatorObj.validator(classRest)) {
      return validatorObj.classGroupId;
    }
  }
  return void 0;
};
var getGroupIdForArbitraryProperty = (className) => className.slice(1, -1).indexOf(":") === -1 ? void 0 : (() => {
  const content = className.slice(1, -1);
  const colonIndex = content.indexOf(":");
  const property = content.slice(0, colonIndex);
  return property ? ARBITRARY_PROPERTY_PREFIX + property : void 0;
})();
var createClassMap = (config) => {
  const {
    theme,
    classGroups
  } = config;
  return processClassGroups(classGroups, theme);
};
var processClassGroups = (classGroups, theme) => {
  const classMap = createClassPartObject();
  for (const classGroupId in classGroups) {
    const group = classGroups[classGroupId];
    processClassesRecursively(group, classMap, classGroupId, theme);
  }
  return classMap;
};
var processClassesRecursively = (classGroup, classPartObject, classGroupId, theme) => {
  const len = classGroup.length;
  for (let i = 0; i < len; i++) {
    const classDefinition = classGroup[i];
    processClassDefinition(classDefinition, classPartObject, classGroupId, theme);
  }
};
var processClassDefinition = (classDefinition, classPartObject, classGroupId, theme) => {
  if (typeof classDefinition === "string") {
    processStringDefinition(classDefinition, classPartObject, classGroupId);
    return;
  }
  if (typeof classDefinition === "function") {
    processFunctionDefinition(classDefinition, classPartObject, classGroupId, theme);
    return;
  }
  processObjectDefinition(classDefinition, classPartObject, classGroupId, theme);
};
var processStringDefinition = (classDefinition, classPartObject, classGroupId) => {
  const classPartObjectToEdit = classDefinition === "" ? classPartObject : getPart(classPartObject, classDefinition);
  classPartObjectToEdit.classGroupId = classGroupId;
};
var processFunctionDefinition = (classDefinition, classPartObject, classGroupId, theme) => {
  if (isThemeGetter(classDefinition)) {
    processClassesRecursively(classDefinition(theme), classPartObject, classGroupId, theme);
    return;
  }
  if (classPartObject.validators === null) {
    classPartObject.validators = [];
  }
  classPartObject.validators.push(createClassValidatorObject(classGroupId, classDefinition));
};
var processObjectDefinition = (classDefinition, classPartObject, classGroupId, theme) => {
  const entries = Object.entries(classDefinition);
  const len = entries.length;
  for (let i = 0; i < len; i++) {
    const [key, value] = entries[i];
    processClassesRecursively(value, getPart(classPartObject, key), classGroupId, theme);
  }
};
var getPart = (classPartObject, path) => {
  let current = classPartObject;
  const parts = path.split(CLASS_PART_SEPARATOR);
  const len = parts.length;
  for (let i = 0; i < len; i++) {
    const part = parts[i];
    let next = current.nextPart.get(part);
    if (!next) {
      next = createClassPartObject();
      current.nextPart.set(part, next);
    }
    current = next;
  }
  return current;
};
var isThemeGetter = (func) => "isThemeGetter" in func && func.isThemeGetter === true;
var createLruCache = (maxCacheSize) => {
  if (maxCacheSize < 1) {
    return {
      get: () => void 0,
      set: () => {
      }
    };
  }
  let cacheSize = 0;
  let cache2 = /* @__PURE__ */ Object.create(null);
  let previousCache = /* @__PURE__ */ Object.create(null);
  const update2 = (key, value) => {
    cache2[key] = value;
    cacheSize++;
    if (cacheSize > maxCacheSize) {
      cacheSize = 0;
      previousCache = cache2;
      cache2 = /* @__PURE__ */ Object.create(null);
    }
  };
  return {
    get(key) {
      let value = cache2[key];
      if (value !== void 0) {
        return value;
      }
      if ((value = previousCache[key]) !== void 0) {
        update2(key, value);
        return value;
      }
    },
    set(key, value) {
      if (key in cache2) {
        cache2[key] = value;
      } else {
        update2(key, value);
      }
    }
  };
};
var IMPORTANT_MODIFIER = "!";
var MODIFIER_SEPARATOR = ":";
var EMPTY_MODIFIERS = [];
var createResultObject = (modifiers, hasImportantModifier, baseClassName, maybePostfixModifierPosition, isExternal) => ({
  modifiers,
  hasImportantModifier,
  baseClassName,
  maybePostfixModifierPosition,
  isExternal
});
var createParseClassName = (config) => {
  const {
    prefix,
    experimentalParseClassName
  } = config;
  let parseClassName = (className) => {
    const modifiers = [];
    let bracketDepth = 0;
    let parenDepth = 0;
    let modifierStart = 0;
    let postfixModifierPosition;
    const len = className.length;
    for (let index = 0; index < len; index++) {
      const currentCharacter = className[index];
      if (bracketDepth === 0 && parenDepth === 0) {
        if (currentCharacter === MODIFIER_SEPARATOR) {
          modifiers.push(className.slice(modifierStart, index));
          modifierStart = index + 1;
          continue;
        }
        if (currentCharacter === "/") {
          postfixModifierPosition = index;
          continue;
        }
      }
      if (currentCharacter === "[") bracketDepth++;
      else if (currentCharacter === "]") bracketDepth--;
      else if (currentCharacter === "(") parenDepth++;
      else if (currentCharacter === ")") parenDepth--;
    }
    const baseClassNameWithImportantModifier = modifiers.length === 0 ? className : className.slice(modifierStart);
    let baseClassName = baseClassNameWithImportantModifier;
    let hasImportantModifier = false;
    if (baseClassNameWithImportantModifier.endsWith(IMPORTANT_MODIFIER)) {
      baseClassName = baseClassNameWithImportantModifier.slice(0, -1);
      hasImportantModifier = true;
    } else if (
      /**
       * In Tailwind CSS v3 the important modifier was at the start of the base class name. This is still supported for legacy reasons.
       * @see https://github.com/dcastil/tailwind-merge/issues/513#issuecomment-2614029864
       */
      baseClassNameWithImportantModifier.startsWith(IMPORTANT_MODIFIER)
    ) {
      baseClassName = baseClassNameWithImportantModifier.slice(1);
      hasImportantModifier = true;
    }
    const maybePostfixModifierPosition = postfixModifierPosition && postfixModifierPosition > modifierStart ? postfixModifierPosition - modifierStart : void 0;
    return createResultObject(modifiers, hasImportantModifier, baseClassName, maybePostfixModifierPosition);
  };
  if (prefix) {
    const fullPrefix = prefix + MODIFIER_SEPARATOR;
    const parseClassNameOriginal = parseClassName;
    parseClassName = (className) => className.startsWith(fullPrefix) ? parseClassNameOriginal(className.slice(fullPrefix.length)) : createResultObject(EMPTY_MODIFIERS, false, className, void 0, true);
  }
  if (experimentalParseClassName) {
    const parseClassNameOriginal = parseClassName;
    parseClassName = (className) => experimentalParseClassName({
      className,
      parseClassName: parseClassNameOriginal
    });
  }
  return parseClassName;
};
var createSortModifiers = (config) => {
  const modifierWeights = /* @__PURE__ */ new Map();
  config.orderSensitiveModifiers.forEach((mod, index) => {
    modifierWeights.set(mod, 1e6 + index);
  });
  return (modifiers) => {
    const result = [];
    let currentSegment = [];
    for (let i = 0; i < modifiers.length; i++) {
      const modifier = modifiers[i];
      const isArbitrary = modifier[0] === "[";
      const isOrderSensitive = modifierWeights.has(modifier);
      if (isArbitrary || isOrderSensitive) {
        if (currentSegment.length > 0) {
          currentSegment.sort();
          result.push(...currentSegment);
          currentSegment = [];
        }
        result.push(modifier);
      } else {
        currentSegment.push(modifier);
      }
    }
    if (currentSegment.length > 0) {
      currentSegment.sort();
      result.push(...currentSegment);
    }
    return result;
  };
};
var createConfigUtils = (config) => ({
  cache: createLruCache(config.cacheSize),
  parseClassName: createParseClassName(config),
  sortModifiers: createSortModifiers(config),
  postfixLookupClassGroupIds: createPostfixLookupClassGroupIds(config),
  ...createClassGroupUtils(config)
});
var createPostfixLookupClassGroupIds = (config) => {
  const lookup = /* @__PURE__ */ Object.create(null);
  const classGroupIds = config.postfixLookupClassGroups;
  if (classGroupIds) {
    for (let i = 0; i < classGroupIds.length; i++) {
      lookup[classGroupIds[i]] = true;
    }
  }
  return lookup;
};
var SPLIT_CLASSES_REGEX = /\s+/;
var mergeClassList = (classList, configUtils) => {
  const {
    parseClassName,
    getClassGroupId,
    getConflictingClassGroupIds,
    sortModifiers,
    postfixLookupClassGroupIds
  } = configUtils;
  const classGroupsInConflict = [];
  const classNames = classList.trim().split(SPLIT_CLASSES_REGEX);
  let result = "";
  for (let index = classNames.length - 1; index >= 0; index -= 1) {
    const originalClassName = classNames[index];
    const {
      isExternal,
      modifiers,
      hasImportantModifier,
      baseClassName,
      maybePostfixModifierPosition
    } = parseClassName(originalClassName);
    if (isExternal) {
      result = originalClassName + (result.length > 0 ? " " + result : result);
      continue;
    }
    let hasPostfixModifier = !!maybePostfixModifierPosition;
    let classGroupId;
    if (hasPostfixModifier) {
      const baseClassNameWithoutPostfix = baseClassName.substring(0, maybePostfixModifierPosition);
      classGroupId = getClassGroupId(baseClassNameWithoutPostfix);
      const classGroupIdWithPostfix = classGroupId && postfixLookupClassGroupIds[classGroupId] ? getClassGroupId(baseClassName) : void 0;
      if (classGroupIdWithPostfix && classGroupIdWithPostfix !== classGroupId) {
        classGroupId = classGroupIdWithPostfix;
        hasPostfixModifier = false;
      }
    } else {
      classGroupId = getClassGroupId(baseClassName);
    }
    if (!classGroupId) {
      if (!hasPostfixModifier) {
        result = originalClassName + (result.length > 0 ? " " + result : result);
        continue;
      }
      classGroupId = getClassGroupId(baseClassName);
      if (!classGroupId) {
        result = originalClassName + (result.length > 0 ? " " + result : result);
        continue;
      }
      hasPostfixModifier = false;
    }
    const variantModifier = modifiers.length === 0 ? "" : modifiers.length === 1 ? modifiers[0] : sortModifiers(modifiers).join(":");
    const modifierId = hasImportantModifier ? variantModifier + IMPORTANT_MODIFIER : variantModifier;
    const classId = modifierId + classGroupId;
    if (classGroupsInConflict.indexOf(classId) > -1) {
      continue;
    }
    classGroupsInConflict.push(classId);
    const conflictGroups = getConflictingClassGroupIds(classGroupId, hasPostfixModifier);
    for (let i = 0; i < conflictGroups.length; ++i) {
      const group = conflictGroups[i];
      classGroupsInConflict.push(modifierId + group);
    }
    result = originalClassName + (result.length > 0 ? " " + result : result);
  }
  return result;
};
var twJoin = (...classLists) => {
  let index = 0;
  let argument;
  let resolvedValue;
  let string = "";
  while (index < classLists.length) {
    if (argument = classLists[index++]) {
      if (resolvedValue = toValue(argument)) {
        string && (string += " ");
        string += resolvedValue;
      }
    }
  }
  return string;
};
var toValue = (mix) => {
  if (typeof mix === "string") {
    return mix;
  }
  let resolvedValue;
  let string = "";
  for (let k = 0; k < mix.length; k++) {
    if (mix[k]) {
      if (resolvedValue = toValue(mix[k])) {
        string && (string += " ");
        string += resolvedValue;
      }
    }
  }
  return string;
};
var createTailwindMerge = (createConfigFirst, ...createConfigRest) => {
  let configUtils;
  let cacheGet;
  let cacheSet;
  let functionToCall;
  const initTailwindMerge = (classList) => {
    const config = createConfigRest.reduce((previousConfig, createConfigCurrent) => createConfigCurrent(previousConfig), createConfigFirst());
    configUtils = createConfigUtils(config);
    cacheGet = configUtils.cache.get;
    cacheSet = configUtils.cache.set;
    functionToCall = tailwindMerge;
    return tailwindMerge(classList);
  };
  const tailwindMerge = (classList) => {
    const cachedResult = cacheGet(classList);
    if (cachedResult) {
      return cachedResult;
    }
    const result = mergeClassList(classList, configUtils);
    cacheSet(classList, result);
    return result;
  };
  functionToCall = initTailwindMerge;
  return (...args) => functionToCall(twJoin(...args));
};
var fallbackThemeArr = [];
var fromTheme = (key) => {
  const themeGetter = (theme) => theme[key] || fallbackThemeArr;
  themeGetter.isThemeGetter = true;
  return themeGetter;
};
var arbitraryValueRegex = /^\[(?:(\w[\w-]*):)?(.+)\]$/i;
var arbitraryVariableRegex = /^\((?:(\w[\w-]*):)?(.+)\)$/i;
var fractionRegex = /^\d+(?:\.\d+)?\/\d+(?:\.\d+)?$/;
var tshirtUnitRegex = /^(\d+(\.\d+)?)?(xs|sm|md|lg|xl)$/;
var lengthUnitRegex = /\d+(%|px|r?em|[sdl]?v([hwib]|min|max)|pt|pc|in|cm|mm|cap|ch|ex|r?lh|cq(w|h|i|b|min|max))|\b(calc|min|max|clamp)\(.+\)|^0$/;
var colorFunctionRegex = /^(rgba?|hsla?|hwb|(ok)?(lab|lch)|color-mix)\(.+\)$/;
var shadowRegex = /^(inset_)?-?((\d+)?\.?(\d+)[a-z]+|0)_-?((\d+)?\.?(\d+)[a-z]+|0)/;
var imageRegex = /^(url|image|image-set|cross-fade|element|(repeating-)?(linear|radial|conic)-gradient)\(.+\)$/;
var isFraction = (value) => fractionRegex.test(value);
var isNumber = (value) => !!value && !Number.isNaN(Number(value));
var isInteger = (value) => !!value && Number.isInteger(Number(value));
var isPercent = (value) => value.endsWith("%") && isNumber(value.slice(0, -1));
var isTshirtSize = (value) => tshirtUnitRegex.test(value);
var isAny = () => true;
var isLengthOnly = (value) => (
  // `colorFunctionRegex` check is necessary because color functions can have percentages in them which which would be incorrectly classified as lengths.
  // For example, `hsl(0 0% 0%)` would be classified as a length without this check.
  // I could also use lookbehind assertion in `lengthUnitRegex` but that isn't supported widely enough.
  lengthUnitRegex.test(value) && !colorFunctionRegex.test(value)
);
var isNever = () => false;
var isShadow = (value) => shadowRegex.test(value);
var isImage = (value) => imageRegex.test(value);
var isAnyNonArbitrary = (value) => !isArbitraryValue(value) && !isArbitraryVariable(value);
var isNamedContainerQuery = (value) => value.startsWith("@container") && (value[10] === "/" && value[11] !== void 0 || value[11] === "s" && value[16] !== void 0 && value.startsWith("-size/", 10) || value[11] === "n" && value[18] !== void 0 && value.startsWith("-normal/", 10));
var isArbitrarySize = (value) => getIsArbitraryValue(value, isLabelSize, isNever);
var isArbitraryValue = (value) => arbitraryValueRegex.test(value);
var isArbitraryLength = (value) => getIsArbitraryValue(value, isLabelLength, isLengthOnly);
var isArbitraryNumber = (value) => getIsArbitraryValue(value, isLabelNumber, isNumber);
var isArbitraryWeight = (value) => getIsArbitraryValue(value, isLabelWeight, isAny);
var isArbitraryFamilyName = (value) => getIsArbitraryValue(value, isLabelFamilyName, isNever);
var isArbitraryPosition = (value) => getIsArbitraryValue(value, isLabelPosition, isNever);
var isArbitraryImage = (value) => getIsArbitraryValue(value, isLabelImage, isImage);
var isArbitraryShadow = (value) => getIsArbitraryValue(value, isLabelShadow, isShadow);
var isArbitraryVariable = (value) => arbitraryVariableRegex.test(value);
var isArbitraryVariableLength = (value) => getIsArbitraryVariable(value, isLabelLength);
var isArbitraryVariableFamilyName = (value) => getIsArbitraryVariable(value, isLabelFamilyName);
var isArbitraryVariablePosition = (value) => getIsArbitraryVariable(value, isLabelPosition);
var isArbitraryVariableSize = (value) => getIsArbitraryVariable(value, isLabelSize);
var isArbitraryVariableImage = (value) => getIsArbitraryVariable(value, isLabelImage);
var isArbitraryVariableShadow = (value) => getIsArbitraryVariable(value, isLabelShadow, true);
var isArbitraryVariableWeight = (value) => getIsArbitraryVariable(value, isLabelWeight, true);
var getIsArbitraryValue = (value, testLabel, testValue) => {
  const result = arbitraryValueRegex.exec(value);
  if (result) {
    if (result[1]) {
      return testLabel(result[1]);
    }
    return testValue(result[2]);
  }
  return false;
};
var getIsArbitraryVariable = (value, testLabel, shouldMatchNoLabel = false) => {
  const result = arbitraryVariableRegex.exec(value);
  if (result) {
    if (result[1]) {
      return testLabel(result[1]);
    }
    return shouldMatchNoLabel;
  }
  return false;
};
var isLabelPosition = (label) => label === "position" || label === "percentage";
var isLabelImage = (label) => label === "image" || label === "url";
var isLabelSize = (label) => label === "length" || label === "size" || label === "bg-size";
var isLabelLength = (label) => label === "length";
var isLabelNumber = (label) => label === "number";
var isLabelFamilyName = (label) => label === "family-name";
var isLabelWeight = (label) => label === "number" || label === "weight";
var isLabelShadow = (label) => label === "shadow";
var getDefaultConfig = () => {
  const themeColor = fromTheme("color");
  const themeFont = fromTheme("font");
  const themeText = fromTheme("text");
  const themeFontWeight = fromTheme("font-weight");
  const themeTracking = fromTheme("tracking");
  const themeLeading = fromTheme("leading");
  const themeBreakpoint = fromTheme("breakpoint");
  const themeContainer = fromTheme("container");
  const themeSpacing = fromTheme("spacing");
  const themeRadius = fromTheme("radius");
  const themeShadow = fromTheme("shadow");
  const themeInsetShadow = fromTheme("inset-shadow");
  const themeTextShadow = fromTheme("text-shadow");
  const themeDropShadow = fromTheme("drop-shadow");
  const themeBlur = fromTheme("blur");
  const themePerspective = fromTheme("perspective");
  const themeAspect = fromTheme("aspect");
  const themeEase = fromTheme("ease");
  const themeAnimate = fromTheme("animate");
  const scaleBreak = () => ["auto", "avoid", "all", "avoid-page", "page", "left", "right", "column"];
  const scalePosition = () => [
    "center",
    "top",
    "bottom",
    "left",
    "right",
    "top-left",
    // Deprecated since Tailwind CSS v4.1.0, see https://github.com/tailwindlabs/tailwindcss/pull/17378
    "left-top",
    "top-right",
    // Deprecated since Tailwind CSS v4.1.0, see https://github.com/tailwindlabs/tailwindcss/pull/17378
    "right-top",
    "bottom-right",
    // Deprecated since Tailwind CSS v4.1.0, see https://github.com/tailwindlabs/tailwindcss/pull/17378
    "right-bottom",
    "bottom-left",
    // Deprecated since Tailwind CSS v4.1.0, see https://github.com/tailwindlabs/tailwindcss/pull/17378
    "left-bottom"
  ];
  const scalePositionWithArbitrary = () => [...scalePosition(), isArbitraryVariable, isArbitraryValue];
  const scaleOverflow = () => ["auto", "hidden", "clip", "visible", "scroll"];
  const scaleOverscroll = () => ["auto", "contain", "none"];
  const scaleUnambiguousSpacing = () => [isArbitraryVariable, isArbitraryValue, themeSpacing];
  const scaleInset = () => [isFraction, "full", "auto", ...scaleUnambiguousSpacing()];
  const scaleGridTemplateColsRows = () => [isInteger, "none", "subgrid", isArbitraryVariable, isArbitraryValue];
  const scaleGridColRowStartAndEnd = () => ["auto", {
    span: ["full", isInteger, isArbitraryVariable, isArbitraryValue]
  }, isInteger, isArbitraryVariable, isArbitraryValue];
  const scaleGridColRowStartOrEnd = () => [isInteger, "auto", isArbitraryVariable, isArbitraryValue];
  const scaleGridAutoColsRows = () => ["auto", "min", "max", "fr", isArbitraryVariable, isArbitraryValue];
  const scaleAlignPrimaryAxis = () => ["start", "end", "center", "between", "around", "evenly", "stretch", "baseline", "center-safe", "end-safe"];
  const scaleAlignSecondaryAxis = () => ["start", "end", "center", "stretch", "center-safe", "end-safe"];
  const scaleMargin = () => ["auto", ...scaleUnambiguousSpacing()];
  const scaleSizing = () => [isFraction, "auto", "full", "dvw", "dvh", "lvw", "lvh", "svw", "svh", "min", "max", "fit", ...scaleUnambiguousSpacing()];
  const scaleSizingInline = () => [isFraction, "screen", "full", "dvw", "lvw", "svw", "min", "max", "fit", ...scaleUnambiguousSpacing()];
  const scaleSizingBlock = () => [isFraction, "screen", "full", "lh", "dvh", "lvh", "svh", "min", "max", "fit", ...scaleUnambiguousSpacing()];
  const scaleColor = () => [themeColor, isArbitraryVariable, isArbitraryValue];
  const scaleBgPosition = () => [...scalePosition(), isArbitraryVariablePosition, isArbitraryPosition, {
    position: [isArbitraryVariable, isArbitraryValue]
  }];
  const scaleBgRepeat = () => ["no-repeat", {
    repeat: ["", "x", "y", "space", "round"]
  }];
  const scaleBgSize = () => ["auto", "cover", "contain", isArbitraryVariableSize, isArbitrarySize, {
    size: [isArbitraryVariable, isArbitraryValue]
  }];
  const scaleGradientStopPosition = () => [isPercent, isArbitraryVariableLength, isArbitraryLength];
  const scaleRadius = () => [
    // Deprecated since Tailwind CSS v4.0.0
    "",
    "none",
    "full",
    themeRadius,
    isArbitraryVariable,
    isArbitraryValue
  ];
  const scaleBorderWidth = () => ["", isNumber, isArbitraryVariableLength, isArbitraryLength];
  const scaleLineStyle = () => ["solid", "dashed", "dotted", "double"];
  const scaleBlendMode = () => ["normal", "multiply", "screen", "overlay", "darken", "lighten", "color-dodge", "color-burn", "hard-light", "soft-light", "difference", "exclusion", "hue", "saturation", "color", "luminosity"];
  const scaleMaskImagePosition = () => [isNumber, isPercent, isArbitraryVariablePosition, isArbitraryPosition];
  const scaleBlur = () => [
    // Deprecated since Tailwind CSS v4.0.0
    "",
    "none",
    themeBlur,
    isArbitraryVariable,
    isArbitraryValue
  ];
  const scaleRotate = () => ["none", isNumber, isArbitraryVariable, isArbitraryValue];
  const scaleScale = () => ["none", isNumber, isArbitraryVariable, isArbitraryValue];
  const scaleSkew = () => [isNumber, isArbitraryVariable, isArbitraryValue];
  const scaleTranslate = () => [isFraction, "full", ...scaleUnambiguousSpacing()];
  return {
    cacheSize: 500,
    theme: {
      animate: ["spin", "ping", "pulse", "bounce"],
      aspect: ["video"],
      blur: [isTshirtSize],
      breakpoint: [isTshirtSize],
      color: [isAny],
      container: [isTshirtSize],
      "drop-shadow": [isTshirtSize],
      ease: ["in", "out", "in-out"],
      font: [isAnyNonArbitrary],
      "font-weight": ["thin", "extralight", "light", "normal", "medium", "semibold", "bold", "extrabold", "black"],
      "inset-shadow": [isTshirtSize],
      leading: ["none", "tight", "snug", "normal", "relaxed", "loose"],
      perspective: ["dramatic", "near", "normal", "midrange", "distant", "none"],
      radius: [isTshirtSize],
      shadow: [isTshirtSize],
      spacing: ["px", isNumber],
      text: [isTshirtSize],
      "text-shadow": [isTshirtSize],
      tracking: ["tighter", "tight", "normal", "wide", "wider", "widest"]
    },
    classGroups: {
      // --------------
      // --- Layout ---
      // --------------
      /**
       * Aspect Ratio
       * @see https://tailwindcss.com/docs/aspect-ratio
       */
      aspect: [{
        aspect: ["auto", "square", isFraction, isArbitraryValue, isArbitraryVariable, themeAspect]
      }],
      /**
       * Container
       * @see https://tailwindcss.com/docs/container
       * @deprecated since Tailwind CSS v4.0.0
       */
      container: ["container"],
      /**
       * Container Type
       * @see https://tailwindcss.com/docs/responsive-design#container-queries
       */
      "container-type": [{
        "@container": ["", "normal", "size", isArbitraryVariable, isArbitraryValue]
      }],
      /**
       * Container Name
       * @see https://tailwindcss.com/docs/responsive-design#named-containers
       */
      "container-named": [isNamedContainerQuery],
      /**
       * Columns
       * @see https://tailwindcss.com/docs/columns
       */
      columns: [{
        columns: [isNumber, isArbitraryValue, isArbitraryVariable, themeContainer]
      }],
      /**
       * Break After
       * @see https://tailwindcss.com/docs/break-after
       */
      "break-after": [{
        "break-after": scaleBreak()
      }],
      /**
       * Break Before
       * @see https://tailwindcss.com/docs/break-before
       */
      "break-before": [{
        "break-before": scaleBreak()
      }],
      /**
       * Break Inside
       * @see https://tailwindcss.com/docs/break-inside
       */
      "break-inside": [{
        "break-inside": ["auto", "avoid", "avoid-page", "avoid-column"]
      }],
      /**
       * Box Decoration Break
       * @see https://tailwindcss.com/docs/box-decoration-break
       */
      "box-decoration": [{
        "box-decoration": ["slice", "clone"]
      }],
      /**
       * Box Sizing
       * @see https://tailwindcss.com/docs/box-sizing
       */
      box: [{
        box: ["border", "content"]
      }],
      /**
       * Display
       * @see https://tailwindcss.com/docs/display
       */
      display: ["block", "inline-block", "inline", "flex", "inline-flex", "table", "inline-table", "table-caption", "table-cell", "table-column", "table-column-group", "table-footer-group", "table-header-group", "table-row-group", "table-row", "flow-root", "grid", "inline-grid", "contents", "list-item", "hidden"],
      /**
       * Screen Reader Only
       * @see https://tailwindcss.com/docs/display#screen-reader-only
       */
      sr: ["sr-only", "not-sr-only"],
      /**
       * Floats
       * @see https://tailwindcss.com/docs/float
       */
      float: [{
        float: ["right", "left", "none", "start", "end"]
      }],
      /**
       * Clear
       * @see https://tailwindcss.com/docs/clear
       */
      clear: [{
        clear: ["left", "right", "both", "none", "start", "end"]
      }],
      /**
       * Isolation
       * @see https://tailwindcss.com/docs/isolation
       */
      isolation: ["isolate", "isolation-auto"],
      /**
       * Object Fit
       * @see https://tailwindcss.com/docs/object-fit
       */
      "object-fit": [{
        object: ["contain", "cover", "fill", "none", "scale-down"]
      }],
      /**
       * Object Position
       * @see https://tailwindcss.com/docs/object-position
       */
      "object-position": [{
        object: scalePositionWithArbitrary()
      }],
      /**
       * Overflow
       * @see https://tailwindcss.com/docs/overflow
       */
      overflow: [{
        overflow: scaleOverflow()
      }],
      /**
       * Overflow X
       * @see https://tailwindcss.com/docs/overflow
       */
      "overflow-x": [{
        "overflow-x": scaleOverflow()
      }],
      /**
       * Overflow Y
       * @see https://tailwindcss.com/docs/overflow
       */
      "overflow-y": [{
        "overflow-y": scaleOverflow()
      }],
      /**
       * Overscroll Behavior
       * @see https://tailwindcss.com/docs/overscroll-behavior
       */
      overscroll: [{
        overscroll: scaleOverscroll()
      }],
      /**
       * Overscroll Behavior X
       * @see https://tailwindcss.com/docs/overscroll-behavior
       */
      "overscroll-x": [{
        "overscroll-x": scaleOverscroll()
      }],
      /**
       * Overscroll Behavior Y
       * @see https://tailwindcss.com/docs/overscroll-behavior
       */
      "overscroll-y": [{
        "overscroll-y": scaleOverscroll()
      }],
      /**
       * Position
       * @see https://tailwindcss.com/docs/position
       */
      position: ["static", "fixed", "absolute", "relative", "sticky"],
      /**
       * Inset
       * @see https://tailwindcss.com/docs/top-right-bottom-left
       */
      inset: [{
        inset: scaleInset()
      }],
      /**
       * Inset Inline
       * @see https://tailwindcss.com/docs/top-right-bottom-left
       */
      "inset-x": [{
        "inset-x": scaleInset()
      }],
      /**
       * Inset Block
       * @see https://tailwindcss.com/docs/top-right-bottom-left
       */
      "inset-y": [{
        "inset-y": scaleInset()
      }],
      /**
       * Inset Inline Start
       * @see https://tailwindcss.com/docs/top-right-bottom-left
       * @todo class group will be renamed to `inset-s` in next major release
       */
      start: [{
        "inset-s": scaleInset(),
        /**
         * @deprecated since Tailwind CSS v4.2.0 in favor of `inset-s-*` utilities.
         * @see https://github.com/tailwindlabs/tailwindcss/pull/19613
         */
        start: scaleInset()
      }],
      /**
       * Inset Inline End
       * @see https://tailwindcss.com/docs/top-right-bottom-left
       * @todo class group will be renamed to `inset-e` in next major release
       */
      end: [{
        "inset-e": scaleInset(),
        /**
         * @deprecated since Tailwind CSS v4.2.0 in favor of `inset-e-*` utilities.
         * @see https://github.com/tailwindlabs/tailwindcss/pull/19613
         */
        end: scaleInset()
      }],
      /**
       * Inset Block Start
       * @see https://tailwindcss.com/docs/top-right-bottom-left
       */
      "inset-bs": [{
        "inset-bs": scaleInset()
      }],
      /**
       * Inset Block End
       * @see https://tailwindcss.com/docs/top-right-bottom-left
       */
      "inset-be": [{
        "inset-be": scaleInset()
      }],
      /**
       * Top
       * @see https://tailwindcss.com/docs/top-right-bottom-left
       */
      top: [{
        top: scaleInset()
      }],
      /**
       * Right
       * @see https://tailwindcss.com/docs/top-right-bottom-left
       */
      right: [{
        right: scaleInset()
      }],
      /**
       * Bottom
       * @see https://tailwindcss.com/docs/top-right-bottom-left
       */
      bottom: [{
        bottom: scaleInset()
      }],
      /**
       * Left
       * @see https://tailwindcss.com/docs/top-right-bottom-left
       */
      left: [{
        left: scaleInset()
      }],
      /**
       * Visibility
       * @see https://tailwindcss.com/docs/visibility
       */
      visibility: ["visible", "invisible", "collapse"],
      /**
       * Z-Index
       * @see https://tailwindcss.com/docs/z-index
       */
      z: [{
        z: [isInteger, "auto", isArbitraryVariable, isArbitraryValue]
      }],
      // ------------------------
      // --- Flexbox and Grid ---
      // ------------------------
      /**
       * Flex Basis
       * @see https://tailwindcss.com/docs/flex-basis
       */
      basis: [{
        basis: [isFraction, "full", "auto", themeContainer, ...scaleUnambiguousSpacing()]
      }],
      /**
       * Flex Direction
       * @see https://tailwindcss.com/docs/flex-direction
       */
      "flex-direction": [{
        flex: ["row", "row-reverse", "col", "col-reverse"]
      }],
      /**
       * Flex Wrap
       * @see https://tailwindcss.com/docs/flex-wrap
       */
      "flex-wrap": [{
        flex: ["nowrap", "wrap", "wrap-reverse"]
      }],
      /**
       * Flex
       * @see https://tailwindcss.com/docs/flex
       */
      flex: [{
        flex: [isNumber, isFraction, "auto", "initial", "none", isArbitraryValue]
      }],
      /**
       * Flex Grow
       * @see https://tailwindcss.com/docs/flex-grow
       */
      grow: [{
        grow: ["", isNumber, isArbitraryVariable, isArbitraryValue]
      }],
      /**
       * Flex Shrink
       * @see https://tailwindcss.com/docs/flex-shrink
       */
      shrink: [{
        shrink: ["", isNumber, isArbitraryVariable, isArbitraryValue]
      }],
      /**
       * Order
       * @see https://tailwindcss.com/docs/order
       */
      order: [{
        order: [isInteger, "first", "last", "none", isArbitraryVariable, isArbitraryValue]
      }],
      /**
       * Grid Template Columns
       * @see https://tailwindcss.com/docs/grid-template-columns
       */
      "grid-cols": [{
        "grid-cols": scaleGridTemplateColsRows()
      }],
      /**
       * Grid Column Start / End
       * @see https://tailwindcss.com/docs/grid-column
       */
      "col-start-end": [{
        col: scaleGridColRowStartAndEnd()
      }],
      /**
       * Grid Column Start
       * @see https://tailwindcss.com/docs/grid-column
       */
      "col-start": [{
        "col-start": scaleGridColRowStartOrEnd()
      }],
      /**
       * Grid Column End
       * @see https://tailwindcss.com/docs/grid-column
       */
      "col-end": [{
        "col-end": scaleGridColRowStartOrEnd()
      }],
      /**
       * Grid Template Rows
       * @see https://tailwindcss.com/docs/grid-template-rows
       */
      "grid-rows": [{
        "grid-rows": scaleGridTemplateColsRows()
      }],
      /**
       * Grid Row Start / End
       * @see https://tailwindcss.com/docs/grid-row
       */
      "row-start-end": [{
        row: scaleGridColRowStartAndEnd()
      }],
      /**
       * Grid Row Start
       * @see https://tailwindcss.com/docs/grid-row
       */
      "row-start": [{
        "row-start": scaleGridColRowStartOrEnd()
      }],
      /**
       * Grid Row End
       * @see https://tailwindcss.com/docs/grid-row
       */
      "row-end": [{
        "row-end": scaleGridColRowStartOrEnd()
      }],
      /**
       * Grid Auto Flow
       * @see https://tailwindcss.com/docs/grid-auto-flow
       */
      "grid-flow": [{
        "grid-flow": ["row", "col", "dense", "row-dense", "col-dense"]
      }],
      /**
       * Grid Auto Columns
       * @see https://tailwindcss.com/docs/grid-auto-columns
       */
      "auto-cols": [{
        "auto-cols": scaleGridAutoColsRows()
      }],
      /**
       * Grid Auto Rows
       * @see https://tailwindcss.com/docs/grid-auto-rows
       */
      "auto-rows": [{
        "auto-rows": scaleGridAutoColsRows()
      }],
      /**
       * Gap
       * @see https://tailwindcss.com/docs/gap
       */
      gap: [{
        gap: scaleUnambiguousSpacing()
      }],
      /**
       * Gap X
       * @see https://tailwindcss.com/docs/gap
       */
      "gap-x": [{
        "gap-x": scaleUnambiguousSpacing()
      }],
      /**
       * Gap Y
       * @see https://tailwindcss.com/docs/gap
       */
      "gap-y": [{
        "gap-y": scaleUnambiguousSpacing()
      }],
      /**
       * Justify Content
       * @see https://tailwindcss.com/docs/justify-content
       */
      "justify-content": [{
        justify: [...scaleAlignPrimaryAxis(), "normal"]
      }],
      /**
       * Justify Items
       * @see https://tailwindcss.com/docs/justify-items
       */
      "justify-items": [{
        "justify-items": [...scaleAlignSecondaryAxis(), "normal"]
      }],
      /**
       * Justify Self
       * @see https://tailwindcss.com/docs/justify-self
       */
      "justify-self": [{
        "justify-self": ["auto", ...scaleAlignSecondaryAxis()]
      }],
      /**
       * Align Content
       * @see https://tailwindcss.com/docs/align-content
       */
      "align-content": [{
        content: ["normal", ...scaleAlignPrimaryAxis()]
      }],
      /**
       * Align Items
       * @see https://tailwindcss.com/docs/align-items
       */
      "align-items": [{
        items: [...scaleAlignSecondaryAxis(), {
          baseline: ["", "last"]
        }]
      }],
      /**
       * Align Self
       * @see https://tailwindcss.com/docs/align-self
       */
      "align-self": [{
        self: ["auto", ...scaleAlignSecondaryAxis(), {
          baseline: ["", "last"]
        }]
      }],
      /**
       * Place Content
       * @see https://tailwindcss.com/docs/place-content
       */
      "place-content": [{
        "place-content": scaleAlignPrimaryAxis()
      }],
      /**
       * Place Items
       * @see https://tailwindcss.com/docs/place-items
       */
      "place-items": [{
        "place-items": [...scaleAlignSecondaryAxis(), "baseline"]
      }],
      /**
       * Place Self
       * @see https://tailwindcss.com/docs/place-self
       */
      "place-self": [{
        "place-self": ["auto", ...scaleAlignSecondaryAxis()]
      }],
      // Spacing
      /**
       * Padding
       * @see https://tailwindcss.com/docs/padding
       */
      p: [{
        p: scaleUnambiguousSpacing()
      }],
      /**
       * Padding Inline
       * @see https://tailwindcss.com/docs/padding
       */
      px: [{
        px: scaleUnambiguousSpacing()
      }],
      /**
       * Padding Block
       * @see https://tailwindcss.com/docs/padding
       */
      py: [{
        py: scaleUnambiguousSpacing()
      }],
      /**
       * Padding Inline Start
       * @see https://tailwindcss.com/docs/padding
       */
      ps: [{
        ps: scaleUnambiguousSpacing()
      }],
      /**
       * Padding Inline End
       * @see https://tailwindcss.com/docs/padding
       */
      pe: [{
        pe: scaleUnambiguousSpacing()
      }],
      /**
       * Padding Block Start
       * @see https://tailwindcss.com/docs/padding
       */
      pbs: [{
        pbs: scaleUnambiguousSpacing()
      }],
      /**
       * Padding Block End
       * @see https://tailwindcss.com/docs/padding
       */
      pbe: [{
        pbe: scaleUnambiguousSpacing()
      }],
      /**
       * Padding Top
       * @see https://tailwindcss.com/docs/padding
       */
      pt: [{
        pt: scaleUnambiguousSpacing()
      }],
      /**
       * Padding Right
       * @see https://tailwindcss.com/docs/padding
       */
      pr: [{
        pr: scaleUnambiguousSpacing()
      }],
      /**
       * Padding Bottom
       * @see https://tailwindcss.com/docs/padding
       */
      pb: [{
        pb: scaleUnambiguousSpacing()
      }],
      /**
       * Padding Left
       * @see https://tailwindcss.com/docs/padding
       */
      pl: [{
        pl: scaleUnambiguousSpacing()
      }],
      /**
       * Margin
       * @see https://tailwindcss.com/docs/margin
       */
      m: [{
        m: scaleMargin()
      }],
      /**
       * Margin Inline
       * @see https://tailwindcss.com/docs/margin
       */
      mx: [{
        mx: scaleMargin()
      }],
      /**
       * Margin Block
       * @see https://tailwindcss.com/docs/margin
       */
      my: [{
        my: scaleMargin()
      }],
      /**
       * Margin Inline Start
       * @see https://tailwindcss.com/docs/margin
       */
      ms: [{
        ms: scaleMargin()
      }],
      /**
       * Margin Inline End
       * @see https://tailwindcss.com/docs/margin
       */
      me: [{
        me: scaleMargin()
      }],
      /**
       * Margin Block Start
       * @see https://tailwindcss.com/docs/margin
       */
      mbs: [{
        mbs: scaleMargin()
      }],
      /**
       * Margin Block End
       * @see https://tailwindcss.com/docs/margin
       */
      mbe: [{
        mbe: scaleMargin()
      }],
      /**
       * Margin Top
       * @see https://tailwindcss.com/docs/margin
       */
      mt: [{
        mt: scaleMargin()
      }],
      /**
       * Margin Right
       * @see https://tailwindcss.com/docs/margin
       */
      mr: [{
        mr: scaleMargin()
      }],
      /**
       * Margin Bottom
       * @see https://tailwindcss.com/docs/margin
       */
      mb: [{
        mb: scaleMargin()
      }],
      /**
       * Margin Left
       * @see https://tailwindcss.com/docs/margin
       */
      ml: [{
        ml: scaleMargin()
      }],
      /**
       * Space Between X
       * @see https://tailwindcss.com/docs/margin#adding-space-between-children
       */
      "space-x": [{
        "space-x": scaleUnambiguousSpacing()
      }],
      /**
       * Space Between X Reverse
       * @see https://tailwindcss.com/docs/margin#adding-space-between-children
       */
      "space-x-reverse": ["space-x-reverse"],
      /**
       * Space Between Y
       * @see https://tailwindcss.com/docs/margin#adding-space-between-children
       */
      "space-y": [{
        "space-y": scaleUnambiguousSpacing()
      }],
      /**
       * Space Between Y Reverse
       * @see https://tailwindcss.com/docs/margin#adding-space-between-children
       */
      "space-y-reverse": ["space-y-reverse"],
      // --------------
      // --- Sizing ---
      // --------------
      /**
       * Size
       * @see https://tailwindcss.com/docs/width#setting-both-width-and-height
       */
      size: [{
        size: scaleSizing()
      }],
      /**
       * Inline Size
       * @see https://tailwindcss.com/docs/width
       */
      "inline-size": [{
        inline: ["auto", ...scaleSizingInline()]
      }],
      /**
       * Min-Inline Size
       * @see https://tailwindcss.com/docs/min-width
       */
      "min-inline-size": [{
        "min-inline": ["auto", ...scaleSizingInline()]
      }],
      /**
       * Max-Inline Size
       * @see https://tailwindcss.com/docs/max-width
       */
      "max-inline-size": [{
        "max-inline": ["none", ...scaleSizingInline()]
      }],
      /**
       * Block Size
       * @see https://tailwindcss.com/docs/height
       */
      "block-size": [{
        block: ["auto", ...scaleSizingBlock()]
      }],
      /**
       * Min-Block Size
       * @see https://tailwindcss.com/docs/min-height
       */
      "min-block-size": [{
        "min-block": ["auto", ...scaleSizingBlock()]
      }],
      /**
       * Max-Block Size
       * @see https://tailwindcss.com/docs/max-height
       */
      "max-block-size": [{
        "max-block": ["none", ...scaleSizingBlock()]
      }],
      /**
       * Width
       * @see https://tailwindcss.com/docs/width
       */
      w: [{
        w: [themeContainer, "screen", ...scaleSizing()]
      }],
      /**
       * Min-Width
       * @see https://tailwindcss.com/docs/min-width
       */
      "min-w": [{
        "min-w": [
          themeContainer,
          "screen",
          /** Deprecated. @see https://github.com/tailwindlabs/tailwindcss.com/issues/2027#issuecomment-2620152757 */
          "none",
          ...scaleSizing()
        ]
      }],
      /**
       * Max-Width
       * @see https://tailwindcss.com/docs/max-width
       */
      "max-w": [{
        "max-w": [
          themeContainer,
          "screen",
          "none",
          /** Deprecated since Tailwind CSS v4.0.0. @see https://github.com/tailwindlabs/tailwindcss.com/issues/2027#issuecomment-2620152757 */
          "prose",
          /** Deprecated since Tailwind CSS v4.0.0. @see https://github.com/tailwindlabs/tailwindcss.com/issues/2027#issuecomment-2620152757 */
          {
            screen: [themeBreakpoint]
          },
          ...scaleSizing()
        ]
      }],
      /**
       * Height
       * @see https://tailwindcss.com/docs/height
       */
      h: [{
        h: ["screen", "lh", ...scaleSizing()]
      }],
      /**
       * Min-Height
       * @see https://tailwindcss.com/docs/min-height
       */
      "min-h": [{
        "min-h": ["screen", "lh", "none", ...scaleSizing()]
      }],
      /**
       * Max-Height
       * @see https://tailwindcss.com/docs/max-height
       */
      "max-h": [{
        "max-h": ["screen", "lh", ...scaleSizing()]
      }],
      // ------------------
      // --- Typography ---
      // ------------------
      /**
       * Font Size
       * @see https://tailwindcss.com/docs/font-size
       */
      "font-size": [{
        text: ["base", themeText, isArbitraryVariableLength, isArbitraryLength]
      }],
      /**
       * Font Smoothing
       * @see https://tailwindcss.com/docs/font-smoothing
       */
      "font-smoothing": ["antialiased", "subpixel-antialiased"],
      /**
       * Font Style
       * @see https://tailwindcss.com/docs/font-style
       */
      "font-style": ["italic", "not-italic"],
      /**
       * Font Weight
       * @see https://tailwindcss.com/docs/font-weight
       */
      "font-weight": [{
        font: [themeFontWeight, isArbitraryVariableWeight, isArbitraryWeight]
      }],
      /**
       * Font Stretch
       * @see https://tailwindcss.com/docs/font-stretch
       */
      "font-stretch": [{
        "font-stretch": ["ultra-condensed", "extra-condensed", "condensed", "semi-condensed", "normal", "semi-expanded", "expanded", "extra-expanded", "ultra-expanded", isPercent, isArbitraryValue]
      }],
      /**
       * Font Family
       * @see https://tailwindcss.com/docs/font-family
       */
      "font-family": [{
        font: [isArbitraryVariableFamilyName, isArbitraryFamilyName, themeFont]
      }],
      /**
       * Font Feature Settings
       * @see https://tailwindcss.com/docs/font-feature-settings
       */
      "font-features": [{
        "font-features": [isArbitraryValue]
      }],
      /**
       * Font Variant Numeric
       * @see https://tailwindcss.com/docs/font-variant-numeric
       */
      "fvn-normal": ["normal-nums"],
      /**
       * Font Variant Numeric
       * @see https://tailwindcss.com/docs/font-variant-numeric
       */
      "fvn-ordinal": ["ordinal"],
      /**
       * Font Variant Numeric
       * @see https://tailwindcss.com/docs/font-variant-numeric
       */
      "fvn-slashed-zero": ["slashed-zero"],
      /**
       * Font Variant Numeric
       * @see https://tailwindcss.com/docs/font-variant-numeric
       */
      "fvn-figure": ["lining-nums", "oldstyle-nums"],
      /**
       * Font Variant Numeric
       * @see https://tailwindcss.com/docs/font-variant-numeric
       */
      "fvn-spacing": ["proportional-nums", "tabular-nums"],
      /**
       * Font Variant Numeric
       * @see https://tailwindcss.com/docs/font-variant-numeric
       */
      "fvn-fraction": ["diagonal-fractions", "stacked-fractions"],
      /**
       * Letter Spacing
       * @see https://tailwindcss.com/docs/letter-spacing
       */
      tracking: [{
        tracking: [themeTracking, isArbitraryVariable, isArbitraryValue]
      }],
      /**
       * Line Clamp
       * @see https://tailwindcss.com/docs/line-clamp
       */
      "line-clamp": [{
        "line-clamp": [isNumber, "none", isArbitraryVariable, isArbitraryNumber]
      }],
      /**
       * Line Height
       * @see https://tailwindcss.com/docs/line-height
       */
      leading: [{
        leading: [
          /** Deprecated since Tailwind CSS v4.0.0. @see https://github.com/tailwindlabs/tailwindcss.com/issues/2027#issuecomment-2620152757 */
          themeLeading,
          ...scaleUnambiguousSpacing()
        ]
      }],
      /**
       * List Style Image
       * @see https://tailwindcss.com/docs/list-style-image
       */
      "list-image": [{
        "list-image": ["none", isArbitraryVariable, isArbitraryValue]
      }],
      /**
       * List Style Position
       * @see https://tailwindcss.com/docs/list-style-position
       */
      "list-style-position": [{
        list: ["inside", "outside"]
      }],
      /**
       * List Style Type
       * @see https://tailwindcss.com/docs/list-style-type
       */
      "list-style-type": [{
        list: ["disc", "decimal", "none", isArbitraryVariable, isArbitraryValue]
      }],
      /**
       * Text Alignment
       * @see https://tailwindcss.com/docs/text-align
       */
      "text-alignment": [{
        text: ["left", "center", "right", "justify", "start", "end"]
      }],
      /**
       * Placeholder Color
       * @deprecated since Tailwind CSS v3.0.0
       * @see https://v3.tailwindcss.com/docs/placeholder-color
       */
      "placeholder-color": [{
        placeholder: scaleColor()
      }],
      /**
       * Text Color
       * @see https://tailwindcss.com/docs/text-color
       */
      "text-color": [{
        text: scaleColor()
      }],
      /**
       * Text Decoration
       * @see https://tailwindcss.com/docs/text-decoration
       */
      "text-decoration": ["underline", "overline", "line-through", "no-underline"],
      /**
       * Text Decoration Style
       * @see https://tailwindcss.com/docs/text-decoration-style
       */
      "text-decoration-style": [{
        decoration: [...scaleLineStyle(), "wavy"]
      }],
      /**
       * Text Decoration Thickness
       * @see https://tailwindcss.com/docs/text-decoration-thickness
       */
      "text-decoration-thickness": [{
        decoration: [isNumber, "from-font", "auto", isArbitraryVariable, isArbitraryLength]
      }],
      /**
       * Text Decoration Color
       * @see https://tailwindcss.com/docs/text-decoration-color
       */
      "text-decoration-color": [{
        decoration: scaleColor()
      }],
      /**
       * Text Underline Offset
       * @see https://tailwindcss.com/docs/text-underline-offset
       */
      "underline-offset": [{
        "underline-offset": [isNumber, "auto", isArbitraryVariable, isArbitraryValue]
      }],
      /**
       * Text Transform
       * @see https://tailwindcss.com/docs/text-transform
       */
      "text-transform": ["uppercase", "lowercase", "capitalize", "normal-case"],
      /**
       * Text Overflow
       * @see https://tailwindcss.com/docs/text-overflow
       */
      "text-overflow": ["truncate", "text-ellipsis", "text-clip"],
      /**
       * Text Wrap
       * @see https://tailwindcss.com/docs/text-wrap
       */
      "text-wrap": [{
        text: ["wrap", "nowrap", "balance", "pretty"]
      }],
      /**
       * Text Indent
       * @see https://tailwindcss.com/docs/text-indent
       */
      indent: [{
        indent: scaleUnambiguousSpacing()
      }],
      /**
       * Tab Size
       * @see https://tailwindcss.com/docs/tab-size
       */
      "tab-size": [{
        tab: [isInteger, isArbitraryVariable, isArbitraryValue]
      }],
      /**
       * Vertical Alignment
       * @see https://tailwindcss.com/docs/vertical-align
       */
      "vertical-align": [{
        align: ["baseline", "top", "middle", "bottom", "text-top", "text-bottom", "sub", "super", isArbitraryVariable, isArbitraryValue]
      }],
      /**
       * Whitespace
       * @see https://tailwindcss.com/docs/whitespace
       */
      whitespace: [{
        whitespace: ["normal", "nowrap", "pre", "pre-line", "pre-wrap", "break-spaces"]
      }],
      /**
       * Word Break
       * @see https://tailwindcss.com/docs/word-break
       */
      break: [{
        break: ["normal", "words", "all", "keep"]
      }],
      /**
       * Overflow Wrap
       * @see https://tailwindcss.com/docs/overflow-wrap
       */
      wrap: [{
        wrap: ["break-word", "anywhere", "normal"]
      }],
      /**
       * Hyphens
       * @see https://tailwindcss.com/docs/hyphens
       */
      hyphens: [{
        hyphens: ["none", "manual", "auto"]
      }],
      /**
       * Content
       * @see https://tailwindcss.com/docs/content
       */
      content: [{
        content: ["none", isArbitraryVariable, isArbitraryValue]
      }],
      // -------------------
      // --- Backgrounds ---
      // -------------------
      /**
       * Background Attachment
       * @see https://tailwindcss.com/docs/background-attachment
       */
      "bg-attachment": [{
        bg: ["fixed", "local", "scroll"]
      }],
      /**
       * Background Clip
       * @see https://tailwindcss.com/docs/background-clip
       */
      "bg-clip": [{
        "bg-clip": ["border", "padding", "content", "text"]
      }],
      /**
       * Background Origin
       * @see https://tailwindcss.com/docs/background-origin
       */
      "bg-origin": [{
        "bg-origin": ["border", "padding", "content"]
      }],
      /**
       * Background Position
       * @see https://tailwindcss.com/docs/background-position
       */
      "bg-position": [{
        bg: scaleBgPosition()
      }],
      /**
       * Background Repeat
       * @see https://tailwindcss.com/docs/background-repeat
       */
      "bg-repeat": [{
        bg: scaleBgRepeat()
      }],
      /**
       * Background Size
       * @see https://tailwindcss.com/docs/background-size
       */
      "bg-size": [{
        bg: scaleBgSize()
      }],
      /**
       * Background Image
       * @see https://tailwindcss.com/docs/background-image
       */
      "bg-image": [{
        bg: ["none", {
          linear: [{
            to: ["t", "tr", "r", "br", "b", "bl", "l", "tl"]
          }, isInteger, isArbitraryVariable, isArbitraryValue],
          radial: ["", isArbitraryVariable, isArbitraryValue],
          conic: [isInteger, isArbitraryVariable, isArbitraryValue]
        }, isArbitraryVariableImage, isArbitraryImage]
      }],
      /**
       * Background Color
       * @see https://tailwindcss.com/docs/background-color
       */
      "bg-color": [{
        bg: scaleColor()
      }],
      /**
       * Gradient Color Stops From Position
       * @see https://tailwindcss.com/docs/gradient-color-stops
       */
      "gradient-from-pos": [{
        from: scaleGradientStopPosition()
      }],
      /**
       * Gradient Color Stops Via Position
       * @see https://tailwindcss.com/docs/gradient-color-stops
       */
      "gradient-via-pos": [{
        via: scaleGradientStopPosition()
      }],
      /**
       * Gradient Color Stops To Position
       * @see https://tailwindcss.com/docs/gradient-color-stops
       */
      "gradient-to-pos": [{
        to: scaleGradientStopPosition()
      }],
      /**
       * Gradient Color Stops From
       * @see https://tailwindcss.com/docs/gradient-color-stops
       */
      "gradient-from": [{
        from: scaleColor()
      }],
      /**
       * Gradient Color Stops Via
       * @see https://tailwindcss.com/docs/gradient-color-stops
       */
      "gradient-via": [{
        via: scaleColor()
      }],
      /**
       * Gradient Color Stops To
       * @see https://tailwindcss.com/docs/gradient-color-stops
       */
      "gradient-to": [{
        to: scaleColor()
      }],
      // ---------------
      // --- Borders ---
      // ---------------
      /**
       * Border Radius
       * @see https://tailwindcss.com/docs/border-radius
       */
      rounded: [{
        rounded: scaleRadius()
      }],
      /**
       * Border Radius Start
       * @see https://tailwindcss.com/docs/border-radius
       */
      "rounded-s": [{
        "rounded-s": scaleRadius()
      }],
      /**
       * Border Radius End
       * @see https://tailwindcss.com/docs/border-radius
       */
      "rounded-e": [{
        "rounded-e": scaleRadius()
      }],
      /**
       * Border Radius Top
       * @see https://tailwindcss.com/docs/border-radius
       */
      "rounded-t": [{
        "rounded-t": scaleRadius()
      }],
      /**
       * Border Radius Right
       * @see https://tailwindcss.com/docs/border-radius
       */
      "rounded-r": [{
        "rounded-r": scaleRadius()
      }],
      /**
       * Border Radius Bottom
       * @see https://tailwindcss.com/docs/border-radius
       */
      "rounded-b": [{
        "rounded-b": scaleRadius()
      }],
      /**
       * Border Radius Left
       * @see https://tailwindcss.com/docs/border-radius
       */
      "rounded-l": [{
        "rounded-l": scaleRadius()
      }],
      /**
       * Border Radius Start Start
       * @see https://tailwindcss.com/docs/border-radius
       */
      "rounded-ss": [{
        "rounded-ss": scaleRadius()
      }],
      /**
       * Border Radius Start End
       * @see https://tailwindcss.com/docs/border-radius
       */
      "rounded-se": [{
        "rounded-se": scaleRadius()
      }],
      /**
       * Border Radius End End
       * @see https://tailwindcss.com/docs/border-radius
       */
      "rounded-ee": [{
        "rounded-ee": scaleRadius()
      }],
      /**
       * Border Radius End Start
       * @see https://tailwindcss.com/docs/border-radius
       */
      "rounded-es": [{
        "rounded-es": scaleRadius()
      }],
      /**
       * Border Radius Top Left
       * @see https://tailwindcss.com/docs/border-radius
       */
      "rounded-tl": [{
        "rounded-tl": scaleRadius()
      }],
      /**
       * Border Radius Top Right
       * @see https://tailwindcss.com/docs/border-radius
       */
      "rounded-tr": [{
        "rounded-tr": scaleRadius()
      }],
      /**
       * Border Radius Bottom Right
       * @see https://tailwindcss.com/docs/border-radius
       */
      "rounded-br": [{
        "rounded-br": scaleRadius()
      }],
      /**
       * Border Radius Bottom Left
       * @see https://tailwindcss.com/docs/border-radius
       */
      "rounded-bl": [{
        "rounded-bl": scaleRadius()
      }],
      /**
       * Border Width
       * @see https://tailwindcss.com/docs/border-width
       */
      "border-w": [{
        border: scaleBorderWidth()
      }],
      /**
       * Border Width Inline
       * @see https://tailwindcss.com/docs/border-width
       */
      "border-w-x": [{
        "border-x": scaleBorderWidth()
      }],
      /**
       * Border Width Block
       * @see https://tailwindcss.com/docs/border-width
       */
      "border-w-y": [{
        "border-y": scaleBorderWidth()
      }],
      /**
       * Border Width Inline Start
       * @see https://tailwindcss.com/docs/border-width
       */
      "border-w-s": [{
        "border-s": scaleBorderWidth()
      }],
      /**
       * Border Width Inline End
       * @see https://tailwindcss.com/docs/border-width
       */
      "border-w-e": [{
        "border-e": scaleBorderWidth()
      }],
      /**
       * Border Width Block Start
       * @see https://tailwindcss.com/docs/border-width
       */
      "border-w-bs": [{
        "border-bs": scaleBorderWidth()
      }],
      /**
       * Border Width Block End
       * @see https://tailwindcss.com/docs/border-width
       */
      "border-w-be": [{
        "border-be": scaleBorderWidth()
      }],
      /**
       * Border Width Top
       * @see https://tailwindcss.com/docs/border-width
       */
      "border-w-t": [{
        "border-t": scaleBorderWidth()
      }],
      /**
       * Border Width Right
       * @see https://tailwindcss.com/docs/border-width
       */
      "border-w-r": [{
        "border-r": scaleBorderWidth()
      }],
      /**
       * Border Width Bottom
       * @see https://tailwindcss.com/docs/border-width
       */
      "border-w-b": [{
        "border-b": scaleBorderWidth()
      }],
      /**
       * Border Width Left
       * @see https://tailwindcss.com/docs/border-width
       */
      "border-w-l": [{
        "border-l": scaleBorderWidth()
      }],
      /**
       * Divide Width X
       * @see https://tailwindcss.com/docs/border-width#between-children
       */
      "divide-x": [{
        "divide-x": scaleBorderWidth()
      }],
      /**
       * Divide Width X Reverse
       * @see https://tailwindcss.com/docs/border-width#between-children
       */
      "divide-x-reverse": ["divide-x-reverse"],
      /**
       * Divide Width Y
       * @see https://tailwindcss.com/docs/border-width#between-children
       */
      "divide-y": [{
        "divide-y": scaleBorderWidth()
      }],
      /**
       * Divide Width Y Reverse
       * @see https://tailwindcss.com/docs/border-width#between-children
       */
      "divide-y-reverse": ["divide-y-reverse"],
      /**
       * Border Style
       * @see https://tailwindcss.com/docs/border-style
       */
      "border-style": [{
        border: [...scaleLineStyle(), "hidden", "none"]
      }],
      /**
       * Divide Style
       * @see https://tailwindcss.com/docs/border-style#setting-the-divider-style
       */
      "divide-style": [{
        divide: [...scaleLineStyle(), "hidden", "none"]
      }],
      /**
       * Border Color
       * @see https://tailwindcss.com/docs/border-color
       */
      "border-color": [{
        border: scaleColor()
      }],
      /**
       * Border Color Inline
       * @see https://tailwindcss.com/docs/border-color
       */
      "border-color-x": [{
        "border-x": scaleColor()
      }],
      /**
       * Border Color Block
       * @see https://tailwindcss.com/docs/border-color
       */
      "border-color-y": [{
        "border-y": scaleColor()
      }],
      /**
       * Border Color Inline Start
       * @see https://tailwindcss.com/docs/border-color
       */
      "border-color-s": [{
        "border-s": scaleColor()
      }],
      /**
       * Border Color Inline End
       * @see https://tailwindcss.com/docs/border-color
       */
      "border-color-e": [{
        "border-e": scaleColor()
      }],
      /**
       * Border Color Block Start
       * @see https://tailwindcss.com/docs/border-color
       */
      "border-color-bs": [{
        "border-bs": scaleColor()
      }],
      /**
       * Border Color Block End
       * @see https://tailwindcss.com/docs/border-color
       */
      "border-color-be": [{
        "border-be": scaleColor()
      }],
      /**
       * Border Color Top
       * @see https://tailwindcss.com/docs/border-color
       */
      "border-color-t": [{
        "border-t": scaleColor()
      }],
      /**
       * Border Color Right
       * @see https://tailwindcss.com/docs/border-color
       */
      "border-color-r": [{
        "border-r": scaleColor()
      }],
      /**
       * Border Color Bottom
       * @see https://tailwindcss.com/docs/border-color
       */
      "border-color-b": [{
        "border-b": scaleColor()
      }],
      /**
       * Border Color Left
       * @see https://tailwindcss.com/docs/border-color
       */
      "border-color-l": [{
        "border-l": scaleColor()
      }],
      /**
       * Divide Color
       * @see https://tailwindcss.com/docs/divide-color
       */
      "divide-color": [{
        divide: scaleColor()
      }],
      /**
       * Outline Style
       * @see https://tailwindcss.com/docs/outline-style
       */
      "outline-style": [{
        outline: [...scaleLineStyle(), "none", "hidden"]
      }],
      /**
       * Outline Offset
       * @see https://tailwindcss.com/docs/outline-offset
       */
      "outline-offset": [{
        "outline-offset": [isNumber, isArbitraryVariable, isArbitraryValue]
      }],
      /**
       * Outline Width
       * @see https://tailwindcss.com/docs/outline-width
       */
      "outline-w": [{
        outline: ["", isNumber, isArbitraryVariableLength, isArbitraryLength]
      }],
      /**
       * Outline Color
       * @see https://tailwindcss.com/docs/outline-color
       */
      "outline-color": [{
        outline: scaleColor()
      }],
      // ---------------
      // --- Effects ---
      // ---------------
      /**
       * Box Shadow
       * @see https://tailwindcss.com/docs/box-shadow
       */
      shadow: [{
        shadow: [
          // Deprecated since Tailwind CSS v4.0.0
          "",
          "none",
          themeShadow,
          isArbitraryVariableShadow,
          isArbitraryShadow
        ]
      }],
      /**
       * Box Shadow Color
       * @see https://tailwindcss.com/docs/box-shadow#setting-the-shadow-color
       */
      "shadow-color": [{
        shadow: scaleColor()
      }],
      /**
       * Inset Box Shadow
       * @see https://tailwindcss.com/docs/box-shadow#adding-an-inset-shadow
       */
      "inset-shadow": [{
        "inset-shadow": ["none", themeInsetShadow, isArbitraryVariableShadow, isArbitraryShadow]
      }],
      /**
       * Inset Box Shadow Color
       * @see https://tailwindcss.com/docs/box-shadow#setting-the-inset-shadow-color
       */
      "inset-shadow-color": [{
        "inset-shadow": scaleColor()
      }],
      /**
       * Ring Width
       * @see https://tailwindcss.com/docs/box-shadow#adding-a-ring
       */
      "ring-w": [{
        ring: scaleBorderWidth()
      }],
      /**
       * Ring Width Inset
       * @see https://v3.tailwindcss.com/docs/ring-width#inset-rings
       * @deprecated since Tailwind CSS v4.0.0
       * @see https://github.com/tailwindlabs/tailwindcss/blob/v4.0.0/packages/tailwindcss/src/utilities.ts#L4158
       */
      "ring-w-inset": ["ring-inset"],
      /**
       * Ring Color
       * @see https://tailwindcss.com/docs/box-shadow#setting-the-ring-color
       */
      "ring-color": [{
        ring: scaleColor()
      }],
      /**
       * Ring Offset Width
       * @see https://v3.tailwindcss.com/docs/ring-offset-width
       * @deprecated since Tailwind CSS v4.0.0
       * @see https://github.com/tailwindlabs/tailwindcss/blob/v4.0.0/packages/tailwindcss/src/utilities.ts#L4158
       */
      "ring-offset-w": [{
        "ring-offset": [isNumber, isArbitraryLength]
      }],
      /**
       * Ring Offset Color
       * @see https://v3.tailwindcss.com/docs/ring-offset-color
       * @deprecated since Tailwind CSS v4.0.0
       * @see https://github.com/tailwindlabs/tailwindcss/blob/v4.0.0/packages/tailwindcss/src/utilities.ts#L4158
       */
      "ring-offset-color": [{
        "ring-offset": scaleColor()
      }],
      /**
       * Inset Ring Width
       * @see https://tailwindcss.com/docs/box-shadow#adding-an-inset-ring
       */
      "inset-ring-w": [{
        "inset-ring": scaleBorderWidth()
      }],
      /**
       * Inset Ring Color
       * @see https://tailwindcss.com/docs/box-shadow#setting-the-inset-ring-color
       */
      "inset-ring-color": [{
        "inset-ring": scaleColor()
      }],
      /**
       * Text Shadow
       * @see https://tailwindcss.com/docs/text-shadow
       */
      "text-shadow": [{
        "text-shadow": ["none", themeTextShadow, isArbitraryVariableShadow, isArbitraryShadow]
      }],
      /**
       * Text Shadow Color
       * @see https://tailwindcss.com/docs/text-shadow#setting-the-shadow-color
       */
      "text-shadow-color": [{
        "text-shadow": scaleColor()
      }],
      /**
       * Opacity
       * @see https://tailwindcss.com/docs/opacity
       */
      opacity: [{
        opacity: [isNumber, isArbitraryVariable, isArbitraryValue]
      }],
      /**
       * Mix Blend Mode
       * @see https://tailwindcss.com/docs/mix-blend-mode
       */
      "mix-blend": [{
        "mix-blend": [...scaleBlendMode(), "plus-darker", "plus-lighter"]
      }],
      /**
       * Background Blend Mode
       * @see https://tailwindcss.com/docs/background-blend-mode
       */
      "bg-blend": [{
        "bg-blend": scaleBlendMode()
      }],
      /**
       * Mask Clip
       * @see https://tailwindcss.com/docs/mask-clip
       */
      "mask-clip": [{
        "mask-clip": ["border", "padding", "content", "fill", "stroke", "view"]
      }, "mask-no-clip"],
      /**
       * Mask Composite
       * @see https://tailwindcss.com/docs/mask-composite
       */
      "mask-composite": [{
        mask: ["add", "subtract", "intersect", "exclude"]
      }],
      /**
       * Mask Image
       * @see https://tailwindcss.com/docs/mask-image
       */
      "mask-image-linear-pos": [{
        "mask-linear": [isNumber]
      }],
      "mask-image-linear-from-pos": [{
        "mask-linear-from": scaleMaskImagePosition()
      }],
      "mask-image-linear-to-pos": [{
        "mask-linear-to": scaleMaskImagePosition()
      }],
      "mask-image-linear-from-color": [{
        "mask-linear-from": scaleColor()
      }],
      "mask-image-linear-to-color": [{
        "mask-linear-to": scaleColor()
      }],
      "mask-image-t-from-pos": [{
        "mask-t-from": scaleMaskImagePosition()
      }],
      "mask-image-t-to-pos": [{
        "mask-t-to": scaleMaskImagePosition()
      }],
      "mask-image-t-from-color": [{
        "mask-t-from": scaleColor()
      }],
      "mask-image-t-to-color": [{
        "mask-t-to": scaleColor()
      }],
      "mask-image-r-from-pos": [{
        "mask-r-from": scaleMaskImagePosition()
      }],
      "mask-image-r-to-pos": [{
        "mask-r-to": scaleMaskImagePosition()
      }],
      "mask-image-r-from-color": [{
        "mask-r-from": scaleColor()
      }],
      "mask-image-r-to-color": [{
        "mask-r-to": scaleColor()
      }],
      "mask-image-b-from-pos": [{
        "mask-b-from": scaleMaskImagePosition()
      }],
      "mask-image-b-to-pos": [{
        "mask-b-to": scaleMaskImagePosition()
      }],
      "mask-image-b-from-color": [{
        "mask-b-from": scaleColor()
      }],
      "mask-image-b-to-color": [{
        "mask-b-to": scaleColor()
      }],
      "mask-image-l-from-pos": [{
        "mask-l-from": scaleMaskImagePosition()
      }],
      "mask-image-l-to-pos": [{
        "mask-l-to": scaleMaskImagePosition()
      }],
      "mask-image-l-from-color": [{
        "mask-l-from": scaleColor()
      }],
      "mask-image-l-to-color": [{
        "mask-l-to": scaleColor()
      }],
      "mask-image-x-from-pos": [{
        "mask-x-from": scaleMaskImagePosition()
      }],
      "mask-image-x-to-pos": [{
        "mask-x-to": scaleMaskImagePosition()
      }],
      "mask-image-x-from-color": [{
        "mask-x-from": scaleColor()
      }],
      "mask-image-x-to-color": [{
        "mask-x-to": scaleColor()
      }],
      "mask-image-y-from-pos": [{
        "mask-y-from": scaleMaskImagePosition()
      }],
      "mask-image-y-to-pos": [{
        "mask-y-to": scaleMaskImagePosition()
      }],
      "mask-image-y-from-color": [{
        "mask-y-from": scaleColor()
      }],
      "mask-image-y-to-color": [{
        "mask-y-to": scaleColor()
      }],
      "mask-image-radial": [{
        "mask-radial": [isArbitraryVariable, isArbitraryValue]
      }],
      "mask-image-radial-from-pos": [{
        "mask-radial-from": scaleMaskImagePosition()
      }],
      "mask-image-radial-to-pos": [{
        "mask-radial-to": scaleMaskImagePosition()
      }],
      "mask-image-radial-from-color": [{
        "mask-radial-from": scaleColor()
      }],
      "mask-image-radial-to-color": [{
        "mask-radial-to": scaleColor()
      }],
      "mask-image-radial-shape": [{
        "mask-radial": ["circle", "ellipse"]
      }],
      "mask-image-radial-size": [{
        "mask-radial": [{
          closest: ["side", "corner"],
          farthest: ["side", "corner"]
        }]
      }],
      "mask-image-radial-pos": [{
        "mask-radial-at": scalePosition()
      }],
      "mask-image-conic-pos": [{
        "mask-conic": [isNumber]
      }],
      "mask-image-conic-from-pos": [{
        "mask-conic-from": scaleMaskImagePosition()
      }],
      "mask-image-conic-to-pos": [{
        "mask-conic-to": scaleMaskImagePosition()
      }],
      "mask-image-conic-from-color": [{
        "mask-conic-from": scaleColor()
      }],
      "mask-image-conic-to-color": [{
        "mask-conic-to": scaleColor()
      }],
      /**
       * Mask Mode
       * @see https://tailwindcss.com/docs/mask-mode
       */
      "mask-mode": [{
        mask: ["alpha", "luminance", "match"]
      }],
      /**
       * Mask Origin
       * @see https://tailwindcss.com/docs/mask-origin
       */
      "mask-origin": [{
        "mask-origin": ["border", "padding", "content", "fill", "stroke", "view"]
      }],
      /**
       * Mask Position
       * @see https://tailwindcss.com/docs/mask-position
       */
      "mask-position": [{
        mask: scaleBgPosition()
      }],
      /**
       * Mask Repeat
       * @see https://tailwindcss.com/docs/mask-repeat
       */
      "mask-repeat": [{
        mask: scaleBgRepeat()
      }],
      /**
       * Mask Size
       * @see https://tailwindcss.com/docs/mask-size
       */
      "mask-size": [{
        mask: scaleBgSize()
      }],
      /**
       * Mask Type
       * @see https://tailwindcss.com/docs/mask-type
       */
      "mask-type": [{
        "mask-type": ["alpha", "luminance"]
      }],
      /**
       * Mask Image
       * @see https://tailwindcss.com/docs/mask-image
       */
      "mask-image": [{
        mask: ["none", isArbitraryVariable, isArbitraryValue]
      }],
      // ---------------
      // --- Filters ---
      // ---------------
      /**
       * Filter
       * @see https://tailwindcss.com/docs/filter
       */
      filter: [{
        filter: [
          // Deprecated since Tailwind CSS v3.0.0
          "",
          "none",
          isArbitraryVariable,
          isArbitraryValue
        ]
      }],
      /**
       * Blur
       * @see https://tailwindcss.com/docs/blur
       */
      blur: [{
        blur: scaleBlur()
      }],
      /**
       * Brightness
       * @see https://tailwindcss.com/docs/brightness
       */
      brightness: [{
        brightness: [isNumber, isArbitraryVariable, isArbitraryValue]
      }],
      /**
       * Contrast
       * @see https://tailwindcss.com/docs/contrast
       */
      contrast: [{
        contrast: [isNumber, isArbitraryVariable, isArbitraryValue]
      }],
      /**
       * Drop Shadow
       * @see https://tailwindcss.com/docs/drop-shadow
       */
      "drop-shadow": [{
        "drop-shadow": [
          // Deprecated since Tailwind CSS v4.0.0
          "",
          "none",
          themeDropShadow,
          isArbitraryVariableShadow,
          isArbitraryShadow
        ]
      }],
      /**
       * Drop Shadow Color
       * @see https://tailwindcss.com/docs/filter-drop-shadow#setting-the-shadow-color
       */
      "drop-shadow-color": [{
        "drop-shadow": scaleColor()
      }],
      /**
       * Grayscale
       * @see https://tailwindcss.com/docs/grayscale
       */
      grayscale: [{
        grayscale: ["", isNumber, isArbitraryVariable, isArbitraryValue]
      }],
      /**
       * Hue Rotate
       * @see https://tailwindcss.com/docs/hue-rotate
       */
      "hue-rotate": [{
        "hue-rotate": [isNumber, isArbitraryVariable, isArbitraryValue]
      }],
      /**
       * Invert
       * @see https://tailwindcss.com/docs/invert
       */
      invert: [{
        invert: ["", isNumber, isArbitraryVariable, isArbitraryValue]
      }],
      /**
       * Saturate
       * @see https://tailwindcss.com/docs/saturate
       */
      saturate: [{
        saturate: [isNumber, isArbitraryVariable, isArbitraryValue]
      }],
      /**
       * Sepia
       * @see https://tailwindcss.com/docs/sepia
       */
      sepia: [{
        sepia: ["", isNumber, isArbitraryVariable, isArbitraryValue]
      }],
      /**
       * Backdrop Filter
       * @see https://tailwindcss.com/docs/backdrop-filter
       */
      "backdrop-filter": [{
        "backdrop-filter": [
          // Deprecated since Tailwind CSS v3.0.0
          "",
          "none",
          isArbitraryVariable,
          isArbitraryValue
        ]
      }],
      /**
       * Backdrop Blur
       * @see https://tailwindcss.com/docs/backdrop-blur
       */
      "backdrop-blur": [{
        "backdrop-blur": scaleBlur()
      }],
      /**
       * Backdrop Brightness
       * @see https://tailwindcss.com/docs/backdrop-brightness
       */
      "backdrop-brightness": [{
        "backdrop-brightness": [isNumber, isArbitraryVariable, isArbitraryValue]
      }],
      /**
       * Backdrop Contrast
       * @see https://tailwindcss.com/docs/backdrop-contrast
       */
      "backdrop-contrast": [{
        "backdrop-contrast": [isNumber, isArbitraryVariable, isArbitraryValue]
      }],
      /**
       * Backdrop Grayscale
       * @see https://tailwindcss.com/docs/backdrop-grayscale
       */
      "backdrop-grayscale": [{
        "backdrop-grayscale": ["", isNumber, isArbitraryVariable, isArbitraryValue]
      }],
      /**
       * Backdrop Hue Rotate
       * @see https://tailwindcss.com/docs/backdrop-hue-rotate
       */
      "backdrop-hue-rotate": [{
        "backdrop-hue-rotate": [isNumber, isArbitraryVariable, isArbitraryValue]
      }],
      /**
       * Backdrop Invert
       * @see https://tailwindcss.com/docs/backdrop-invert
       */
      "backdrop-invert": [{
        "backdrop-invert": ["", isNumber, isArbitraryVariable, isArbitraryValue]
      }],
      /**
       * Backdrop Opacity
       * @see https://tailwindcss.com/docs/backdrop-opacity
       */
      "backdrop-opacity": [{
        "backdrop-opacity": [isNumber, isArbitraryVariable, isArbitraryValue]
      }],
      /**
       * Backdrop Saturate
       * @see https://tailwindcss.com/docs/backdrop-saturate
       */
      "backdrop-saturate": [{
        "backdrop-saturate": [isNumber, isArbitraryVariable, isArbitraryValue]
      }],
      /**
       * Backdrop Sepia
       * @see https://tailwindcss.com/docs/backdrop-sepia
       */
      "backdrop-sepia": [{
        "backdrop-sepia": ["", isNumber, isArbitraryVariable, isArbitraryValue]
      }],
      // --------------
      // --- Tables ---
      // --------------
      /**
       * Border Collapse
       * @see https://tailwindcss.com/docs/border-collapse
       */
      "border-collapse": [{
        border: ["collapse", "separate"]
      }],
      /**
       * Border Spacing
       * @see https://tailwindcss.com/docs/border-spacing
       */
      "border-spacing": [{
        "border-spacing": scaleUnambiguousSpacing()
      }],
      /**
       * Border Spacing X
       * @see https://tailwindcss.com/docs/border-spacing
       */
      "border-spacing-x": [{
        "border-spacing-x": scaleUnambiguousSpacing()
      }],
      /**
       * Border Spacing Y
       * @see https://tailwindcss.com/docs/border-spacing
       */
      "border-spacing-y": [{
        "border-spacing-y": scaleUnambiguousSpacing()
      }],
      /**
       * Table Layout
       * @see https://tailwindcss.com/docs/table-layout
       */
      "table-layout": [{
        table: ["auto", "fixed"]
      }],
      /**
       * Caption Side
       * @see https://tailwindcss.com/docs/caption-side
       */
      caption: [{
        caption: ["top", "bottom"]
      }],
      // ---------------------------------
      // --- Transitions and Animation ---
      // ---------------------------------
      /**
       * Transition Property
       * @see https://tailwindcss.com/docs/transition-property
       */
      transition: [{
        transition: ["", "all", "colors", "opacity", "shadow", "transform", "none", isArbitraryVariable, isArbitraryValue]
      }],
      /**
       * Transition Behavior
       * @see https://tailwindcss.com/docs/transition-behavior
       */
      "transition-behavior": [{
        transition: ["normal", "discrete"]
      }],
      /**
       * Transition Duration
       * @see https://tailwindcss.com/docs/transition-duration
       */
      duration: [{
        duration: [isNumber, "initial", isArbitraryVariable, isArbitraryValue]
      }],
      /**
       * Transition Timing Function
       * @see https://tailwindcss.com/docs/transition-timing-function
       */
      ease: [{
        ease: ["linear", "initial", themeEase, isArbitraryVariable, isArbitraryValue]
      }],
      /**
       * Transition Delay
       * @see https://tailwindcss.com/docs/transition-delay
       */
      delay: [{
        delay: [isNumber, isArbitraryVariable, isArbitraryValue]
      }],
      /**
       * Animation
       * @see https://tailwindcss.com/docs/animation
       */
      animate: [{
        animate: ["none", themeAnimate, isArbitraryVariable, isArbitraryValue]
      }],
      // ------------------
      // --- Transforms ---
      // ------------------
      /**
       * Backface Visibility
       * @see https://tailwindcss.com/docs/backface-visibility
       */
      backface: [{
        backface: ["hidden", "visible"]
      }],
      /**
       * Perspective
       * @see https://tailwindcss.com/docs/perspective
       */
      perspective: [{
        perspective: [themePerspective, isArbitraryVariable, isArbitraryValue]
      }],
      /**
       * Perspective Origin
       * @see https://tailwindcss.com/docs/perspective-origin
       */
      "perspective-origin": [{
        "perspective-origin": scalePositionWithArbitrary()
      }],
      /**
       * Rotate
       * @see https://tailwindcss.com/docs/rotate
       */
      rotate: [{
        rotate: scaleRotate()
      }],
      /**
       * Rotate X
       * @see https://tailwindcss.com/docs/rotate
       */
      "rotate-x": [{
        "rotate-x": scaleRotate()
      }],
      /**
       * Rotate Y
       * @see https://tailwindcss.com/docs/rotate
       */
      "rotate-y": [{
        "rotate-y": scaleRotate()
      }],
      /**
       * Rotate Z
       * @see https://tailwindcss.com/docs/rotate
       */
      "rotate-z": [{
        "rotate-z": scaleRotate()
      }],
      /**
       * Scale
       * @see https://tailwindcss.com/docs/scale
       */
      scale: [{
        scale: scaleScale()
      }],
      /**
       * Scale X
       * @see https://tailwindcss.com/docs/scale
       */
      "scale-x": [{
        "scale-x": scaleScale()
      }],
      /**
       * Scale Y
       * @see https://tailwindcss.com/docs/scale
       */
      "scale-y": [{
        "scale-y": scaleScale()
      }],
      /**
       * Scale Z
       * @see https://tailwindcss.com/docs/scale
       */
      "scale-z": [{
        "scale-z": scaleScale()
      }],
      /**
       * Scale 3D
       * @see https://tailwindcss.com/docs/scale
       */
      "scale-3d": ["scale-3d"],
      /**
       * Skew
       * @see https://tailwindcss.com/docs/skew
       */
      skew: [{
        skew: scaleSkew()
      }],
      /**
       * Skew X
       * @see https://tailwindcss.com/docs/skew
       */
      "skew-x": [{
        "skew-x": scaleSkew()
      }],
      /**
       * Skew Y
       * @see https://tailwindcss.com/docs/skew
       */
      "skew-y": [{
        "skew-y": scaleSkew()
      }],
      /**
       * Transform
       * @see https://tailwindcss.com/docs/transform
       */
      transform: [{
        transform: [isArbitraryVariable, isArbitraryValue, "", "none", "gpu", "cpu"]
      }],
      /**
       * Transform Origin
       * @see https://tailwindcss.com/docs/transform-origin
       */
      "transform-origin": [{
        origin: scalePositionWithArbitrary()
      }],
      /**
       * Transform Style
       * @see https://tailwindcss.com/docs/transform-style
       */
      "transform-style": [{
        transform: ["3d", "flat"]
      }],
      /**
       * Translate
       * @see https://tailwindcss.com/docs/translate
       */
      translate: [{
        translate: scaleTranslate()
      }],
      /**
       * Translate X
       * @see https://tailwindcss.com/docs/translate
       */
      "translate-x": [{
        "translate-x": scaleTranslate()
      }],
      /**
       * Translate Y
       * @see https://tailwindcss.com/docs/translate
       */
      "translate-y": [{
        "translate-y": scaleTranslate()
      }],
      /**
       * Translate Z
       * @see https://tailwindcss.com/docs/translate
       */
      "translate-z": [{
        "translate-z": scaleTranslate()
      }],
      /**
       * Translate None
       * @see https://tailwindcss.com/docs/translate
       */
      "translate-none": ["translate-none"],
      /**
       * Zoom
       * @see https://tailwindcss.com/docs/zoom
       */
      zoom: [{
        zoom: [isInteger, isArbitraryVariable, isArbitraryValue]
      }],
      // ---------------------
      // --- Interactivity ---
      // ---------------------
      /**
       * Accent Color
       * @see https://tailwindcss.com/docs/accent-color
       */
      accent: [{
        accent: scaleColor()
      }],
      /**
       * Appearance
       * @see https://tailwindcss.com/docs/appearance
       */
      appearance: [{
        appearance: ["none", "auto"]
      }],
      /**
       * Caret Color
       * @see https://tailwindcss.com/docs/just-in-time-mode#caret-color-utilities
       */
      "caret-color": [{
        caret: scaleColor()
      }],
      /**
       * Color Scheme
       * @see https://tailwindcss.com/docs/color-scheme
       */
      "color-scheme": [{
        scheme: ["normal", "dark", "light", "light-dark", "only-dark", "only-light"]
      }],
      /**
       * Cursor
       * @see https://tailwindcss.com/docs/cursor
       */
      cursor: [{
        cursor: ["auto", "default", "pointer", "wait", "text", "move", "help", "not-allowed", "none", "context-menu", "progress", "cell", "crosshair", "vertical-text", "alias", "copy", "no-drop", "grab", "grabbing", "all-scroll", "col-resize", "row-resize", "n-resize", "e-resize", "s-resize", "w-resize", "ne-resize", "nw-resize", "se-resize", "sw-resize", "ew-resize", "ns-resize", "nesw-resize", "nwse-resize", "zoom-in", "zoom-out", isArbitraryVariable, isArbitraryValue]
      }],
      /**
       * Field Sizing
       * @see https://tailwindcss.com/docs/field-sizing
       */
      "field-sizing": [{
        "field-sizing": ["fixed", "content"]
      }],
      /**
       * Pointer Events
       * @see https://tailwindcss.com/docs/pointer-events
       */
      "pointer-events": [{
        "pointer-events": ["auto", "none"]
      }],
      /**
       * Resize
       * @see https://tailwindcss.com/docs/resize
       */
      resize: [{
        resize: ["none", "", "y", "x"]
      }],
      /**
       * Scroll Behavior
       * @see https://tailwindcss.com/docs/scroll-behavior
       */
      "scroll-behavior": [{
        scroll: ["auto", "smooth"]
      }],
      /**
       * Scrollbar Thumb Color
       * @see https://tailwindcss.com/docs/scrollbar-color
       */
      "scrollbar-thumb-color": [{
        "scrollbar-thumb": scaleColor()
      }],
      /**
       * Scrollbar Track Color
       * @see https://tailwindcss.com/docs/scrollbar-color
       */
      "scrollbar-track-color": [{
        "scrollbar-track": scaleColor()
      }],
      /**
       * Scrollbar Gutter
       * @see https://tailwindcss.com/docs/scrollbar-gutter
       */
      "scrollbar-gutter": [{
        "scrollbar-gutter": ["auto", "stable", "both"]
      }],
      /**
       * Scrollbar Width
       * @see https://tailwindcss.com/docs/scrollbar-width
       */
      "scrollbar-w": [{
        scrollbar: ["auto", "thin", "none"]
      }],
      /**
       * Scroll Margin
       * @see https://tailwindcss.com/docs/scroll-margin
       */
      "scroll-m": [{
        "scroll-m": scaleUnambiguousSpacing()
      }],
      /**
       * Scroll Margin Inline
       * @see https://tailwindcss.com/docs/scroll-margin
       */
      "scroll-mx": [{
        "scroll-mx": scaleUnambiguousSpacing()
      }],
      /**
       * Scroll Margin Block
       * @see https://tailwindcss.com/docs/scroll-margin
       */
      "scroll-my": [{
        "scroll-my": scaleUnambiguousSpacing()
      }],
      /**
       * Scroll Margin Inline Start
       * @see https://tailwindcss.com/docs/scroll-margin
       */
      "scroll-ms": [{
        "scroll-ms": scaleUnambiguousSpacing()
      }],
      /**
       * Scroll Margin Inline End
       * @see https://tailwindcss.com/docs/scroll-margin
       */
      "scroll-me": [{
        "scroll-me": scaleUnambiguousSpacing()
      }],
      /**
       * Scroll Margin Block Start
       * @see https://tailwindcss.com/docs/scroll-margin
       */
      "scroll-mbs": [{
        "scroll-mbs": scaleUnambiguousSpacing()
      }],
      /**
       * Scroll Margin Block End
       * @see https://tailwindcss.com/docs/scroll-margin
       */
      "scroll-mbe": [{
        "scroll-mbe": scaleUnambiguousSpacing()
      }],
      /**
       * Scroll Margin Top
       * @see https://tailwindcss.com/docs/scroll-margin
       */
      "scroll-mt": [{
        "scroll-mt": scaleUnambiguousSpacing()
      }],
      /**
       * Scroll Margin Right
       * @see https://tailwindcss.com/docs/scroll-margin
       */
      "scroll-mr": [{
        "scroll-mr": scaleUnambiguousSpacing()
      }],
      /**
       * Scroll Margin Bottom
       * @see https://tailwindcss.com/docs/scroll-margin
       */
      "scroll-mb": [{
        "scroll-mb": scaleUnambiguousSpacing()
      }],
      /**
       * Scroll Margin Left
       * @see https://tailwindcss.com/docs/scroll-margin
       */
      "scroll-ml": [{
        "scroll-ml": scaleUnambiguousSpacing()
      }],
      /**
       * Scroll Padding
       * @see https://tailwindcss.com/docs/scroll-padding
       */
      "scroll-p": [{
        "scroll-p": scaleUnambiguousSpacing()
      }],
      /**
       * Scroll Padding Inline
       * @see https://tailwindcss.com/docs/scroll-padding
       */
      "scroll-px": [{
        "scroll-px": scaleUnambiguousSpacing()
      }],
      /**
       * Scroll Padding Block
       * @see https://tailwindcss.com/docs/scroll-padding
       */
      "scroll-py": [{
        "scroll-py": scaleUnambiguousSpacing()
      }],
      /**
       * Scroll Padding Inline Start
       * @see https://tailwindcss.com/docs/scroll-padding
       */
      "scroll-ps": [{
        "scroll-ps": scaleUnambiguousSpacing()
      }],
      /**
       * Scroll Padding Inline End
       * @see https://tailwindcss.com/docs/scroll-padding
       */
      "scroll-pe": [{
        "scroll-pe": scaleUnambiguousSpacing()
      }],
      /**
       * Scroll Padding Block Start
       * @see https://tailwindcss.com/docs/scroll-padding
       */
      "scroll-pbs": [{
        "scroll-pbs": scaleUnambiguousSpacing()
      }],
      /**
       * Scroll Padding Block End
       * @see https://tailwindcss.com/docs/scroll-padding
       */
      "scroll-pbe": [{
        "scroll-pbe": scaleUnambiguousSpacing()
      }],
      /**
       * Scroll Padding Top
       * @see https://tailwindcss.com/docs/scroll-padding
       */
      "scroll-pt": [{
        "scroll-pt": scaleUnambiguousSpacing()
      }],
      /**
       * Scroll Padding Right
       * @see https://tailwindcss.com/docs/scroll-padding
       */
      "scroll-pr": [{
        "scroll-pr": scaleUnambiguousSpacing()
      }],
      /**
       * Scroll Padding Bottom
       * @see https://tailwindcss.com/docs/scroll-padding
       */
      "scroll-pb": [{
        "scroll-pb": scaleUnambiguousSpacing()
      }],
      /**
       * Scroll Padding Left
       * @see https://tailwindcss.com/docs/scroll-padding
       */
      "scroll-pl": [{
        "scroll-pl": scaleUnambiguousSpacing()
      }],
      /**
       * Scroll Snap Align
       * @see https://tailwindcss.com/docs/scroll-snap-align
       */
      "snap-align": [{
        snap: ["start", "end", "center", "align-none"]
      }],
      /**
       * Scroll Snap Stop
       * @see https://tailwindcss.com/docs/scroll-snap-stop
       */
      "snap-stop": [{
        snap: ["normal", "always"]
      }],
      /**
       * Scroll Snap Type
       * @see https://tailwindcss.com/docs/scroll-snap-type
       */
      "snap-type": [{
        snap: ["none", "x", "y", "both"]
      }],
      /**
       * Scroll Snap Type Strictness
       * @see https://tailwindcss.com/docs/scroll-snap-type
       */
      "snap-strictness": [{
        snap: ["mandatory", "proximity"]
      }],
      /**
       * Touch Action
       * @see https://tailwindcss.com/docs/touch-action
       */
      touch: [{
        touch: ["auto", "none", "manipulation"]
      }],
      /**
       * Touch Action X
       * @see https://tailwindcss.com/docs/touch-action
       */
      "touch-x": [{
        "touch-pan": ["x", "left", "right"]
      }],
      /**
       * Touch Action Y
       * @see https://tailwindcss.com/docs/touch-action
       */
      "touch-y": [{
        "touch-pan": ["y", "up", "down"]
      }],
      /**
       * Touch Action Pinch Zoom
       * @see https://tailwindcss.com/docs/touch-action
       */
      "touch-pz": ["touch-pinch-zoom"],
      /**
       * User Select
       * @see https://tailwindcss.com/docs/user-select
       */
      select: [{
        select: ["none", "text", "all", "auto"]
      }],
      /**
       * Will Change
       * @see https://tailwindcss.com/docs/will-change
       */
      "will-change": [{
        "will-change": ["auto", "scroll", "contents", "transform", isArbitraryVariable, isArbitraryValue]
      }],
      // -----------
      // --- SVG ---
      // -----------
      /**
       * Fill
       * @see https://tailwindcss.com/docs/fill
       */
      fill: [{
        fill: ["none", ...scaleColor()]
      }],
      /**
       * Stroke Width
       * @see https://tailwindcss.com/docs/stroke-width
       */
      "stroke-w": [{
        stroke: [isNumber, isArbitraryVariableLength, isArbitraryLength, isArbitraryNumber]
      }],
      /**
       * Stroke
       * @see https://tailwindcss.com/docs/stroke
       */
      stroke: [{
        stroke: ["none", ...scaleColor()]
      }],
      // ---------------------
      // --- Accessibility ---
      // ---------------------
      /**
       * Forced Color Adjust
       * @see https://tailwindcss.com/docs/forced-color-adjust
       */
      "forced-color-adjust": [{
        "forced-color-adjust": ["auto", "none"]
      }]
    },
    conflictingClassGroups: {
      "container-named": ["container-type"],
      overflow: ["overflow-x", "overflow-y"],
      overscroll: ["overscroll-x", "overscroll-y"],
      inset: ["inset-x", "inset-y", "inset-bs", "inset-be", "start", "end", "top", "right", "bottom", "left"],
      "inset-x": ["right", "left"],
      "inset-y": ["top", "bottom"],
      flex: ["basis", "grow", "shrink"],
      gap: ["gap-x", "gap-y"],
      p: ["px", "py", "ps", "pe", "pbs", "pbe", "pt", "pr", "pb", "pl"],
      px: ["pr", "pl"],
      py: ["pt", "pb"],
      m: ["mx", "my", "ms", "me", "mbs", "mbe", "mt", "mr", "mb", "ml"],
      mx: ["mr", "ml"],
      my: ["mt", "mb"],
      size: ["w", "h"],
      "font-size": ["leading"],
      "fvn-normal": ["fvn-ordinal", "fvn-slashed-zero", "fvn-figure", "fvn-spacing", "fvn-fraction"],
      "fvn-ordinal": ["fvn-normal"],
      "fvn-slashed-zero": ["fvn-normal"],
      "fvn-figure": ["fvn-normal"],
      "fvn-spacing": ["fvn-normal"],
      "fvn-fraction": ["fvn-normal"],
      "line-clamp": ["display", "overflow"],
      rounded: ["rounded-s", "rounded-e", "rounded-t", "rounded-r", "rounded-b", "rounded-l", "rounded-ss", "rounded-se", "rounded-ee", "rounded-es", "rounded-tl", "rounded-tr", "rounded-br", "rounded-bl"],
      "rounded-s": ["rounded-ss", "rounded-es"],
      "rounded-e": ["rounded-se", "rounded-ee"],
      "rounded-t": ["rounded-tl", "rounded-tr"],
      "rounded-r": ["rounded-tr", "rounded-br"],
      "rounded-b": ["rounded-br", "rounded-bl"],
      "rounded-l": ["rounded-tl", "rounded-bl"],
      "border-spacing": ["border-spacing-x", "border-spacing-y"],
      "border-w": ["border-w-x", "border-w-y", "border-w-s", "border-w-e", "border-w-bs", "border-w-be", "border-w-t", "border-w-r", "border-w-b", "border-w-l"],
      "border-w-x": ["border-w-r", "border-w-l"],
      "border-w-y": ["border-w-t", "border-w-b"],
      "border-color": ["border-color-x", "border-color-y", "border-color-s", "border-color-e", "border-color-bs", "border-color-be", "border-color-t", "border-color-r", "border-color-b", "border-color-l"],
      "border-color-x": ["border-color-r", "border-color-l"],
      "border-color-y": ["border-color-t", "border-color-b"],
      translate: ["translate-x", "translate-y", "translate-none"],
      "translate-none": ["translate", "translate-x", "translate-y", "translate-z"],
      "scroll-m": ["scroll-mx", "scroll-my", "scroll-ms", "scroll-me", "scroll-mbs", "scroll-mbe", "scroll-mt", "scroll-mr", "scroll-mb", "scroll-ml"],
      "scroll-mx": ["scroll-mr", "scroll-ml"],
      "scroll-my": ["scroll-mt", "scroll-mb"],
      "scroll-p": ["scroll-px", "scroll-py", "scroll-ps", "scroll-pe", "scroll-pbs", "scroll-pbe", "scroll-pt", "scroll-pr", "scroll-pb", "scroll-pl"],
      "scroll-px": ["scroll-pr", "scroll-pl"],
      "scroll-py": ["scroll-pt", "scroll-pb"],
      touch: ["touch-x", "touch-y", "touch-pz"],
      "touch-x": ["touch"],
      "touch-y": ["touch"],
      "touch-pz": ["touch"]
    },
    conflictingClassGroupModifiers: {
      "font-size": ["leading"]
    },
    postfixLookupClassGroups: ["container-type"],
    orderSensitiveModifiers: ["*", "**", "after", "backdrop", "before", "details-content", "file", "first-letter", "first-line", "marker", "placeholder", "selection"]
  };
};
var twMerge = /* @__PURE__ */ createTailwindMerge(getDefaultConfig);

// src/presentation/components/ui/cn.ts
function cn(...inputs) {
  return twMerge(clsx(inputs));
}

// src/presentation/components/ui/Label.tsx
var import_jsx_runtime3 = __toESM(require_jsx_runtime(), 1);

// node_modules/@base-ui/react/slider/index.parts.mjs
var index_parts_exports = {};
__export(index_parts_exports, {
  Control: () => SliderControl,
  Indicator: () => SliderIndicator,
  Label: () => SliderLabel,
  Root: () => SliderRoot,
  Thumb: () => SliderThumb,
  Track: () => SliderTrack,
  Value: () => SliderValue
});

// node_modules/@base-ui/react/slider/root/SliderRoot.mjs
var React20 = __toESM(require_react(), 1);

// node_modules/@floating-ui/utils/dist/floating-ui.utils.dom.mjs
function hasWindow() {
  return typeof window !== "undefined";
}
function getWindow(node) {
  var _node$ownerDocument;
  return (node == null || (_node$ownerDocument = node.ownerDocument) == null ? void 0 : _node$ownerDocument.defaultView) || window;
}
function isElement(value) {
  if (!hasWindow()) {
    return false;
  }
  return value instanceof Element || value instanceof getWindow(value).Element;
}
function isHTMLElement(value) {
  if (!hasWindow()) {
    return false;
  }
  return value instanceof HTMLElement || value instanceof getWindow(value).HTMLElement;
}
function isShadowRoot(value) {
  if (!hasWindow() || typeof ShadowRoot === "undefined") {
    return false;
  }
  return value instanceof ShadowRoot || value instanceof getWindow(value).ShadowRoot;
}

// node_modules/@base-ui/utils/owner.mjs
function ownerDocument(node) {
  return node?.ownerDocument || document;
}

// node_modules/@base-ui/utils/useControlled.mjs
var React4 = __toESM(require_react(), 1);

// node_modules/@base-ui/utils/error.mjs
var set;
if (true) {
  set = /* @__PURE__ */ new Set();
}
function error(...messages) {
  if (true) {
    const messageKey = messages.join(" ");
    if (!set.has(messageKey)) {
      set.add(messageKey);
      console.error(`Base UI: ${messageKey}`);
    }
  }
}

// node_modules/@base-ui/utils/useControlled.mjs
function useControlled({
  controlled,
  default: defaultProp,
  name,
  state = "value"
}) {
  const {
    current: isControlled
  } = React4.useRef(controlled !== void 0);
  const [valueState, setValue] = React4.useState(defaultProp);
  const value = isControlled ? controlled : valueState;
  if (true) {
    React4.useEffect(() => {
      if (isControlled !== (controlled !== void 0)) {
        error([`A component is changing the ${isControlled ? "" : "un"}controlled ${state} state of ${name} to be ${isControlled ? "un" : ""}controlled.`, "Elements should not switch from uncontrolled to controlled (or vice versa).", `Decide between using a controlled or uncontrolled ${name} element for the lifetime of the component.`, "The nature of the state is determined during the first render. It's considered controlled if the value is not `undefined`.", "More info: https://fb.me/react-controlled-components"].join("\n"));
      }
    }, [state, name, controlled]);
    const {
      current: defaultValue
    } = React4.useRef(defaultProp);
    React4.useEffect(() => {
      if (!isControlled && serializeToDevModeString(defaultValue) !== serializeToDevModeString(defaultProp)) {
        error([`A component is changing the default ${state} state of an uncontrolled ${name} after being initialized. To suppress this warning opt to use a controlled ${name}.`].join("\n"));
      }
    }, [defaultProp]);
  }
  const setValueIfUncontrolled = React4.useCallback((newValue) => {
    if (!isControlled) {
      setValue(newValue);
    }
  }, []);
  return [value, setValueIfUncontrolled];
}
function serializeToDevModeString(input) {
  let nextId = 0;
  const seen = /* @__PURE__ */ new WeakMap();
  try {
    const result = JSON.stringify(input, function replacer(key, value) {
      if (key === "_owner" && this != null && typeof this === "object" && "$$typeof" in this) {
        return void 0;
      }
      if (typeof value === "bigint") {
        return `__bigint__:${value}`;
      }
      if (value !== null && typeof value === "object") {
        const id = seen.get(value);
        if (id !== void 0) {
          return `__object__:${id}`;
        }
        seen.set(value, nextId);
        nextId += 1;
      }
      return value;
    });
    return result ?? `__top__:${typeof input}`;
  } catch {
    return "__unserializable__";
  }
}

// node_modules/@base-ui/utils/safeReact.mjs
var React5 = __toESM(require_react(), 1);
var SafeReact = {
  ...React5
};

// node_modules/@base-ui/utils/useRefWithInit.mjs
var React6 = __toESM(require_react(), 1);
var UNINITIALIZED = {};
function useRefWithInit(init, initArg) {
  const ref = React6.useRef(UNINITIALIZED);
  if (ref.current === UNINITIALIZED) {
    ref.current = init(initArg);
  }
  return ref;
}

// node_modules/@base-ui/utils/useStableCallback.mjs
var useInsertionEffect = SafeReact.useInsertionEffect;
var useSafeInsertionEffect = (
  // React 17 doesn't have useInsertionEffect.
  useInsertionEffect && // Preact replaces useInsertionEffect with useLayoutEffect and fires too late.
  useInsertionEffect !== SafeReact.useLayoutEffect ? useInsertionEffect : (fn) => fn()
);
function useStableCallback(callback) {
  const stable = useRefWithInit(createStableCallback).current;
  stable.next = callback;
  useSafeInsertionEffect(stable.effect);
  return stable.trampoline;
}
function createStableCallback() {
  const stable = {
    next: void 0,
    callback: assertNotCalled,
    trampoline: (...args) => stable.callback?.(...args),
    effect: () => {
      stable.callback = stable.next;
    }
  };
  return stable;
}
function assertNotCalled() {
  if (true) {
    throw (
      /* minify-error-disabled */
      new Error("Base UI: Cannot call an event handler while rendering.")
    );
  }
}

// node_modules/@base-ui/utils/useIsoLayoutEffect.mjs
var React7 = __toESM(require_react(), 1);
var noop = () => {
};
var useIsoLayoutEffect = typeof document !== "undefined" ? React7.useLayoutEffect : noop;

// node_modules/@base-ui/utils/useValueAsRef.mjs
function useValueAsRef(value) {
  const latest = useRefWithInit(createLatestRef, value).current;
  latest.next = value;
  useIsoLayoutEffect(latest.effect);
  return latest;
}
function createLatestRef(value) {
  const latest = {
    current: value,
    next: value,
    effect: () => {
      latest.current = latest.next;
    }
  };
  return latest;
}

// node_modules/@base-ui/utils/warn.mjs
var set2;
if (true) {
  set2 = /* @__PURE__ */ new Set();
}
function warn(...messages) {
  if (true) {
    const messageKey = messages.join(" ");
    if (!set2.has(messageKey)) {
      set2.add(messageKey);
      console.warn(`Base UI: ${messageKey}`);
    }
  }
}

// node_modules/@base-ui/utils/empty.mjs
function NOOP() {
}
var EMPTY_ARRAY = Object.freeze([]);
var EMPTY_OBJECT = Object.freeze({});

// node_modules/@base-ui/react/internals/reason-parts.mjs
var reason_parts_exports = {};
__export(reason_parts_exports, {
  cancelOpen: () => cancelOpen,
  chipRemovePress: () => chipRemovePress,
  clearPress: () => clearPress,
  closePress: () => closePress,
  closeWatcher: () => closeWatcher,
  decrementPress: () => decrementPress,
  disabled: () => disabled,
  drag: () => drag,
  escapeKey: () => escapeKey,
  focusOut: () => focusOut,
  imperativeAction: () => imperativeAction,
  incrementPress: () => incrementPress,
  initial: () => initial,
  inputBlur: () => inputBlur,
  inputChange: () => inputChange,
  inputClear: () => inputClear,
  inputPaste: () => inputPaste,
  inputPress: () => inputPress,
  itemPress: () => itemPress,
  keyboard: () => keyboard,
  linkPress: () => linkPress,
  listNavigation: () => listNavigation,
  missing: () => missing,
  none: () => none,
  outsidePress: () => outsidePress,
  pointer: () => pointer,
  scrub: () => scrub,
  siblingOpen: () => siblingOpen,
  swipe: () => swipe,
  trackPress: () => trackPress,
  triggerFocus: () => triggerFocus,
  triggerHover: () => triggerHover,
  triggerPress: () => triggerPress,
  wheel: () => wheel,
  windowResize: () => windowResize
});
var none = "none";
var triggerPress = "trigger-press";
var triggerHover = "trigger-hover";
var triggerFocus = "trigger-focus";
var outsidePress = "outside-press";
var itemPress = "item-press";
var closePress = "close-press";
var linkPress = "link-press";
var clearPress = "clear-press";
var chipRemovePress = "chip-remove-press";
var trackPress = "track-press";
var incrementPress = "increment-press";
var decrementPress = "decrement-press";
var inputChange = "input-change";
var inputClear = "input-clear";
var inputBlur = "input-blur";
var inputPaste = "input-paste";
var inputPress = "input-press";
var focusOut = "focus-out";
var escapeKey = "escape-key";
var closeWatcher = "close-watcher";
var listNavigation = "list-navigation";
var keyboard = "keyboard";
var pointer = "pointer";
var drag = "drag";
var wheel = "wheel";
var scrub = "scrub";
var cancelOpen = "cancel-open";
var siblingOpen = "sibling-open";
var disabled = "disabled";
var missing = "missing";
var initial = "initial";
var imperativeAction = "imperative-action";
var swipe = "swipe";
var windowResize = "window-resize";

// node_modules/@base-ui/react/internals/createBaseUIEventDetails.mjs
function createChangeEventDetails(reason, event, trigger, customProperties) {
  let canceled = false;
  let allowPropagation = false;
  const custom = customProperties ?? EMPTY_OBJECT;
  const details = {
    reason,
    event: event ?? new Event("base-ui"),
    cancel() {
      canceled = true;
    },
    allowPropagation() {
      allowPropagation = true;
    },
    get isCanceled() {
      return canceled;
    },
    get isPropagationAllowed() {
      return allowPropagation;
    },
    trigger,
    ...custom
  };
  return details;
}
function createGenericEventDetails(reason, event, customProperties) {
  const custom = customProperties ?? EMPTY_OBJECT;
  const details = {
    reason,
    event: event ?? new Event("base-ui"),
    ...custom
  };
  return details;
}

// node_modules/@base-ui/react/internals/useValueChanged.mjs
var React8 = __toESM(require_react(), 1);
function useValueChanged(value, onChange) {
  const valueRef = React8.useRef(value);
  const onChangeCallback = useStableCallback(onChange);
  useIsoLayoutEffect(() => {
    if (valueRef.current === value) {
      return;
    }
    onChangeCallback(valueRef.current);
  }, [value, onChangeCallback]);
  useIsoLayoutEffect(() => {
    valueRef.current = value;
  }, [value]);
}

// node_modules/@base-ui/utils/useId.mjs
var React9 = __toESM(require_react(), 1);
var globalId = 0;
function useGlobalId(idOverride, prefix = "mui") {
  const [defaultId, setDefaultId] = React9.useState(idOverride);
  const id = idOverride || defaultId;
  React9.useEffect(() => {
    if (defaultId == null) {
      globalId += 1;
      setDefaultId(`${prefix}-${globalId}`);
    }
  }, [defaultId, prefix]);
  return id;
}
var maybeReactUseId = SafeReact.useId;
function useId(idOverride, prefix) {
  if (maybeReactUseId !== void 0) {
    const reactId = maybeReactUseId();
    return idOverride ?? (prefix ? `${prefix}-${reactId}` : reactId);
  }
  return useGlobalId(idOverride, prefix);
}

// node_modules/@base-ui/react/internals/useBaseUiId.mjs
function useBaseUiId(idOverride) {
  return useId(idOverride, "base-ui");
}

// node_modules/@base-ui/react/internals/useRenderElement.mjs
var React12 = __toESM(require_react(), 1);

// node_modules/@base-ui/utils/useMergedRefs.mjs
function useMergedRefs(a, b, c, d) {
  const forkRef = useRefWithInit(createForkRef).current;
  if (didChange(forkRef, a, b, c, d)) {
    update(forkRef, [a, b, c, d]);
  }
  return forkRef.callback;
}
function useMergedRefsN(refs) {
  const forkRef = useRefWithInit(createForkRef).current;
  if (didChangeN(forkRef, refs)) {
    update(forkRef, refs);
  }
  return forkRef.callback;
}
function createForkRef() {
  return {
    callback: null,
    cleanup: null,
    refs: []
  };
}
function didChange(forkRef, a, b, c, d) {
  return forkRef.refs[0] !== a || forkRef.refs[1] !== b || forkRef.refs[2] !== c || forkRef.refs[3] !== d;
}
function didChangeN(forkRef, newRefs) {
  return forkRef.refs.length !== newRefs.length || forkRef.refs.some((ref, index) => ref !== newRefs[index]);
}
function update(forkRef, refs) {
  forkRef.refs = refs;
  if (refs.every((ref) => ref == null)) {
    forkRef.callback = null;
    return;
  }
  forkRef.callback = (instance) => {
    if (forkRef.cleanup) {
      forkRef.cleanup();
      forkRef.cleanup = null;
    }
    if (instance != null) {
      const cleanupCallbacks = Array(refs.length).fill(null);
      for (let i = 0; i < refs.length; i += 1) {
        const ref = refs[i];
        if (ref == null) {
          continue;
        }
        switch (typeof ref) {
          case "function": {
            const refCleanup = ref(instance);
            if (typeof refCleanup === "function") {
              cleanupCallbacks[i] = refCleanup;
            }
            break;
          }
          case "object": {
            ref.current = instance;
            break;
          }
          default:
        }
      }
      forkRef.cleanup = () => {
        for (let i = 0; i < refs.length; i += 1) {
          const ref = refs[i];
          if (ref == null) {
            continue;
          }
          switch (typeof ref) {
            case "function": {
              const cleanupCallback = cleanupCallbacks[i];
              if (typeof cleanupCallback === "function") {
                cleanupCallback();
              } else {
                ref(null);
              }
              break;
            }
            case "object": {
              ref.current = null;
              break;
            }
            default:
          }
        }
      };
    }
  };
}

// node_modules/@base-ui/utils/getReactElementRef.mjs
var React11 = __toESM(require_react(), 1);

// node_modules/@base-ui/utils/reactVersion.mjs
var React10 = __toESM(require_react(), 1);
var majorVersion = parseInt(React10.version, 10);
function isReactVersionAtLeast(reactVersionToCheck) {
  return majorVersion >= reactVersionToCheck;
}

// node_modules/@base-ui/utils/getReactElementRef.mjs
function getReactElementRef(element) {
  if (!/* @__PURE__ */ React11.isValidElement(element)) {
    return null;
  }
  const reactElement = element;
  const propsWithRef = reactElement.props;
  return (isReactVersionAtLeast(19) ? propsWithRef?.ref : reactElement.ref) ?? null;
}

// node_modules/@base-ui/utils/mergeObjects.mjs
function mergeObjects(a, b) {
  if (a && !b) {
    return a;
  }
  if (!a && b) {
    return b;
  }
  if (a || b) {
    return {
      ...a,
      ...b
    };
  }
  return void 0;
}

// node_modules/@base-ui/react/internals/getStateAttributesProps.mjs
function getStateAttributesProps(state, customMapping) {
  const props = {};
  for (const key in state) {
    const value = state[key];
    if (customMapping?.hasOwnProperty(key)) {
      const customProps = customMapping[key](value);
      if (customProps != null) {
        Object.assign(props, customProps);
      }
      continue;
    }
    if (value === true) {
      props[`data-${key.toLowerCase()}`] = "";
    } else if (value) {
      props[`data-${key.toLowerCase()}`] = value.toString();
    }
  }
  return props;
}

// node_modules/@base-ui/react/utils/resolveClassName.mjs
function resolveClassName(className, state) {
  return typeof className === "function" ? className(state) : className;
}

// node_modules/@base-ui/react/utils/resolveStyle.mjs
function resolveStyle(style, state) {
  return typeof style === "function" ? style(state) : style;
}

// node_modules/@base-ui/react/merge-props/mergeProps.mjs
var EMPTY_PROPS = {};
function mergeProps(a, b, c, d, e) {
  if (!c && !d && !e && !a) {
    return createInitialMergedProps(b);
  }
  let merged = createInitialMergedProps(a);
  if (b) {
    merged = mergeInto(merged, b);
  }
  if (c) {
    merged = mergeInto(merged, c);
  }
  if (d) {
    merged = mergeInto(merged, d);
  }
  if (e) {
    merged = mergeInto(merged, e);
  }
  return merged;
}
function mergePropsN(props) {
  if (props.length === 0) {
    return EMPTY_PROPS;
  }
  if (props.length === 1) {
    return createInitialMergedProps(props[0]);
  }
  let merged = createInitialMergedProps(props[0]);
  for (let i = 1; i < props.length; i += 1) {
    merged = mergeInto(merged, props[i]);
  }
  return merged;
}
function createInitialMergedProps(inputProps) {
  if (isPropsGetter(inputProps)) {
    return {
      ...resolvePropsGetter(inputProps, EMPTY_PROPS)
    };
  }
  return copyInitialProps(inputProps);
}
function mergeInto(merged, inputProps) {
  if (isPropsGetter(inputProps)) {
    return resolvePropsGetter(inputProps, merged);
  }
  return mutablyMergeInto(merged, inputProps);
}
function copyInitialProps(inputProps) {
  const copiedProps = {
    ...inputProps
  };
  for (const propName in copiedProps) {
    const propValue = copiedProps[propName];
    if (isEventHandler(propName, propValue)) {
      copiedProps[propName] = wrapEventHandler(propValue);
    }
  }
  return copiedProps;
}
function mutablyMergeInto(mergedProps, externalProps) {
  if (!externalProps) {
    return mergedProps;
  }
  for (const propName in externalProps) {
    const externalPropValue = externalProps[propName];
    switch (propName) {
      case "style": {
        mergedProps[propName] = mergeObjects(mergedProps.style, externalPropValue);
        break;
      }
      case "className": {
        mergedProps[propName] = mergeClassNames(mergedProps.className, externalPropValue);
        break;
      }
      default: {
        if (isEventHandler(propName, externalPropValue)) {
          mergedProps[propName] = mergeEventHandlers(mergedProps[propName], externalPropValue);
        } else {
          mergedProps[propName] = externalPropValue;
        }
      }
    }
  }
  return mergedProps;
}
function isEventHandler(key, value) {
  const code0 = key.charCodeAt(0);
  const code1 = key.charCodeAt(1);
  const code2 = key.charCodeAt(2);
  return code0 === 111 && code1 === 110 && code2 >= 65 && code2 <= 90 && (typeof value === "function" || typeof value === "undefined");
}
function isPropsGetter(inputProps) {
  return typeof inputProps === "function";
}
function resolvePropsGetter(inputProps, previousProps) {
  if (isPropsGetter(inputProps)) {
    return inputProps(previousProps);
  }
  return inputProps ?? EMPTY_PROPS;
}
function mergeEventHandlers(ourHandler, theirHandler) {
  if (!theirHandler) {
    return ourHandler;
  }
  if (!ourHandler) {
    return wrapEventHandler(theirHandler);
  }
  return (...args) => {
    const event = args[0];
    if (isSyntheticEvent(event)) {
      const baseUIEvent = event;
      makeEventPreventable(baseUIEvent);
      const result2 = theirHandler(...args);
      if (!baseUIEvent.baseUIHandlerPrevented) {
        ourHandler?.(...args);
      }
      return result2;
    }
    const result = theirHandler(...args);
    ourHandler?.(...args);
    return result;
  };
}
function wrapEventHandler(handler) {
  if (!handler) {
    return handler;
  }
  return (...args) => {
    const event = args[0];
    if (isSyntheticEvent(event)) {
      makeEventPreventable(event);
    }
    return handler(...args);
  };
}
function makeEventPreventable(event) {
  event.preventBaseUIHandler = () => {
    event.baseUIHandlerPrevented = true;
  };
  return event;
}
function mergeClassNames(ourClassName, theirClassName) {
  if (theirClassName) {
    if (ourClassName) {
      return theirClassName + " " + ourClassName;
    }
    return theirClassName;
  }
  return ourClassName;
}
function isSyntheticEvent(event) {
  return event != null && typeof event === "object" && "nativeEvent" in event;
}

// node_modules/@base-ui/react/internals/useRenderElement.mjs
var import_react4 = __toESM(require_react(), 1);
function useRenderElement(element, componentProps, params = {}) {
  const renderProp = componentProps.render;
  const outProps = useRenderElementProps(componentProps, params);
  if (params.enabled === false) {
    return null;
  }
  const state = params.state ?? EMPTY_OBJECT;
  return evaluateRenderProp(element, renderProp, outProps, state);
}
function useRenderElementProps(componentProps, params = {}) {
  const {
    className: classNameProp,
    style: styleProp,
    render: renderProp
  } = componentProps;
  const {
    state = EMPTY_OBJECT,
    ref,
    props,
    stateAttributesMapping,
    enabled = true
  } = params;
  const className = enabled ? resolveClassName(classNameProp, state) : void 0;
  const style = enabled ? resolveStyle(styleProp, state) : void 0;
  const stateProps = enabled ? getStateAttributesProps(state, stateAttributesMapping) : EMPTY_OBJECT;
  const resolvedProps = enabled && props ? resolveRenderFunctionProps(props) : void 0;
  const outProps = enabled ? mergeObjects(stateProps, resolvedProps) ?? {} : EMPTY_OBJECT;
  if (typeof document !== "undefined") {
    if (!enabled) {
      useMergedRefs(null, null);
    } else if (Array.isArray(ref)) {
      outProps.ref = useMergedRefsN([outProps.ref, getReactElementRef(renderProp), ...ref]);
    } else {
      outProps.ref = useMergedRefs(outProps.ref, getReactElementRef(renderProp), ref);
    }
  }
  if (!enabled) {
    return EMPTY_OBJECT;
  }
  if (className !== void 0) {
    outProps.className = mergeClassNames(outProps.className, className);
  }
  if (style !== void 0) {
    outProps.style = mergeObjects(outProps.style, style);
  }
  return outProps;
}
function resolveRenderFunctionProps(props) {
  if (Array.isArray(props)) {
    return mergePropsN(props);
  }
  return mergeProps(void 0, props);
}
var REACT_LAZY_TYPE = Symbol.for("react.lazy");
var COMPONENT_IDENTIFIER_PATTERN = /^[A-Z][A-Za-z0-9$]*$/;
var LOWERCASE_CHARACTER_PATTERN = /[a-z]/;
function evaluateRenderProp(element, render, props, state) {
  if (render) {
    if (typeof render === "function") {
      if (true) {
        warnIfRenderPropLooksLikeComponent(render);
      }
      return render(props, state);
    }
    const mergedProps = mergeProps(props, render.props);
    mergedProps.ref = props.ref;
    let newElement = render;
    if (newElement?.$$typeof === REACT_LAZY_TYPE) {
      const children = React12.Children.toArray(render);
      newElement = children[0];
    }
    if (true) {
      if (!/* @__PURE__ */ React12.isValidElement(newElement)) {
        throw new Error(["Base UI: The `render` prop was provided an invalid React element as `React.isValidElement(render)` is `false`.", "A valid React element must be provided to the `render` prop because it is cloned with props to replace the default element.", "https://base-ui.com/r/invalid-render-prop"].join("\n"));
      }
    }
    return /* @__PURE__ */ React12.cloneElement(newElement, mergedProps);
  }
  if (element) {
    if (typeof element === "string") {
      return renderTag(element, props);
    }
  }
  throw new Error(true ? "Base UI: Render element or function are not defined." : formatErrorMessage_default(8));
}
function warnIfRenderPropLooksLikeComponent(renderFn) {
  const functionName = renderFn.name;
  if (functionName.length === 0) {
    return;
  }
  if (!COMPONENT_IDENTIFIER_PATTERN.test(functionName)) {
    return;
  }
  if (!LOWERCASE_CHARACTER_PATTERN.test(functionName)) {
    return;
  }
  warn(`The \`render\` prop received a function named \`${functionName}\` that starts with an uppercase letter.`, "This usually means a React component was passed directly as `render={Component}`.", "Base UI calls `render` as a plain function, which can break the Rules of Hooks during reconciliation.", "If this is an intentional render callback, rename it to start with a lowercase letter.", "Use `render={<Component />}` or `render={(props) => <Component {...props} />}` instead.", "https://base-ui.com/r/invalid-render-prop");
}
function renderTag(Tag, props) {
  if (Tag === "button") {
    return /* @__PURE__ */ (0, import_react4.createElement)("button", {
      type: "button",
      ...props,
      key: props.key
    });
  }
  if (Tag === "img") {
    return /* @__PURE__ */ (0, import_react4.createElement)("img", {
      alt: "",
      ...props,
      key: props.key
    });
  }
  return /* @__PURE__ */ React12.createElement(Tag, props);
}

// node_modules/@base-ui/react/internals/clamp.mjs
function clamp(val, min = Number.MIN_SAFE_INTEGER, max = Number.MAX_SAFE_INTEGER) {
  return Math.max(min, Math.min(val, max));
}

// node_modules/@base-ui/react/internals/areArraysEqual.mjs
function areArraysEqual(array1, array2, itemComparer = (a, b) => a === b) {
  return array1.length === array2.length && array1.every((value, index) => itemComparer(value, array2[index]));
}

// node_modules/@base-ui/utils/platform/parts.mjs
var parts_exports = {};
__export(parts_exports, {
  engine: () => engine_exports,
  env: () => env_exports,
  os: () => os_exports,
  screenReader: () => screen_reader_exports
});

// node_modules/@base-ui/utils/platform/os.mjs
var os_exports = {};
__export(os_exports, {
  android: () => android,
  apple: () => apple,
  ios: () => ios,
  linux: () => linux,
  mac: () => mac,
  windows: () => windows
});

// node_modules/@base-ui/utils/platform/shared.mjs
function readRawData() {
  if (typeof navigator === "undefined") {
    return {
      userAgent: "",
      platform: "",
      maxTouchPoints: 0
    };
  }
  if (true) {
    const uaData = navigator.userAgentData;
    if (uaData && Array.isArray(uaData.brands)) {
      return {
        userAgent: uaData.brands.map(({
          brand,
          version: version2
        }) => `${brand}/${version2}`).join(" "),
        platform: uaData.platform ?? navigator.platform ?? "",
        maxTouchPoints: navigator.maxTouchPoints ?? 0
      };
    }
  }
  return {
    userAgent: navigator.userAgent,
    platform: navigator.platform ?? "",
    maxTouchPoints: navigator.maxTouchPoints ?? 0
  };
}
var {
  userAgent,
  platform,
  maxTouchPoints
} = readRawData();
var lowerUserAgent = userAgent.toLowerCase();
var lowerPlatform = platform.toLowerCase();

// node_modules/@base-ui/utils/platform/os.mjs
var ios = /^i(os$|p)/.test(lowerPlatform) || lowerPlatform === "macintel" && maxTouchPoints > 1;
var ANDROID_STRING = "android";
var android = lowerPlatform === ANDROID_STRING || lowerUserAgent.includes(ANDROID_STRING);
var mac = !ios && lowerPlatform.startsWith("mac");
var windows = lowerPlatform.startsWith("win");
var linux = !android && /^(linux|chrome os)/.test(lowerPlatform);
var apple = mac || ios;

// node_modules/@base-ui/utils/platform/engine.mjs
var engine_exports = {};
__export(engine_exports, {
  blink: () => blink,
  gecko: () => gecko,
  webkit: () => webkit
});
var webkit = typeof CSS !== "undefined" && !!CSS.supports?.("-webkit-backdrop-filter:none");
var gecko = !webkit && lowerUserAgent.includes("firefox");
var blink = !webkit && lowerUserAgent.includes("chrom");

// node_modules/@base-ui/utils/platform/screen-reader.mjs
var screen_reader_exports = {};
__export(screen_reader_exports, {
  voiceOver: () => voiceOver
});
var voiceOver = apple;

// node_modules/@base-ui/utils/platform/env.mjs
var env_exports = {};
__export(env_exports, {
  jsdom: () => jsdom
});
var jsdom = /jsdom|happydom/.test(lowerUserAgent);

// node_modules/@base-ui/react/internals/shadowDom.mjs
function activeElement(doc) {
  let element = doc.activeElement;
  while (element?.shadowRoot?.activeElement != null) {
    element = element.shadowRoot.activeElement;
  }
  return element;
}
function contains(parent, child) {
  if (!parent || !child) {
    return false;
  }
  const rootNode = child.getRootNode?.();
  if (parent.contains(child)) {
    return true;
  }
  if (rootNode && isShadowRoot(rootNode)) {
    let next = child;
    while (next) {
      if (parent === next) {
        return true;
      }
      next = next.parentNode || next.host;
    }
  }
  return false;
}
function getTarget(event) {
  if ("composedPath" in event) {
    return event.composedPath()[0];
  }
  return event.target;
}

// node_modules/@base-ui/react/floating-ui-react/utils/element.mjs
function matchesFocusVisible(element) {
  if (!element || parts_exports.env.jsdom) {
    return true;
  }
  try {
    return element.matches(":focus-visible");
  } catch (_e) {
    return true;
  }
}

// node_modules/@base-ui/react/internals/composite/list/CompositeList.mjs
var React14 = __toESM(require_react(), 1);

// node_modules/@base-ui/react/internals/composite/list/CompositeListContext.mjs
var React13 = __toESM(require_react(), 1);
var CompositeListContext = /* @__PURE__ */ React13.createContext({
  register: () => {
  },
  unregister: () => {
  },
  subscribeMapChange: () => {
    return () => {
    };
  },
  elementsRef: {
    current: []
  },
  nextIndexRef: {
    current: 0
  }
});
if (true) CompositeListContext.displayName = "CompositeListContext";
function useCompositeListContext() {
  return React13.useContext(CompositeListContext);
}

// node_modules/@base-ui/react/internals/composite/list/CompositeList.mjs
var import_jsx_runtime4 = __toESM(require_jsx_runtime(), 1);
function CompositeList(props) {
  const {
    children,
    elementsRef,
    labelsRef,
    onMapChange: onMapChangeProp
  } = props;
  const onMapChange = useStableCallback(onMapChangeProp);
  const nextIndexRef = React14.useRef(0);
  const listeners = useRefWithInit(createListeners).current;
  const map = useRefWithInit(createMap).current;
  const [mapTick, setMapTick] = React14.useState(0);
  const lastTickRef = React14.useRef(mapTick);
  const register = useStableCallback((node, metadata) => {
    map.set(node, metadata ?? null);
    lastTickRef.current += 1;
    setMapTick(lastTickRef.current);
  });
  const unregister = useStableCallback((node) => {
    map.delete(node);
    lastTickRef.current += 1;
    setMapTick(lastTickRef.current);
  });
  const sortedMap = React14.useMemo(() => {
    disableEslintWarning(mapTick);
    const newMap = /* @__PURE__ */ new Map();
    const sortedNodes = Array.from(map.keys()).filter((node) => node.isConnected).sort(sortByDocumentPosition);
    sortedNodes.forEach((node, index) => {
      const metadata = map.get(node) ?? {};
      newMap.set(node, {
        ...metadata,
        index
      });
    });
    return newMap;
  }, [map, mapTick]);
  useIsoLayoutEffect(() => {
    if (typeof MutationObserver !== "function" || sortedMap.size === 0) {
      return void 0;
    }
    const mutationObserver = new MutationObserver((entries) => {
      const diff = /* @__PURE__ */ new Set();
      const updateDiff = (node) => diff.has(node) ? diff.delete(node) : diff.add(node);
      entries.forEach((entry) => {
        entry.removedNodes.forEach(updateDiff);
        entry.addedNodes.forEach(updateDiff);
      });
      if (diff.size === 0) {
        lastTickRef.current += 1;
        setMapTick(lastTickRef.current);
      }
    });
    sortedMap.forEach((_, node) => {
      if (node.parentElement) {
        mutationObserver.observe(node.parentElement, {
          childList: true
        });
      }
    });
    return () => {
      mutationObserver.disconnect();
    };
  }, [sortedMap]);
  useIsoLayoutEffect(() => {
    const shouldUpdateLengths = lastTickRef.current === mapTick;
    if (shouldUpdateLengths) {
      if (elementsRef.current.length !== sortedMap.size) {
        elementsRef.current.length = sortedMap.size;
      }
      if (labelsRef && labelsRef.current.length !== sortedMap.size) {
        labelsRef.current.length = sortedMap.size;
      }
      nextIndexRef.current = sortedMap.size;
    }
    onMapChange(sortedMap);
  }, [onMapChange, sortedMap, elementsRef, labelsRef, mapTick]);
  useIsoLayoutEffect(() => {
    return () => {
      elementsRef.current = [];
    };
  }, [elementsRef]);
  useIsoLayoutEffect(() => {
    return () => {
      if (labelsRef) {
        labelsRef.current = [];
      }
    };
  }, [labelsRef]);
  const subscribeMapChange = useStableCallback((fn) => {
    listeners.add(fn);
    return () => {
      listeners.delete(fn);
    };
  });
  useIsoLayoutEffect(() => {
    listeners.forEach((l) => l(sortedMap));
  }, [listeners, sortedMap]);
  const contextValue = React14.useMemo(() => ({
    register,
    unregister,
    subscribeMapChange,
    elementsRef,
    labelsRef,
    nextIndexRef
  }), [register, unregister, subscribeMapChange, elementsRef, labelsRef, nextIndexRef]);
  return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(CompositeListContext.Provider, {
    value: contextValue,
    children
  });
}
function createMap() {
  return /* @__PURE__ */ new Map();
}
function createListeners() {
  return /* @__PURE__ */ new Set();
}
function sortByDocumentPosition(a, b) {
  const position = a.compareDocumentPosition(b);
  if (position & Node.DOCUMENT_POSITION_FOLLOWING || position & Node.DOCUMENT_POSITION_CONTAINED_BY) {
    return -1;
  }
  if (position & Node.DOCUMENT_POSITION_PRECEDING || position & Node.DOCUMENT_POSITION_CONTAINS) {
    return 1;
  }
  return 0;
}
function disableEslintWarning(_) {
}

// node_modules/@base-ui/react/internals/field-root-context/FieldRootContext.mjs
var React15 = __toESM(require_react(), 1);

// node_modules/@base-ui/react/field/control/FieldControlDataAttributes.mjs
var FieldControlDataAttributes = /* @__PURE__ */ function(FieldControlDataAttributes2) {
  FieldControlDataAttributes2["disabled"] = "data-disabled";
  FieldControlDataAttributes2["valid"] = "data-valid";
  FieldControlDataAttributes2["invalid"] = "data-invalid";
  FieldControlDataAttributes2["touched"] = "data-touched";
  FieldControlDataAttributes2["dirty"] = "data-dirty";
  FieldControlDataAttributes2["filled"] = "data-filled";
  FieldControlDataAttributes2["focused"] = "data-focused";
  return FieldControlDataAttributes2;
}({});

// node_modules/@base-ui/react/internals/field-constants/constants.mjs
var DEFAULT_VALIDITY_STATE = {
  badInput: false,
  customError: false,
  patternMismatch: false,
  rangeOverflow: false,
  rangeUnderflow: false,
  stepMismatch: false,
  tooLong: false,
  tooShort: false,
  typeMismatch: false,
  valid: null,
  valueMissing: false
};
var DEFAULT_FIELD_STATE_ATTRIBUTES = {
  valid: null,
  touched: false,
  dirty: false,
  filled: false,
  focused: false
};
var DEFAULT_FIELD_ROOT_STATE = {
  disabled: false,
  ...DEFAULT_FIELD_STATE_ATTRIBUTES
};
var fieldValidityMapping = {
  valid(value) {
    if (value === null) {
      return null;
    }
    if (value) {
      return {
        [FieldControlDataAttributes.valid]: ""
      };
    }
    return {
      [FieldControlDataAttributes.invalid]: ""
    };
  }
};

// node_modules/@base-ui/react/internals/field-root-context/FieldRootContext.mjs
var DEFAULT_FIELD_ROOT_CONTEXT = {
  invalid: void 0,
  name: void 0,
  validityData: {
    state: DEFAULT_VALIDITY_STATE,
    errors: [],
    error: "",
    value: "",
    initialValue: null
  },
  setValidityData: NOOP,
  disabled: void 0,
  touched: DEFAULT_FIELD_STATE_ATTRIBUTES.touched,
  setTouched: NOOP,
  dirty: DEFAULT_FIELD_STATE_ATTRIBUTES.dirty,
  setDirty: NOOP,
  filled: DEFAULT_FIELD_STATE_ATTRIBUTES.filled,
  setFilled: NOOP,
  focused: DEFAULT_FIELD_STATE_ATTRIBUTES.focused,
  setFocused: NOOP,
  validate: () => null,
  validationMode: "onSubmit",
  validationDebounceTime: 0,
  shouldValidateOnChange: () => false,
  state: DEFAULT_FIELD_ROOT_STATE,
  markedDirtyRef: {
    current: false
  },
  registerFieldControl: NOOP,
  validation: {
    getValidationProps: (_disabled, props = EMPTY_OBJECT) => props,
    inputRef: {
      current: null
    },
    registerInput: NOOP,
    commit: async () => {
    },
    change: NOOP
  }
};
var FieldRootContext = /* @__PURE__ */ React15.createContext(DEFAULT_FIELD_ROOT_CONTEXT);
if (true) FieldRootContext.displayName = "FieldRootContext";
function useFieldRootContext(optional = true) {
  const context = React15.useContext(FieldRootContext);
  if (context.setValidityData === NOOP && !optional) {
    throw new Error(true ? "Base UI: FieldRootContext is missing. Field parts must be placed within <Field.Root>." : formatErrorMessage_default(28));
  }
  return context;
}

// node_modules/@base-ui/react/internals/field-register-control/useRegisterFieldControl.mjs
var React16 = __toESM(require_react(), 1);
function useRegisterFieldControl(controlRef, id, value, getFormValueOverride, enabled = true, name) {
  const {
    registerFieldControl
  } = useFieldRootContext();
  const sourceRef = React16.useRef(null);
  if (!sourceRef.current) {
    sourceRef.current = Symbol();
  }
  useIsoLayoutEffect(() => {
    const source = sourceRef.current;
    if (!source || !enabled) {
      return void 0;
    }
    const registration = {
      controlRef,
      getValue: getFormValueOverride,
      id,
      name,
      value
    };
    registerFieldControl(source, registration);
    return () => {
      registerFieldControl(source, void 0);
    };
  }, [controlRef, enabled, getFormValueOverride, id, name, registerFieldControl, value]);
}

// node_modules/@base-ui/react/internals/form-context/FormContext.mjs
var React17 = __toESM(require_react(), 1);
var FormContext = /* @__PURE__ */ React17.createContext({
  formRef: {
    current: {
      fields: /* @__PURE__ */ new Map()
    }
  },
  errors: {},
  clearErrors: NOOP,
  validationMode: "onSubmit",
  submitAttemptedRef: {
    current: false
  }
});
if (true) FormContext.displayName = "FormContext";
function useFormContext() {
  return React17.useContext(FormContext);
}

// node_modules/@base-ui/react/internals/labelable-provider/LabelableContext.mjs
var React18 = __toESM(require_react(), 1);
var LabelableContext = /* @__PURE__ */ React18.createContext({
  controlId: void 0,
  registerControlId: NOOP,
  labelId: void 0,
  setLabelId: NOOP,
  messageIds: [],
  setMessageIds: NOOP,
  getDescriptionProps: (externalProps) => externalProps
});
if (true) LabelableContext.displayName = "LabelableContext";
function useLabelableContext() {
  return React18.useContext(LabelableContext);
}

// node_modules/@base-ui/react/utils/resolveAriaLabelledBy.mjs
function getDefaultLabelId(id) {
  return id == null ? void 0 : `${id}-label`;
}
function resolveAriaLabelledBy(fieldLabelId, localLabelId) {
  return fieldLabelId ?? localLabelId;
}

// node_modules/@base-ui/react/slider/utils/asc.mjs
function asc(a, b) {
  return a - b;
}

// node_modules/@base-ui/react/slider/utils/replaceArrayItemAtIndex.mjs
function replaceArrayItemAtIndex(array, index, newValue) {
  const output = array.slice();
  output[index] = newValue;
  return output.sort(asc);
}

// node_modules/@base-ui/react/slider/utils/getSliderValue.mjs
function getSliderValue(valueInput, index, min, max, range, values) {
  let newValue = valueInput;
  newValue = clamp(newValue, min, max);
  if (range) {
    newValue = replaceArrayItemAtIndex(
      values,
      index,
      // Bound the new value to the thumb's neighbours.
      clamp(newValue, values[index - 1] ?? -Infinity, values[index + 1] ?? Infinity)
    );
  }
  return newValue;
}

// node_modules/@base-ui/react/slider/utils/validateMinimumDistance.mjs
function validateMinimumDistance(values, step, minStepsBetweenValues) {
  if (!Array.isArray(values)) {
    return true;
  }
  const distances = values.reduce((acc, val, index, vals) => {
    if (index === vals.length - 1) {
      return acc;
    }
    acc.push(Math.abs(val - vals[index + 1]));
    return acc;
  }, []);
  return Math.min(...distances) >= step * minStepsBetweenValues;
}

// node_modules/@base-ui/react/slider/root/stateAttributesMapping.mjs
var sliderStateAttributesMapping = {
  activeThumbIndex: () => null,
  max: () => null,
  min: () => null,
  minStepsBetweenValues: () => null,
  step: () => null,
  values: () => null,
  ...fieldValidityMapping
};

// node_modules/@base-ui/react/slider/root/SliderRootContext.mjs
var React19 = __toESM(require_react(), 1);
var SliderRootContext = /* @__PURE__ */ React19.createContext(void 0);
if (true) SliderRootContext.displayName = "SliderRootContext";
function useSliderRootContext() {
  const context = React19.useContext(SliderRootContext);
  if (context === void 0) {
    throw new Error(true ? "Base UI: SliderRootContext is missing. Slider parts must be placed within <Slider.Root>." : formatErrorMessage_default(62));
  }
  return context;
}

// node_modules/@base-ui/react/slider/root/SliderRoot.mjs
var import_jsx_runtime5 = __toESM(require_jsx_runtime(), 1);
function getSliderChangeEventReason(event) {
  return "key" in event ? reason_parts_exports.keyboard : reason_parts_exports.inputChange;
}
function areValuesEqual(newValue, oldValue) {
  if (typeof newValue === "number" && typeof oldValue === "number") {
    return newValue === oldValue;
  }
  if (Array.isArray(newValue) && Array.isArray(oldValue)) {
    return areArraysEqual(newValue, oldValue);
  }
  return false;
}
var SliderRoot = /* @__PURE__ */ React20.forwardRef(function SliderRoot2(componentProps, forwardedRef) {
  const {
    "aria-labelledby": ariaLabelledByProp,
    className,
    defaultValue,
    disabled: disabledProp = false,
    id: idProp,
    format,
    largeStep = 10,
    locale,
    render,
    max = 100,
    min = 0,
    minStepsBetweenValues = 0,
    form,
    name: nameProp,
    onValueChange: onValueChangeProp,
    onValueCommitted: onValueCommittedProp,
    orientation = "horizontal",
    step = 1,
    thumbCollisionBehavior = "push",
    thumbAlignment = "center",
    value: valueProp,
    style,
    ...elementProps
  } = componentProps;
  const id = useBaseUiId(idProp);
  const defaultLabelId = getDefaultLabelId(id);
  const onValueChange = useStableCallback(onValueChangeProp);
  const onValueCommitted = useStableCallback(onValueCommittedProp);
  const {
    clearErrors
  } = useFormContext();
  const {
    state: fieldState,
    disabled: fieldDisabled,
    name: fieldName,
    setTouched,
    setDirty,
    validityData,
    validation
  } = useFieldRootContext();
  const {
    labelId: fieldLabelId
  } = useLabelableContext();
  const [labelId, setLabelId] = React20.useState();
  const ariaLabelledby = ariaLabelledByProp ?? resolveAriaLabelledBy(fieldLabelId, labelId);
  const disabled2 = fieldDisabled || disabledProp;
  const name = fieldName ?? nameProp;
  const [valueUnwrapped, setValueUnwrapped] = useControlled({
    controlled: valueProp,
    default: defaultValue ?? min,
    name: "Slider"
  });
  const sliderRef = React20.useRef(null);
  const controlRef = React20.useRef(null);
  const thumbRefs = React20.useRef([]);
  const pressedInputRef = React20.useRef(null);
  const pressedThumbCenterOffsetRef = React20.useRef(null);
  const pressedThumbIndexRef = React20.useRef(-1);
  const pressedValuesRef = React20.useRef(null);
  const lastChangeReasonRef = React20.useRef("none");
  const formatOptionsRef = useValueAsRef(format);
  const [active, setActiveState] = React20.useState(-1);
  const [lastUsedThumbIndex, setLastUsedThumbIndex] = React20.useState(-1);
  const [dragging, setDragging] = React20.useState(false);
  const [thumbMap, setThumbMap] = React20.useState(() => /* @__PURE__ */ new Map());
  const [indicatorPosition, setIndicatorPosition] = React20.useState([void 0, void 0]);
  const setActive = useStableCallback((value) => {
    setActiveState(value);
    if (value !== -1) {
      setLastUsedThumbIndex(value);
    }
  });
  useRegisterFieldControl(validation.inputRef, id, valueUnwrapped, void 0, !disabled2, nameProp);
  useValueChanged(valueUnwrapped, () => {
    clearErrors(name);
    validation.change(valueUnwrapped);
    const initialValue = validityData.initialValue;
    let isDirty;
    if (Array.isArray(valueUnwrapped) && Array.isArray(initialValue)) {
      isDirty = !areArraysEqual(valueUnwrapped, initialValue);
    } else {
      isDirty = valueUnwrapped !== initialValue;
    }
    setDirty(isDirty);
  });
  const registerFieldControlRef = useStableCallback((element2) => {
    if (element2) {
      controlRef.current = element2;
    }
  });
  const range = Array.isArray(valueUnwrapped);
  const values = React20.useMemo(() => {
    if (!range) {
      return [clamp(valueUnwrapped, min, max)];
    }
    return valueUnwrapped.slice().sort(asc);
  }, [max, min, range, valueUnwrapped]);
  const setValue = useStableCallback((newValue, details) => {
    if (Number.isNaN(newValue) || areValuesEqual(newValue, valueUnwrapped)) {
      return false;
    }
    const changeDetails = details ?? createChangeEventDetails(reason_parts_exports.none, void 0, void 0, {
      activeThumbIndex: -1
    });
    const nativeEvent = changeDetails.event;
    const EventConstructor = nativeEvent.constructor ?? Event;
    const clonedEvent = new EventConstructor(nativeEvent.type, nativeEvent);
    Object.defineProperty(clonedEvent, "target", {
      writable: true,
      value: {
        value: newValue,
        name
      }
    });
    changeDetails.event = clonedEvent;
    onValueChange(newValue, changeDetails);
    if (changeDetails.isCanceled) {
      return false;
    }
    lastChangeReasonRef.current = changeDetails.reason;
    setValueUnwrapped(newValue);
    return true;
  });
  const handleInputChange = useStableCallback((valueInput, index, event) => {
    const newValue = getSliderValue(valueInput, index, min, max, range, values);
    if (validateMinimumDistance(newValue, step, minStepsBetweenValues)) {
      const reason = getSliderChangeEventReason(event);
      const applied = setValue(newValue, createChangeEventDetails(reason, event.nativeEvent, void 0, {
        activeThumbIndex: index
      }));
      setTouched(true);
      if (applied) {
        onValueCommitted(newValue, createGenericEventDetails(reason, event.nativeEvent));
      }
    }
  });
  if (true) {
    if (min >= max) {
      warn("Slider `max` must be greater than `min`.");
    }
  }
  useIsoLayoutEffect(() => {
    const activeEl = activeElement(ownerDocument(sliderRef.current));
    if (disabled2 && contains(sliderRef.current, activeEl)) {
      activeEl.blur();
    }
  }, [disabled2]);
  if (disabled2 && active !== -1) {
    setActive(-1);
  }
  const state = React20.useMemo(() => ({
    ...fieldState,
    activeThumbIndex: active,
    disabled: disabled2,
    dragging,
    orientation,
    max,
    min,
    minStepsBetweenValues,
    step,
    values
  }), [fieldState, active, disabled2, dragging, max, min, minStepsBetweenValues, orientation, step, values]);
  const contextValue = React20.useMemo(() => ({
    active,
    controlRef,
    disabled: disabled2,
    dragging,
    validation,
    formatOptionsRef,
    handleInputChange,
    indicatorPosition,
    inset: thumbAlignment !== "center",
    labelId: ariaLabelledby,
    rootLabelId: defaultLabelId,
    largeStep,
    lastUsedThumbIndex,
    lastChangeReasonRef,
    form,
    locale,
    max,
    min,
    minStepsBetweenValues,
    name,
    onValueCommitted,
    orientation,
    pressedInputRef,
    pressedThumbCenterOffsetRef,
    pressedThumbIndexRef,
    pressedValuesRef,
    registerFieldControlRef,
    renderBeforeHydration: thumbAlignment === "edge",
    setActive,
    setDragging,
    setIndicatorPosition,
    setLabelId,
    setValue,
    state,
    step,
    thumbCollisionBehavior,
    thumbMap,
    thumbRefs,
    values
  }), [active, controlRef, ariaLabelledby, defaultLabelId, disabled2, dragging, validation, formatOptionsRef, handleInputChange, indicatorPosition, largeStep, lastUsedThumbIndex, lastChangeReasonRef, form, locale, max, min, minStepsBetweenValues, name, onValueCommitted, orientation, pressedInputRef, pressedThumbCenterOffsetRef, pressedThumbIndexRef, pressedValuesRef, registerFieldControlRef, setActive, setDragging, setIndicatorPosition, setLabelId, setValue, state, step, thumbCollisionBehavior, thumbAlignment, thumbMap, thumbRefs, values]);
  const element = useRenderElement("div", componentProps, {
    state,
    ref: [forwardedRef, sliderRef],
    props: [{
      "aria-labelledby": ariaLabelledby,
      id,
      role: "group"
    }, elementProps, (props) => validation.getValidationProps(disabled2, props)],
    stateAttributesMapping: sliderStateAttributesMapping
  });
  return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(SliderRootContext.Provider, {
    value: contextValue,
    children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(CompositeList, {
      elementsRef: thumbRefs,
      onMapChange: setThumbMap,
      children: element
    })
  });
});
if (true) SliderRoot.displayName = "SliderRoot";

// node_modules/@base-ui/react/slider/label/SliderLabel.mjs
var React21 = __toESM(require_react(), 1);

// node_modules/@base-ui/react/utils/useRegisteredLabelId.mjs
function useRegisteredLabelId(idProp, setLabelId) {
  const id = useBaseUiId(idProp);
  useIsoLayoutEffect(() => {
    setLabelId(id);
    return () => {
      setLabelId(void 0);
    };
  }, [id, setLabelId]);
  return id;
}

// node_modules/@base-ui/react/internals/labelable-provider/useLabel.mjs
function useLabel(params = {}) {
  const {
    id: idProp,
    fallbackControlId,
    native = false,
    setLabelId: setLabelIdProp,
    focusControl: focusControlProp
  } = params;
  const {
    controlId: contextControlId,
    setLabelId: setContextLabelId
  } = useLabelableContext();
  const syncLabelId = useStableCallback((nextLabelId) => {
    setContextLabelId(nextLabelId);
    setLabelIdProp?.(nextLabelId);
  });
  const id = useRegisteredLabelId(idProp, syncLabelId);
  const resolvedControlId = contextControlId ?? fallbackControlId;
  function focusControl(event) {
    if (focusControlProp) {
      focusControlProp(event, resolvedControlId);
      return;
    }
    if (!resolvedControlId) {
      return;
    }
    const controlElement = ownerDocument(event.currentTarget).getElementById(resolvedControlId);
    if (isHTMLElement(controlElement)) {
      focusElementWithVisible(controlElement);
    }
  }
  function handleInteraction(event) {
    const target = getTarget(event.nativeEvent);
    if (target?.closest("button,input,select,textarea")) {
      return;
    }
    if (!event.defaultPrevented && event.detail > 1) {
      event.preventDefault();
    }
    if (native) {
      return;
    }
    focusControl(event);
  }
  return native ? {
    id,
    htmlFor: resolvedControlId ?? void 0,
    onMouseDown: handleInteraction
  } : {
    id,
    onClick: handleInteraction,
    onPointerDown(event) {
      event.preventDefault();
    }
  };
}
function focusElementWithVisible(element) {
  element.focus({
    // Available from Chrome 144+ (January 2026).
    // Safari and Firefox already support it.
    focusVisible: true
  });
}

// node_modules/@base-ui/react/slider/label/SliderLabel.mjs
var SliderLabel = /* @__PURE__ */ React21.forwardRef(function SliderLabel2(componentProps, forwardedRef) {
  const {
    render,
    className,
    style,
    ...elementProps
  } = componentProps;
  const elementPropsWithoutId = elementProps;
  delete elementPropsWithoutId.id;
  const {
    state,
    setLabelId,
    controlRef,
    rootLabelId
  } = useSliderRootContext();
  function focusControl(event, controlId) {
    if (controlId) {
      const controlElement = ownerDocument(event.currentTarget).getElementById(controlId);
      if (isHTMLElement(controlElement)) {
        focusElementWithVisible(controlElement);
        return;
      }
    }
    const fallbackInputs = controlRef.current?.querySelectorAll('input[type="range"]');
    const fallbackInput = fallbackInputs?.length === 1 ? fallbackInputs[0] : null;
    if (isHTMLElement(fallbackInput)) {
      focusElementWithVisible(fallbackInput);
    }
  }
  const labelProps = useLabel({
    id: rootLabelId,
    setLabelId,
    focusControl
  });
  return useRenderElement("div", componentProps, {
    ref: forwardedRef,
    state,
    props: [labelProps, elementProps],
    stateAttributesMapping: sliderStateAttributesMapping
  });
});
if (true) SliderLabel.displayName = "SliderLabel";

// node_modules/@base-ui/react/slider/value/SliderValue.mjs
var React22 = __toESM(require_react(), 1);

// node_modules/@base-ui/react/utils/stringifyLocale.mjs
function stringifyLocale(locale) {
  if (Array.isArray(locale)) {
    return locale.map((value) => stringifyLocale(value)).join(",");
  }
  if (locale == null) {
    return "";
  }
  return String(locale);
}

// node_modules/@base-ui/react/utils/formatNumber.mjs
var cache = /* @__PURE__ */ new Map();
function getFormatter(locale, options) {
  const optionsString = JSON.stringify({
    locale: stringifyLocale(locale),
    options
  });
  const cachedFormatter = cache.get(optionsString);
  if (cachedFormatter) {
    return cachedFormatter;
  }
  const formatter = new Intl.NumberFormat(locale, options);
  cache.set(optionsString, formatter);
  return formatter;
}
function formatNumber(value, locale, options) {
  if (value == null) {
    return "";
  }
  return getFormatter(locale, options).format(value);
}

// node_modules/@base-ui/react/slider/value/SliderValue.mjs
var SliderValue = /* @__PURE__ */ React22.forwardRef(function SliderValue2(componentProps, forwardedRef) {
  const {
    "aria-live": ariaLive = "off",
    render,
    className,
    children,
    style,
    ...elementProps
  } = componentProps;
  const {
    thumbMap,
    state,
    values,
    formatOptionsRef,
    locale
  } = useSliderRootContext();
  let htmlFor = "";
  for (const thumbMetadata of thumbMap.values()) {
    if (thumbMetadata?.inputId) {
      htmlFor += `${thumbMetadata.inputId} `;
    }
  }
  const outputFor = htmlFor.trim() === "" ? void 0 : htmlFor.trim();
  const formattedValues = React22.useMemo(() => {
    const arr = [];
    for (let i = 0; i < values.length; i += 1) {
      arr.push(formatNumber(values[i], locale, formatOptionsRef.current ?? void 0));
    }
    return arr;
  }, [formatOptionsRef, locale, values]);
  const defaultDisplayValue = values.map((v, i) => formattedValues[i] || v).join(" \u2013 ");
  const element = useRenderElement("output", componentProps, {
    state,
    ref: forwardedRef,
    props: [{
      // off by default because it will keep announcing when the slider is being dragged
      // and also when the value is changing (but not yet committed)
      "aria-live": ariaLive,
      children: typeof children === "function" ? children(formattedValues, values) : defaultDisplayValue,
      htmlFor: outputFor
    }, elementProps],
    stateAttributesMapping: sliderStateAttributesMapping
  });
  return element;
});
if (true) SliderValue.displayName = "SliderValue";

// node_modules/@base-ui/react/slider/control/SliderControl.mjs
var React25 = __toESM(require_react(), 1);

// node_modules/@base-ui/utils/addEventListener.mjs
function addEventListener(target, type, listener, options) {
  target.addEventListener(type, listener, options);
  return () => {
    target.removeEventListener(type, listener, options);
  };
}

// node_modules/@base-ui/utils/useOnMount.mjs
var React23 = __toESM(require_react(), 1);
var EMPTY = [];
function useOnMount(fn) {
  React23.useEffect(fn, EMPTY);
}

// node_modules/@base-ui/utils/useAnimationFrame.mjs
var EMPTY2 = null;
var LAST_RAF = globalThis.requestAnimationFrame;
var Scheduler = class {
  constructor() {
    /* This implementation uses an array as a backing data-structure for frame callbacks.
     * It allows `O(1)` callback cancelling by inserting a `null` in the array, though it
     * never calls the native `cancelAnimationFrame` if there are no frames left. This can
     * be much more efficient if there is a call pattern that alterns as
     * "request-cancel-request-cancel-…".
     * But in the case of "request-request-…-cancel-cancel-…", it leaves the final animation
     * frame to run anyway. We turn that frame into a `O(1)` no-op via `callbacksCount`. */
    __publicField(this, "callbacks", []);
    __publicField(this, "callbacksCount", 0);
    __publicField(this, "nextId", 1);
    __publicField(this, "startId", 1);
    __publicField(this, "isScheduled", false);
    __publicField(this, "tick", (timestamp) => {
      this.isScheduled = false;
      const currentCallbacks = this.callbacks;
      const currentCallbacksCount = this.callbacksCount;
      this.callbacks = [];
      this.callbacksCount = 0;
      this.startId = this.nextId;
      if (currentCallbacksCount > 0) {
        for (let i = 0; i < currentCallbacks.length; i += 1) {
          currentCallbacks[i]?.(timestamp);
        }
      }
    });
  }
  request(fn) {
    const id = this.nextId;
    this.nextId += 1;
    this.callbacks.push(fn);
    this.callbacksCount += 1;
    const didRAFChange = LAST_RAF !== requestAnimationFrame && (LAST_RAF = requestAnimationFrame, true);
    if (!this.isScheduled || didRAFChange) {
      requestAnimationFrame(this.tick);
      this.isScheduled = true;
    }
    return id;
  }
  cancel(id) {
    const index = id - this.startId;
    if (index < 0 || index >= this.callbacks.length) {
      return;
    }
    this.callbacks[index] = null;
    this.callbacksCount -= 1;
  }
};
var scheduler = new Scheduler();
var AnimationFrame = class _AnimationFrame {
  constructor() {
    __publicField(this, "currentId", EMPTY2);
    __publicField(this, "cancel", () => {
      if (this.currentId !== EMPTY2) {
        scheduler.cancel(this.currentId);
        this.currentId = EMPTY2;
      }
    });
    __publicField(this, "disposeEffect", () => {
      return this.cancel;
    });
  }
  static create() {
    return new _AnimationFrame();
  }
  static request(fn) {
    return scheduler.request(fn);
  }
  static cancel(id) {
    return scheduler.cancel(id);
  }
  /**
   * Executes `fn` after `delay`, clearing any previously scheduled call.
   */
  request(fn) {
    this.cancel();
    this.currentId = scheduler.request(() => {
      this.currentId = EMPTY2;
      fn();
    });
  }
};
function useAnimationFrame() {
  const timeout = useRefWithInit(AnimationFrame.create).current;
  useOnMount(timeout.disposeEffect);
  return timeout;
}

// node_modules/@base-ui/react/internals/direction-context/DirectionContext.mjs
var React24 = __toESM(require_react(), 1);
var DirectionContext = /* @__PURE__ */ React24.createContext(void 0);
if (true) DirectionContext.displayName = "DirectionContext";
function useDirection() {
  const context = React24.useContext(DirectionContext);
  return context?.direction ?? "ltr";
}

// node_modules/@base-ui/react/slider/utils/getMidpoint.mjs
function getMidpoint(element) {
  const rect = element.getBoundingClientRect();
  return {
    x: (rect.left + rect.right) / 2,
    y: (rect.top + rect.bottom) / 2
  };
}

// node_modules/@base-ui/react/slider/utils/roundValueToStep.mjs
function getDecimalPrecision(num2) {
  if (num2 === 0) {
    return 0;
  }
  if (Math.abs(num2) < 1) {
    const parts = num2.toExponential().split("e-");
    const matissaDecimalPart = parts[0].split(".")[1];
    return (matissaDecimalPart ? matissaDecimalPart.length : 0) + parseInt(parts[1], 10);
  }
  const decimalPart = num2.toString().split(".")[1];
  return decimalPart ? decimalPart.length : 0;
}
function roundValueToStep(value, step, min) {
  const nearest = Math.round((value - min) / step) * step + min;
  return Number(nearest.toFixed(Math.max(getDecimalPrecision(step), getDecimalPrecision(min))));
}

// node_modules/@base-ui/react/slider/utils/getPushedThumbValues.mjs
function getPushedThumbValues({
  values,
  index,
  nextValue,
  min,
  max,
  step,
  minStepsBetweenValues,
  initialValues
}) {
  if (values.length === 0) {
    return [];
  }
  const nextValues = values.slice();
  const minValueDifference = step * minStepsBetweenValues;
  const lastIndex = nextValues.length - 1;
  const baseInitialValues = initialValues ?? values;
  const indexMin = min + index * minValueDifference;
  const indexMax = max - (lastIndex - index) * minValueDifference;
  nextValues[index] = clamp(nextValue, indexMin, indexMax);
  for (let i = index + 1; i <= lastIndex; i += 1) {
    const minAllowed = nextValues[i - 1] + minValueDifference;
    const maxAllowed = max - (lastIndex - i) * minValueDifference;
    const initialValue = baseInitialValues[i] ?? nextValues[i];
    let candidate = Math.max(nextValues[i], minAllowed);
    if (initialValue < candidate) {
      candidate = Math.max(initialValue, minAllowed);
    }
    nextValues[i] = clamp(candidate, minAllowed, maxAllowed);
  }
  for (let i = index - 1; i >= 0; i -= 1) {
    const maxAllowed = nextValues[i + 1] - minValueDifference;
    const minAllowed = min + i * minValueDifference;
    const initialValue = baseInitialValues[i] ?? nextValues[i];
    let candidate = Math.min(nextValues[i], maxAllowed);
    if (initialValue > candidate) {
      candidate = Math.min(initialValue, maxAllowed);
    }
    nextValues[i] = clamp(candidate, minAllowed, maxAllowed);
  }
  for (let i = 0; i <= lastIndex; i += 1) {
    nextValues[i] = Number(nextValues[i].toFixed(12));
  }
  return nextValues;
}

// node_modules/@base-ui/react/slider/utils/resolveThumbCollision.mjs
function resolveThumbCollision({
  behavior,
  values,
  currentValues,
  initialValues,
  pressedIndex,
  nextValue,
  min,
  max,
  step,
  minStepsBetweenValues
}) {
  const activeValues = currentValues ?? values;
  const baselineValues = initialValues ?? values;
  const range = activeValues.length > 1;
  if (!range) {
    return {
      value: nextValue,
      thumbIndex: 0,
      didSwap: false
    };
  }
  const minValueDifference = step * minStepsBetweenValues;
  switch (behavior) {
    case "swap": {
      const pressedInitialValue = activeValues[pressedIndex];
      const epsilon = 1e-7;
      const candidateValues = activeValues.slice();
      const previousNeighbor = candidateValues[pressedIndex - 1];
      const nextNeighbor = candidateValues[pressedIndex + 1];
      const lowerBound = previousNeighbor != null ? previousNeighbor + minValueDifference : min;
      const upperBound = nextNeighbor != null ? nextNeighbor - minValueDifference : max;
      const constrainedValue = clamp(nextValue, lowerBound, upperBound);
      const pressedValueAfterClamp = Number(constrainedValue.toFixed(12));
      candidateValues[pressedIndex] = pressedValueAfterClamp;
      const movingForward = nextValue > pressedInitialValue;
      const movingBackward = nextValue < pressedInitialValue;
      const shouldSwapForward = movingForward && nextNeighbor != null && nextValue >= nextNeighbor - epsilon;
      const shouldSwapBackward = movingBackward && previousNeighbor != null && nextValue <= previousNeighbor + epsilon;
      if (!shouldSwapForward && !shouldSwapBackward) {
        return {
          value: candidateValues,
          thumbIndex: pressedIndex,
          didSwap: false
        };
      }
      const targetIndex = shouldSwapForward ? pressedIndex + 1 : pressedIndex - 1;
      const initialValuesForPush = candidateValues.map((_, index) => {
        if (index === pressedIndex) {
          return pressedValueAfterClamp;
        }
        const baseline = baselineValues[index];
        if (baseline != null) {
          return baseline;
        }
        return activeValues[index];
      });
      let nextValueForTarget = nextValue;
      if (shouldSwapForward) {
        nextValueForTarget = Math.max(nextValue, candidateValues[targetIndex]);
      } else {
        nextValueForTarget = Math.min(nextValue, candidateValues[targetIndex]);
      }
      const adjustedValues = getPushedThumbValues({
        values: candidateValues,
        index: targetIndex,
        nextValue: nextValueForTarget,
        min,
        max,
        step,
        minStepsBetweenValues,
        initialValues: initialValuesForPush
      });
      const neighborIndex = shouldSwapForward ? targetIndex - 1 : targetIndex + 1;
      if (neighborIndex >= 0 && neighborIndex < adjustedValues.length) {
        const previousValue = adjustedValues[neighborIndex - 1];
        const nextValueAfter = adjustedValues[neighborIndex + 1];
        let neighborLowerBound = previousValue != null ? previousValue + minValueDifference : min;
        neighborLowerBound = Math.max(neighborLowerBound, min + neighborIndex * minValueDifference);
        let neighborUpperBound = nextValueAfter != null ? nextValueAfter - minValueDifference : max;
        neighborUpperBound = Math.min(neighborUpperBound, max - (adjustedValues.length - 1 - neighborIndex) * minValueDifference);
        const restoredValue = clamp(pressedValueAfterClamp, neighborLowerBound, neighborUpperBound);
        adjustedValues[neighborIndex] = Number(restoredValue.toFixed(12));
      }
      return {
        value: adjustedValues,
        thumbIndex: targetIndex,
        didSwap: true
      };
    }
    case "push": {
      const nextValues = getPushedThumbValues({
        values: activeValues,
        index: pressedIndex,
        nextValue,
        min,
        max,
        step,
        minStepsBetweenValues
      });
      return {
        value: nextValues,
        thumbIndex: pressedIndex,
        didSwap: false
      };
    }
    case "none":
    default: {
      const candidateValues = activeValues.slice();
      const previousNeighbor = candidateValues[pressedIndex - 1];
      const nextNeighbor = candidateValues[pressedIndex + 1];
      const lowerBound = previousNeighbor != null ? previousNeighbor + minValueDifference : min;
      const upperBound = nextNeighbor != null ? nextNeighbor - minValueDifference : max;
      const constrainedValue = clamp(nextValue, lowerBound, upperBound);
      candidateValues[pressedIndex] = Number(constrainedValue.toFixed(12));
      return {
        value: candidateValues,
        thumbIndex: pressedIndex,
        didSwap: false
      };
    }
  }
}

// node_modules/@base-ui/react/slider/control/SliderControl.mjs
var INTENTIONAL_DRAG_COUNT_THRESHOLD = 2;
function getControlOffset(styles, vertical) {
  if (!styles) {
    return {
      start: 0,
      end: 0
    };
  }
  function parseSize(value) {
    const parsed = value != null ? parseFloat(value) : 0;
    return Number.isNaN(parsed) ? 0 : parsed;
  }
  const start = !vertical ? "InlineStart" : "Top";
  const end = !vertical ? "InlineEnd" : "Bottom";
  return {
    start: parseSize(styles[`border${start}Width`]) + parseSize(styles[`padding${start}`]),
    end: parseSize(styles[`border${end}Width`]) + parseSize(styles[`padding${end}`])
  };
}
function getFingerCoords(event, touchIdRef) {
  if (touchIdRef.current != null && event.changedTouches) {
    const touchEvent = event;
    for (let i = 0; i < touchEvent.changedTouches.length; i += 1) {
      const touch = touchEvent.changedTouches[i];
      if (touch.identifier === touchIdRef.current) {
        return {
          x: touch.clientX,
          y: touch.clientY
        };
      }
    }
    return null;
  }
  return {
    x: event.clientX,
    y: event.clientY
  };
}
var SliderControl = /* @__PURE__ */ React25.forwardRef(function SliderControl2(componentProps, forwardedRef) {
  const {
    render: renderProp,
    className,
    style,
    ...elementProps
  } = componentProps;
  const {
    disabled: disabled2,
    dragging,
    inset,
    lastChangeReasonRef,
    max,
    min,
    minStepsBetweenValues,
    onValueCommitted,
    orientation,
    pressedInputRef,
    pressedThumbCenterOffsetRef,
    pressedThumbIndexRef,
    pressedValuesRef,
    registerFieldControlRef,
    renderBeforeHydration,
    setActive,
    setDragging,
    setValue,
    state,
    step,
    thumbCollisionBehavior,
    thumbRefs,
    values
  } = useSliderRootContext();
  const direction = useDirection();
  const range = values.length > 1;
  const vertical = orientation === "vertical";
  const controlRef = React25.useRef(null);
  const stylesRef = React25.useRef(null);
  const setStylesRef = useStableCallback((element2) => {
    if (element2 && stylesRef.current == null) {
      stylesRef.current = getWindow(element2).getComputedStyle(element2);
    }
  });
  const touchIdRef = React25.useRef(null);
  const moveCountRef = React25.useRef(0);
  const insetThumbOffsetRef = React25.useRef(0);
  const currentInteractionValueRef = React25.useRef(null);
  const latestValuesRef = useValueAsRef(values);
  function updatePressedThumb(nextIndex) {
    if (pressedThumbIndexRef.current !== nextIndex) {
      pressedThumbIndexRef.current = nextIndex;
    }
    const thumbElement = thumbRefs.current[nextIndex];
    if (!thumbElement) {
      pressedThumbCenterOffsetRef.current = null;
      pressedInputRef.current = null;
      return;
    }
    pressedInputRef.current = thumbElement.querySelector('input[type="range"]');
  }
  function resetPressedThumb() {
    pressedThumbIndexRef.current = -1;
    pressedThumbCenterOffsetRef.current = null;
    pressedInputRef.current = null;
  }
  function isTargetDisabledThumb(target) {
    if (!isElement(target)) {
      return false;
    }
    return thumbRefs.current.some((thumbEl) => {
      if (!isElement(thumbEl) || !contains(thumbEl, target)) {
        return false;
      }
      return thumbEl.querySelector('input[type="range"]')?.disabled === true;
    });
  }
  function getFingerState(fingerCoords) {
    const control = controlRef.current;
    const thumbIndex = pressedThumbIndexRef.current;
    if (!control || !range && (thumbIndex < 0 || thumbIndex >= values.length)) {
      return null;
    }
    const {
      width,
      height,
      bottom,
      left,
      right
    } = control.getBoundingClientRect();
    const controlOffset = getControlOffset(stylesRef.current, vertical);
    const insetThumbOffset = insetThumbOffsetRef.current;
    const controlSize = (vertical ? height : width) - controlOffset.start - controlOffset.end - insetThumbOffset * 2;
    const thumbCenterOffset = pressedThumbCenterOffsetRef.current ?? 0;
    const fingerX = fingerCoords.x - thumbCenterOffset;
    const fingerY = fingerCoords.y - thumbCenterOffset;
    const valueSize = vertical ? bottom - fingerY - controlOffset.end : (direction === "rtl" ? right - fingerX : fingerX - left) - controlOffset.start;
    const valueRescaled = clamp((valueSize - insetThumbOffset) / controlSize, 0, 1);
    let newValue = (max - min) * valueRescaled + min;
    newValue = roundValueToStep(newValue, step, min);
    newValue = clamp(newValue, min, max);
    if (!range) {
      return {
        value: newValue,
        thumbIndex,
        didSwap: false
      };
    }
    if (thumbIndex < 0) {
      return null;
    }
    const collisionResult = resolveThumbCollision({
      behavior: thumbCollisionBehavior,
      values,
      currentValues: latestValuesRef.current ?? values,
      initialValues: pressedValuesRef.current,
      pressedIndex: thumbIndex,
      nextValue: newValue,
      min,
      max,
      step,
      minStepsBetweenValues
    });
    return collisionResult;
  }
  function startPressing(fingerCoords) {
    pressedValuesRef.current = range ? values.slice() : null;
    currentInteractionValueRef.current = null;
    latestValuesRef.current = values;
    const pressedThumbIndex = pressedThumbIndexRef.current;
    let closestThumbIndex = pressedThumbIndex;
    if (pressedThumbIndex > -1 && pressedThumbIndex < values.length) {
      if (values[pressedThumbIndex] === max) {
        let candidateIndex = pressedThumbIndex;
        while (candidateIndex > 0 && values[candidateIndex - 1] === max) {
          candidateIndex -= 1;
        }
        closestThumbIndex = candidateIndex;
      }
    } else {
      const axis = !vertical ? "x" : "y";
      let minDistance;
      closestThumbIndex = -1;
      for (let i = 0; i < thumbRefs.current.length; i += 1) {
        const thumbEl = thumbRefs.current[i];
        if (isElement(thumbEl) && !thumbEl.querySelector('input[type="range"]')?.disabled) {
          const midpoint = getMidpoint(thumbEl);
          const distance = Math.abs(fingerCoords[axis] - midpoint[axis]);
          if (minDistance === void 0 || distance <= minDistance) {
            closestThumbIndex = i;
            minDistance = distance;
          }
        }
      }
    }
    if (closestThumbIndex > -1 && closestThumbIndex !== pressedThumbIndex) {
      updatePressedThumb(closestThumbIndex);
    }
    if (inset) {
      const thumbEl = thumbRefs.current[closestThumbIndex];
      if (isElement(thumbEl)) {
        const thumbRect = thumbEl.getBoundingClientRect();
        const side = !vertical ? "width" : "height";
        insetThumbOffsetRef.current = thumbRect[side] / 2;
      }
    }
  }
  function focusThumb(thumbIndex) {
    const input = thumbRefs.current?.[thumbIndex]?.querySelector('input[type="range"]');
    if (!input) {
      return;
    }
    input.focus({
      preventScroll: true,
      // Prevent pointer-driven focus rings in browsers that support this option.
      // Supported in Chrome from 144+.
      focusVisible: false
    });
  }
  function setValueFromPointer(finger, reason, nativeEvent) {
    const applied = setValue(finger.value, createChangeEventDetails(reason, nativeEvent, void 0, {
      activeThumbIndex: finger.thumbIndex
    }));
    if (applied) {
      currentInteractionValueRef.current = finger.value;
      latestValuesRef.current = Array.isArray(finger.value) ? finger.value : [finger.value];
      if (finger.didSwap) {
        updatePressedThumb(finger.thumbIndex);
      }
    }
    return applied;
  }
  const handleTouchMove = useStableCallback((nativeEvent) => {
    const fingerCoords = getFingerCoords(nativeEvent, touchIdRef);
    if (fingerCoords == null) {
      return;
    }
    moveCountRef.current += 1;
    if (nativeEvent.type === "pointermove" && nativeEvent.buttons === 0) {
      handleTouchEnd(nativeEvent);
      return;
    }
    const finger = getFingerState(fingerCoords);
    if (finger == null) {
      return;
    }
    if (validateMinimumDistance(finger.value, step, minStepsBetweenValues)) {
      if (!dragging && moveCountRef.current > INTENTIONAL_DRAG_COUNT_THRESHOLD) {
        setDragging(true);
      }
      const applied = setValueFromPointer(finger, reason_parts_exports.drag, nativeEvent);
      if (applied && finger.didSwap) {
        focusThumb(finger.thumbIndex);
      }
    }
  });
  const handleTouchEnd = useStableCallback((nativeEvent) => {
    setActive(-1);
    setDragging(false);
    pressedInputRef.current = null;
    pressedThumbCenterOffsetRef.current = null;
    if (currentInteractionValueRef.current != null) {
      const commitReason = lastChangeReasonRef.current;
      onValueCommitted(currentInteractionValueRef.current, createGenericEventDetails(commitReason, nativeEvent));
    }
    if ("pointerType" in nativeEvent && controlRef.current?.hasPointerCapture(nativeEvent.pointerId)) {
      controlRef.current?.releasePointerCapture(nativeEvent.pointerId);
    }
    pressedThumbIndexRef.current = -1;
    touchIdRef.current = null;
    pressedValuesRef.current = null;
    currentInteractionValueRef.current = null;
    stopListening();
  });
  const handleTouchStart = useStableCallback((nativeEvent) => {
    if (disabled2) {
      return;
    }
    if (isTargetDisabledThumb(getTarget(nativeEvent))) {
      resetPressedThumb();
      return;
    }
    const touch = nativeEvent.changedTouches[0];
    if (touch != null) {
      touchIdRef.current = touch.identifier;
    }
    const fingerCoords = getFingerCoords(nativeEvent, touchIdRef);
    if (fingerCoords != null) {
      startPressing(fingerCoords);
      const finger = getFingerState(fingerCoords);
      if (finger == null) {
        return;
      }
      focusThumb(finger.thumbIndex);
      const applied = setValueFromPointer(finger, reason_parts_exports.trackPress, nativeEvent);
      if (applied && finger.didSwap) {
        focusThumb(finger.thumbIndex);
      }
    }
    moveCountRef.current = 0;
    const doc = ownerDocument(controlRef.current);
    doc.addEventListener("touchmove", handleTouchMove, {
      passive: true
    });
    doc.addEventListener("touchend", handleTouchEnd, {
      passive: true
    });
  });
  const stopListening = useStableCallback(() => {
    const doc = ownerDocument(controlRef.current);
    doc.removeEventListener("pointermove", handleTouchMove);
    doc.removeEventListener("pointerup", handleTouchEnd);
    doc.removeEventListener("touchmove", handleTouchMove);
    doc.removeEventListener("touchend", handleTouchEnd);
    pressedValuesRef.current = null;
    currentInteractionValueRef.current = null;
  });
  const focusFrame = useAnimationFrame();
  React25.useEffect(() => {
    const control = controlRef.current;
    if (!control) {
      return () => stopListening();
    }
    const unsubscribeTouchStart = addEventListener(control, "touchstart", handleTouchStart, {
      passive: true
    });
    return () => {
      unsubscribeTouchStart();
      focusFrame.cancel();
      stopListening();
    };
  }, [stopListening, handleTouchStart, controlRef, focusFrame]);
  React25.useEffect(() => {
    if (disabled2) {
      stopListening();
    }
  }, [disabled2, stopListening]);
  const element = useRenderElement("div", componentProps, {
    state,
    ref: [forwardedRef, registerFieldControlRef, controlRef, setStylesRef],
    props: [{
      ["data-base-ui-slider-control"]: renderBeforeHydration ? "" : void 0,
      onPointerDown(event) {
        const control = controlRef.current;
        const target = getTarget(event.nativeEvent);
        if (!control || disabled2 || event.defaultPrevented || !isElement(target) || // Only handle left clicks
        event.button !== 0) {
          return;
        }
        if (isTargetDisabledThumb(target)) {
          resetPressedThumb();
          return;
        }
        const fingerCoords = getFingerCoords(event, touchIdRef);
        if (fingerCoords != null) {
          startPressing(fingerCoords);
          const finger = getFingerState(fingerCoords);
          if (finger == null) {
            return;
          }
          const pressedOnFocusedThumb = contains(thumbRefs.current[finger.thumbIndex], activeElement(ownerDocument(control)));
          if (pressedOnFocusedThumb) {
            event.preventDefault();
          } else {
            focusFrame.request(() => {
              focusThumb(finger.thumbIndex);
            });
          }
          setDragging(true);
          const pressedOnAnyThumb = pressedThumbCenterOffsetRef.current != null;
          if (!pressedOnAnyThumb) {
            const applied = setValueFromPointer(finger, reason_parts_exports.trackPress, event.nativeEvent);
            if (applied && finger.didSwap) {
              focusThumb(finger.thumbIndex);
            }
          }
        }
        if (event.nativeEvent.pointerId) {
          control.setPointerCapture(event.nativeEvent.pointerId);
        }
        moveCountRef.current = 0;
        const doc = ownerDocument(controlRef.current);
        doc.addEventListener("pointermove", handleTouchMove, {
          passive: true
        });
        doc.addEventListener("pointerup", handleTouchEnd, {
          once: true
        });
      }
    }, elementProps],
    stateAttributesMapping: sliderStateAttributesMapping
  });
  return element;
});
if (true) SliderControl.displayName = "SliderControl";

// node_modules/@base-ui/react/slider/track/SliderTrack.mjs
var React26 = __toESM(require_react(), 1);
var SliderTrack = /* @__PURE__ */ React26.forwardRef(function SliderTrack2(componentProps, forwardedRef) {
  const {
    render,
    className,
    style,
    ...elementProps
  } = componentProps;
  const {
    state
  } = useSliderRootContext();
  const element = useRenderElement("div", componentProps, {
    state,
    ref: forwardedRef,
    props: [{
      style: {
        position: "relative"
      }
    }, elementProps],
    stateAttributesMapping: sliderStateAttributesMapping
  });
  return element;
});
if (true) SliderTrack.displayName = "SliderTrack";

// node_modules/@base-ui/react/slider/thumb/SliderThumb.mjs
var React30 = __toESM(require_react(), 1);

// node_modules/@base-ui/utils/visuallyHidden.mjs
var visuallyHiddenBase = {
  clipPath: "inset(50%)",
  overflow: "hidden",
  whiteSpace: "nowrap",
  border: 0,
  padding: 0,
  width: 1,
  height: 1,
  margin: -1
};
var visuallyHidden = {
  ...visuallyHiddenBase,
  position: "fixed",
  top: 0,
  left: 0
};
var visuallyHiddenInput = {
  ...visuallyHiddenBase,
  position: "absolute"
};

// node_modules/@base-ui/react/utils/useIsHydrating.mjs
var import_shim = __toESM(require_shim(), 1);
function subscribe() {
  return NOOP;
}
function getSnapshot() {
  return false;
}
function getServerSnapshot() {
  return true;
}
function useIsHydrating() {
  return (0, import_shim.useSyncExternalStore)(subscribe, getSnapshot, getServerSnapshot);
}

// node_modules/@base-ui/react/utils/valueToPercent.mjs
function valueToPercent(value, min, max) {
  return (value - min) * 100 / (max - min);
}

// node_modules/@base-ui/react/internals/composite/composite.mjs
var ARROW_UP = "ArrowUp";
var ARROW_DOWN = "ArrowDown";
var ARROW_LEFT = "ArrowLeft";
var ARROW_RIGHT = "ArrowRight";
var HOME = "Home";
var END = "End";
var PAGE_UP = "PageUp";
var PAGE_DOWN = "PageDown";
var HORIZONTAL_KEYS = /* @__PURE__ */ new Set([ARROW_LEFT, ARROW_RIGHT]);
var VERTICAL_KEYS = /* @__PURE__ */ new Set([ARROW_UP, ARROW_DOWN]);
var ARROW_KEYS = /* @__PURE__ */ new Set([...HORIZONTAL_KEYS, ...VERTICAL_KEYS]);
var COMPOSITE_KEYS = /* @__PURE__ */ new Set([...ARROW_KEYS, HOME, END]);

// node_modules/@base-ui/react/internals/composite/list/useCompositeListItem.mjs
var React27 = __toESM(require_react(), 1);
var IndexGuessBehavior = /* @__PURE__ */ function(IndexGuessBehavior2) {
  IndexGuessBehavior2[IndexGuessBehavior2["None"] = 0] = "None";
  IndexGuessBehavior2[IndexGuessBehavior2["GuessFromOrder"] = 1] = "GuessFromOrder";
  return IndexGuessBehavior2;
}({});
function useCompositeListItem(params = {}) {
  const {
    label,
    metadata,
    textRef,
    indexGuessBehavior,
    index: externalIndex
  } = params;
  const {
    register,
    unregister,
    subscribeMapChange,
    elementsRef,
    labelsRef,
    nextIndexRef
  } = useCompositeListContext();
  const indexRef = React27.useRef(-1);
  const [index, setIndex] = React27.useState(externalIndex ?? (indexGuessBehavior === IndexGuessBehavior.GuessFromOrder ? () => {
    if (indexRef.current === -1) {
      const newIndex = nextIndexRef.current;
      nextIndexRef.current += 1;
      indexRef.current = newIndex;
    }
    return indexRef.current;
  } : -1));
  const componentRef = React27.useRef(null);
  const ref = React27.useCallback((node) => {
    componentRef.current = node;
    if (index !== -1 && node !== null) {
      elementsRef.current[index] = node;
      if (labelsRef) {
        const isLabelDefined = label !== void 0;
        labelsRef.current[index] = isLabelDefined ? label : textRef?.current?.textContent ?? node.textContent;
      }
    }
  }, [index, elementsRef, labelsRef, label, textRef]);
  useIsoLayoutEffect(() => {
    if (externalIndex != null) {
      return void 0;
    }
    const node = componentRef.current;
    if (node) {
      register(node, metadata);
      return () => {
        unregister(node);
      };
    }
    return void 0;
  }, [externalIndex, register, unregister, metadata]);
  useIsoLayoutEffect(() => {
    if (externalIndex != null) {
      return void 0;
    }
    return subscribeMapChange((map) => {
      const i = componentRef.current ? map.get(componentRef.current)?.index : null;
      if (i != null) {
        setIndex(i);
      }
    });
  }, [externalIndex, subscribeMapChange, setIndex]);
  return {
    ref,
    index
  };
}

// node_modules/@base-ui/react/internals/csp-context/CSPContext.mjs
var React28 = __toESM(require_react(), 1);
var CSPContext = /* @__PURE__ */ React28.createContext(void 0);
if (true) CSPContext.displayName = "CSPContext";
var DEFAULT_CSP_CONTEXT_VALUE = {
  disableStyleElements: false
};
function useCSPContext() {
  return React28.useContext(CSPContext) ?? DEFAULT_CSP_CONTEXT_VALUE;
}

// node_modules/@base-ui/react/internals/labelable-provider/useLabelableId.mjs
var React29 = __toESM(require_react(), 1);
function useLabelableId(params = {}) {
  const {
    id,
    implicit = false,
    controlRef
  } = params;
  const {
    controlId,
    registerControlId
  } = useLabelableContext();
  const defaultId = useBaseUiId(id);
  const controlIdForEffect = implicit ? controlId : void 0;
  const controlSourceRef = useRefWithInit(() => Symbol("labelable-control"));
  const hasRegisteredRef = React29.useRef(false);
  const hadExplicitIdRef = React29.useRef(id != null);
  const unregisterControlId = useStableCallback(() => {
    if (!hasRegisteredRef.current || registerControlId === NOOP) {
      return;
    }
    hasRegisteredRef.current = false;
    registerControlId(controlSourceRef.current, void 0);
  });
  useIsoLayoutEffect(() => {
    if (registerControlId === NOOP) {
      return void 0;
    }
    let nextId;
    if (implicit) {
      const elem = controlRef?.current;
      if (isElement(elem) && elem.closest("label") != null) {
        nextId = id ?? null;
      } else {
        nextId = controlIdForEffect ?? defaultId;
      }
    } else if (id != null) {
      hadExplicitIdRef.current = true;
      nextId = id;
    } else if (hadExplicitIdRef.current) {
      nextId = defaultId;
    } else {
      unregisterControlId();
      return void 0;
    }
    if (nextId === void 0) {
      unregisterControlId();
      return void 0;
    }
    hasRegisteredRef.current = true;
    registerControlId(controlSourceRef.current, nextId);
    return void 0;
  }, [id, controlRef, controlIdForEffect, registerControlId, implicit, defaultId, controlSourceRef, unregisterControlId]);
  React29.useEffect(() => {
    return unregisterControlId;
  }, [unregisterControlId]);
  return controlId ?? defaultId;
}

// node_modules/@base-ui/react/slider/thumb/SliderThumbDataAttributes.mjs
var SliderThumbDataAttributes = /* @__PURE__ */ function(SliderThumbDataAttributes2) {
  SliderThumbDataAttributes2["index"] = "data-index";
  SliderThumbDataAttributes2["dragging"] = "data-dragging";
  SliderThumbDataAttributes2["orientation"] = "data-orientation";
  SliderThumbDataAttributes2["disabled"] = "data-disabled";
  SliderThumbDataAttributes2["valid"] = "data-valid";
  SliderThumbDataAttributes2["invalid"] = "data-invalid";
  SliderThumbDataAttributes2["touched"] = "data-touched";
  SliderThumbDataAttributes2["dirty"] = "data-dirty";
  SliderThumbDataAttributes2["focused"] = "data-focused";
  return SliderThumbDataAttributes2;
}({});

// node_modules/@base-ui/react/slider/thumb/prehydrationScript.min.mjs
var script = '!function(){const t=document.currentScript?.parentElement;if(!t)return;const e=t.closest("[data-base-ui-slider-control]");if(!e)return;const r=e.querySelector("[data-base-ui-slider-indicator]"),i=e.getBoundingClientRect(),n="vertical"===e.getAttribute("data-orientation")?"height":"width",o=e.querySelectorAll(\'input[type="range"]\'),l=o.length>1,s=o.length-1;let a=null,u=null;for(let t=0;t<o.length;t+=1){const e=o[t],y=parseFloat(e.getAttribute("value")??"");if(Number.isNaN(y))return;const c=e.parentElement;if(!c)return;const p=parseFloat(e.getAttribute("max")??"100"),g=parseFloat(e.getAttribute("min")??"0"),b=c?.getBoundingClientRect(),d=i[n]-b[n],m=100*(y-g)/(p-g),v=(b[n]/2+d*m/100)/i[n]*100;c.style.setProperty("--position",`${v}%`),Number.isFinite(v)&&(c.style.removeProperty("visibility"),r&&(0===t?(a=v,r.style.setProperty("--start-position",`${v}%`),l||r.style.removeProperty("visibility")):t===s&&(u=v-(a??0),r.style.setProperty("--end-position",`${v}%`),r.style.setProperty("--relative-size",`${u}%`),r.style.removeProperty("visibility"))))}}();';

// node_modules/@base-ui/react/slider/thumb/SliderThumb.mjs
var import_jsx_runtime6 = __toESM(require_jsx_runtime(), 1);
var ALL_KEYS = /* @__PURE__ */ new Set([...COMPOSITE_KEYS, PAGE_UP, PAGE_DOWN]);
function getDefaultAriaValueText(values, index, format, locale) {
  if (index < 0) {
    return void 0;
  }
  if (values.length === 2) {
    if (index === 0) {
      return `${formatNumber(values[index], locale, format)} start range`;
    }
    return `${formatNumber(values[index], locale, format)} end range`;
  }
  return format ? formatNumber(values[index], locale, format) : void 0;
}
function getNewValue(thumbValue, increment, direction, min, max) {
  const value = direction === 1 ? thumbValue + increment : thumbValue - increment;
  const roundedValue = Number(value.toFixed(Math.max(getDecimalPrecision(thumbValue), getDecimalPrecision(increment), getDecimalPrecision(min))));
  return clamp(roundedValue, min, max);
}
var SliderThumb = /* @__PURE__ */ React30.forwardRef(function SliderThumb2(componentProps, forwardedRef) {
  const {
    render,
    children: childrenProp,
    className,
    "aria-describedby": ariaDescribedByProp,
    "aria-label": ariaLabelProp,
    "aria-labelledby": ariaLabelledByProp,
    "aria-valuetext": ariaValueTextProp,
    disabled: disabledProp = false,
    getAriaLabel: getAriaLabelProp,
    getAriaValueText: getAriaValueTextProp,
    id: idProp,
    index: indexProp,
    inputRef: inputRefProp,
    onBlur: onBlurProp,
    onFocus: onFocusProp,
    onKeyDown: onKeyDownProp,
    tabIndex: tabIndexProp,
    style,
    ...elementProps
  } = componentProps;
  const {
    nonce
  } = useCSPContext();
  const id = useBaseUiId(idProp);
  const {
    active: activeIndex,
    lastUsedThumbIndex,
    controlRef,
    disabled: contextDisabled,
    validation,
    formatOptionsRef,
    handleInputChange,
    inset,
    labelId,
    largeStep,
    locale,
    max,
    min,
    minStepsBetweenValues,
    form,
    name,
    orientation,
    pressedInputRef,
    pressedThumbCenterOffsetRef,
    pressedThumbIndexRef,
    renderBeforeHydration,
    setActive,
    setIndicatorPosition,
    state,
    step,
    values: sliderValues
  } = useSliderRootContext();
  const direction = useDirection();
  const disabled2 = disabledProp || contextDisabled;
  const range = sliderValues.length > 1;
  const vertical = orientation === "vertical";
  const rtl = direction === "rtl";
  const {
    setTouched,
    setFocused,
    validationMode
  } = useFieldRootContext();
  const thumbRef = React30.useRef(null);
  const inputRef = React30.useRef(null);
  const restoringFocusVisibleRef = React30.useRef(false);
  const defaultInputId = useBaseUiId();
  const labelableId = useLabelableId();
  const inputId = range ? defaultInputId : labelableId;
  const thumbMetadata = React30.useMemo(() => ({
    inputId
  }), [inputId]);
  const {
    ref: listItemRef,
    index: compositeIndex
  } = useCompositeListItem({
    metadata: thumbMetadata
  });
  const index = !range ? 0 : indexProp ?? compositeIndex;
  const last = index === sliderValues.length - 1;
  const thumbValue = sliderValues[index];
  const thumbValuePercent = valueToPercent(thumbValue, min, max);
  const [positionPercent, setPositionPercent] = React30.useState();
  const isHydrating = useIsHydrating();
  const safeLastUsedThumbIndex = lastUsedThumbIndex >= 0 && lastUsedThumbIndex < sliderValues.length ? lastUsedThumbIndex : -1;
  const getInsetPosition = useStableCallback(() => {
    const control = controlRef.current;
    const thumb = thumbRef.current;
    if (!control || !thumb) {
      return;
    }
    const thumbRect = thumb.getBoundingClientRect();
    const controlRect = control.getBoundingClientRect();
    const side = vertical ? "height" : "width";
    const controlSize = controlRect[side] - thumbRect[side];
    const thumbOffsetFromControlEdge = thumbRect[side] / 2 + controlSize * thumbValuePercent / 100;
    const nextPositionPercent = thumbOffsetFromControlEdge / controlRect[side] * 100;
    const nextInsetPosition = Number.isFinite(nextPositionPercent) ? nextPositionPercent : void 0;
    setPositionPercent(nextInsetPosition);
    if (index === 0) {
      setIndicatorPosition((prevPosition) => [nextInsetPosition, prevPosition[1]]);
    } else if (last) {
      setIndicatorPosition((prevPosition) => [prevPosition[0], nextInsetPosition]);
    }
  });
  useIsoLayoutEffect(() => {
    if (inset) {
      queueMicrotask(getInsetPosition);
    }
  }, [getInsetPosition, inset]);
  useIsoLayoutEffect(() => {
    if (inset) {
      getInsetPosition();
    }
  }, [getInsetPosition, inset, thumbValuePercent]);
  useIsoLayoutEffect(() => {
    if (!inset) {
      return void 0;
    }
    const control = controlRef.current;
    const thumb = thumbRef.current;
    if (!control || !thumb) {
      return void 0;
    }
    const ResizeObserverCtor = getWindow(control).ResizeObserver;
    if (typeof ResizeObserverCtor !== "function") {
      return void 0;
    }
    const resizeObserver = new ResizeObserverCtor(getInsetPosition);
    resizeObserver.observe(control);
    resizeObserver.observe(thumb);
    return () => {
      resizeObserver.disconnect();
    };
  }, [controlRef, getInsetPosition, inset]);
  const startEdge = vertical ? "bottom" : "insetInlineStart";
  const crossOffsetProperty = vertical ? "left" : "top";
  let zIndex;
  if (range) {
    if (activeIndex === index) {
      zIndex = 2;
    } else if (safeLastUsedThumbIndex === index) {
      zIndex = 1;
    }
  } else if (activeIndex === index) {
    zIndex = 1;
  }
  let thumbStyle;
  if (inset) {
    thumbStyle = {
      ["--position"]: `${positionPercent ?? 0}%`,
      visibility: renderBeforeHydration && isHydrating || positionPercent === void 0 ? "hidden" : void 0,
      position: "absolute",
      [startEdge]: "var(--position)",
      [crossOffsetProperty]: "50%",
      translate: `${(vertical || !rtl ? -1 : 1) * 50}% ${(vertical ? 1 : -1) * 50}%`,
      zIndex
    };
  } else {
    thumbStyle = !Number.isFinite(thumbValuePercent) ? visuallyHidden : {
      position: "absolute",
      [startEdge]: `${thumbValuePercent}%`,
      [crossOffsetProperty]: "50%",
      translate: `${(vertical || !rtl ? -1 : 1) * 50}% ${(vertical ? 1 : -1) * 50}%`,
      zIndex
    };
  }
  let cssWritingMode;
  if (orientation === "vertical") {
    cssWritingMode = rtl ? "vertical-rl" : "vertical-lr";
  }
  const ariaLabel = typeof getAriaLabelProp === "function" ? getAriaLabelProp(index) : ariaLabelProp;
  const inputProps = mergeProps({
    "aria-label": ariaLabel,
    "aria-labelledby": ariaLabelledByProp ?? (ariaLabel == null ? labelId : void 0),
    "aria-describedby": ariaDescribedByProp,
    "aria-orientation": orientation,
    "aria-valuenow": thumbValue,
    "aria-valuetext": typeof getAriaValueTextProp === "function" ? getAriaValueTextProp(formatNumber(thumbValue, locale, formatOptionsRef.current ?? void 0), thumbValue, index) : ariaValueTextProp ?? getDefaultAriaValueText(sliderValues, index, formatOptionsRef.current ?? void 0, locale),
    disabled: disabled2,
    form,
    id: inputId,
    max,
    min,
    name,
    onChange(event) {
      handleInputChange(event.currentTarget.valueAsNumber, index, event);
    },
    onFocus(event) {
      const isRestoringFocusVisible = restoringFocusVisibleRef.current;
      restoringFocusVisibleRef.current = false;
      setActive(index);
      setFocused(true);
      if (isRestoringFocusVisible) {
        event.stopPropagation();
      }
    },
    onBlur(event) {
      if (restoringFocusVisibleRef.current) {
        event.stopPropagation();
        return;
      }
      if (!thumbRef.current) {
        return;
      }
      setActive(-1);
      setTouched(true);
      setFocused(false);
      if (validationMode === "onBlur") {
        validation.commit(getSliderValue(thumbValue, index, min, max, range, sliderValues));
      }
    },
    onKeyDown(event) {
      if (event.defaultPrevented) {
        return;
      }
      if (!ALL_KEYS.has(event.key)) {
        return;
      }
      if (COMPOSITE_KEYS.has(event.key)) {
        event.stopPropagation();
      }
      let newValue = null;
      const roundedValue = roundValueToStep(thumbValue, step, min);
      switch (event.key) {
        case ARROW_UP:
          newValue = getNewValue(roundedValue, event.shiftKey ? largeStep : step, 1, min, max);
          break;
        case ARROW_RIGHT:
          newValue = getNewValue(roundedValue, event.shiftKey ? largeStep : step, rtl ? -1 : 1, min, max);
          break;
        case ARROW_DOWN:
          newValue = getNewValue(roundedValue, event.shiftKey ? largeStep : step, -1, min, max);
          break;
        case ARROW_LEFT:
          newValue = getNewValue(roundedValue, event.shiftKey ? largeStep : step, rtl ? 1 : -1, min, max);
          break;
        case PAGE_UP:
          newValue = getNewValue(roundedValue, largeStep, 1, min, max);
          break;
        case PAGE_DOWN:
          newValue = getNewValue(roundedValue, largeStep, -1, min, max);
          break;
        case END:
          newValue = max;
          if (range) {
            newValue = Number.isFinite(sliderValues[index + 1]) ? sliderValues[index + 1] - step * minStepsBetweenValues : max;
          }
          break;
        case HOME:
          newValue = min;
          if (range) {
            newValue = Number.isFinite(sliderValues[index - 1]) ? sliderValues[index - 1] + step * minStepsBetweenValues : min;
          }
          break;
        default:
          break;
      }
      if (newValue !== null) {
        const input = event.currentTarget;
        if (!matchesFocusVisible(input)) {
          restoringFocusVisibleRef.current = true;
          input.blur();
          input.focus({
            preventScroll: true,
            // Show `:focus-visible` after keyboard interaction, even if the
            // thumb was previously focused by a pointer.
            focusVisible: true
          });
        }
        handleInputChange(newValue, index, event);
        event.preventDefault();
      }
    },
    step,
    style: {
      ...visuallyHidden,
      // So that VoiceOver's focus indicator matches the thumb's dimensions
      width: "100%",
      height: "100%",
      writingMode: cssWritingMode
    },
    tabIndex: tabIndexProp ?? void 0,
    type: "range",
    value: thumbValue ?? ""
  }, (props) => validation.getValidationProps(disabled2, props), {
    onKeyDown: onKeyDownProp
  });
  const mergedInputRef = useMergedRefs(inputRef, validation.inputRef, inputRefProp);
  const element = useRenderElement("div", componentProps, {
    state,
    ref: [forwardedRef, listItemRef, thumbRef],
    props: [{
      [SliderThumbDataAttributes.index]: index,
      children: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(React30.Fragment, {
        children: [childrenProp, /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("input", {
          ref: mergedInputRef,
          ...inputProps,
          suppressHydrationWarning: true
        }), inset && isHydrating && renderBeforeHydration && // this must be rendered with the last thumb to ensure all
        // preceding thumbs are already rendered in the DOM
        last && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("script", {
          nonce,
          dangerouslySetInnerHTML: {
            __html: script
          },
          suppressHydrationWarning: true
        })]
      }),
      id,
      onBlur: onBlurProp,
      onFocus: onFocusProp,
      onPointerDown(event) {
        if (disabled2) {
          return;
        }
        pressedThumbIndexRef.current = index;
        if (thumbRef.current != null) {
          const axis = orientation === "horizontal" ? "x" : "y";
          const midpoint = getMidpoint(thumbRef.current);
          const offset = (orientation === "horizontal" ? event.clientX : event.clientY) - midpoint[axis];
          pressedThumbCenterOffsetRef.current = offset;
        }
        if (inputRef.current != null && pressedInputRef.current !== inputRef.current) {
          pressedInputRef.current = inputRef.current;
        }
      },
      style: thumbStyle,
      suppressHydrationWarning: renderBeforeHydration || void 0
    }, elementProps],
    stateAttributesMapping: sliderStateAttributesMapping
  });
  return element;
});
if (true) SliderThumb.displayName = "SliderThumb";

// node_modules/@base-ui/react/slider/indicator/SliderIndicator.mjs
var React31 = __toESM(require_react(), 1);
function getInsetStyles(vertical, range, start, end, renderBeforeHydration, hydrating) {
  const visibility = start === void 0 || range && end === void 0 ? "hidden" : void 0;
  const startEdge = vertical ? "bottom" : "insetInlineStart";
  const mainSide = vertical ? "height" : "width";
  const crossSide = vertical ? "width" : "height";
  const styles = {
    visibility: renderBeforeHydration && hydrating ? "hidden" : visibility,
    position: vertical ? "absolute" : "relative",
    [crossSide]: "inherit"
  };
  styles["--start-position"] = `${start ?? 0}%`;
  if (!range) {
    styles[startEdge] = 0;
    styles[mainSide] = "var(--start-position)";
    return styles;
  }
  styles["--relative-size"] = `${(end ?? 0) - (start ?? 0)}%`;
  styles[startEdge] = "var(--start-position)";
  styles[mainSide] = "var(--relative-size)";
  return styles;
}
function getCenteredStyles(vertical, range, start, end) {
  const startEdge = vertical ? "bottom" : "insetInlineStart";
  const mainSide = vertical ? "height" : "width";
  const crossSide = vertical ? "width" : "height";
  const styles = {
    position: vertical ? "absolute" : "relative",
    [crossSide]: "inherit"
  };
  if (!range) {
    styles[startEdge] = 0;
    styles[mainSide] = `${start}%`;
    return styles;
  }
  const size = end - start;
  styles[startEdge] = `${start}%`;
  styles[mainSide] = `${size}%`;
  return styles;
}
var SliderIndicator = /* @__PURE__ */ React31.forwardRef(function SliderIndicator2(componentProps, forwardedRef) {
  const {
    render,
    className,
    style: styleProp,
    ...elementProps
  } = componentProps;
  const {
    indicatorPosition,
    inset,
    max,
    min,
    orientation,
    renderBeforeHydration,
    state,
    values
  } = useSliderRootContext();
  const isHydrating = useIsHydrating();
  const vertical = orientation === "vertical";
  const range = values.length > 1;
  const style = inset ? getInsetStyles(vertical, range, indicatorPosition[0], indicatorPosition[1], renderBeforeHydration, isHydrating) : getCenteredStyles(vertical, range, valueToPercent(values[0], min, max), valueToPercent(values[values.length - 1], min, max));
  const element = useRenderElement("div", componentProps, {
    state,
    ref: forwardedRef,
    props: [{
      ["data-base-ui-slider-indicator"]: renderBeforeHydration ? "" : void 0,
      style,
      suppressHydrationWarning: renderBeforeHydration || void 0
    }, elementProps],
    stateAttributesMapping: sliderStateAttributesMapping
  });
  return element;
});
if (true) SliderIndicator.displayName = "SliderIndicator";

// src/presentation/components/ui/Slider.tsx
var import_jsx_runtime7 = __toESM(require_jsx_runtime(), 1);
function Slider({
  className,
  defaultValue,
  value,
  min = 0,
  max = 100,
  ...props
}) {
  const values = Array.isArray(value) ? value : Array.isArray(defaultValue) ? defaultValue : [min, max];
  return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
    index_parts_exports.Root,
    {
      className: cn(
        "data-[orientation=horizontal]:w-full data-[orientation=vertical]:h-full",
        className
      ),
      "data-slot": "slider",
      defaultValue,
      value,
      min,
      max,
      thumbAlignment: "edge",
      ...props,
      children: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(index_parts_exports.Control, { className: "relative flex w-full touch-none items-center select-none data-disabled:opacity-50 data-[orientation=vertical]:h-full data-[orientation=vertical]:min-h-40 data-[orientation=vertical]:w-auto data-[orientation=vertical]:flex-col", children: [
        /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
          index_parts_exports.Track,
          {
            "data-slot": "slider-track",
            className: "relative grow overflow-hidden rounded-full bg-input select-none data-[orientation=horizontal]:h-1.5 data-[orientation=horizontal]:w-full data-[orientation=vertical]:h-full data-[orientation=vertical]:w-1.5",
            children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
              index_parts_exports.Indicator,
              {
                "data-slot": "slider-range",
                className: "bg-primary select-none data-[orientation=horizontal]:h-full data-[orientation=vertical]:w-full"
              }
            )
          }
        ),
        Array.from({ length: values.length }, (_, index) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
          index_parts_exports.Thumb,
          {
            "data-slot": "slider-thumb",
            className: "relative block size-4 shrink-0 rounded-full border border-primary bg-background shadow-sm ring-ring/50 transition-[color,box-shadow] select-none after:absolute after:-inset-2 hover:ring-4 focus-visible:ring-4 focus-visible:outline-hidden active:ring-4 disabled:pointer-events-none disabled:opacity-50"
          },
          index
        ))
      ] })
    }
  );
}

// src/presentation/components/ui/Switch.tsx
var import_jsx_runtime8 = __toESM(require_jsx_runtime(), 1);

// src/widgets/primitives/WidgetLayout.tsx
var import_react5 = __toESM(require_react(), 1);
var import_jsx_runtime9 = __toESM(require_jsx_runtime(), 1);
function VisualSlot({ children }) {
  return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_jsx_runtime9.Fragment, { children });
}
function ControlsSlot({ children }) {
  return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_jsx_runtime9.Fragment, { children });
}
function AsideSlot({ children }) {
  return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_jsx_runtime9.Fragment, { children });
}
VisualSlot.__widgetSlot = "visual";
ControlsSlot.__widgetSlot = "controls";
AsideSlot.__widgetSlot = "aside";
function extractSlots(children) {
  const slots = {};
  import_react5.default.Children.forEach(children, (child) => {
    if (import_react5.default.isValidElement(child)) {
      const t = child.type;
      if (t?.__widgetSlot) {
        slots[t.__widgetSlot] = child;
      }
    }
  });
  return slots;
}
function WidgetLayoutImpl(props) {
  const arrangement = props.arrangement ?? "visual-left";
  const slots = extractSlots(props.children);
  return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: `readrun-widget readrun-widget--${arrangement}`, children: [
    (props.title || props.subtitle || props.headMeta) && /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
      "div",
      {
        className: "readrun-widget__head",
        style: { display: "flex", justifyContent: "space-between" },
        children: [
          /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { children: [
            props.title && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("h2", { className: "readrun-widget__title", children: props.title }),
            props.subtitle && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "readrun-widget__subtitle", children: props.subtitle })
          ] }),
          props.headMeta && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { children: props.headMeta })
        ]
      }
    ),
    /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "readrun-widget__body", children: [
      slots["visual"] && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "readrun-widget__visual", children: slots["visual"] }),
      (slots["controls"] || slots["aside"]) && /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "readrun-widget__sidebar", children: [
        slots["controls"] && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "readrun-widget__controls", children: slots["controls"] }),
        slots["aside"] && /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "readrun-widget__aside", children: [
          /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "readrun-widget__aside-label", children: "What to notice" }),
          slots["aside"]
        ] })
      ] })
    ] })
  ] });
}
var WidgetLayout = Object.assign(WidgetLayoutImpl, {
  Visual: VisualSlot,
  Controls: ControlsSlot,
  Aside: AsideSlot
});

// src/widgets/primitives/FormulaSteps.tsx
var import_react6 = __toESM(require_react(), 1);
var import_jsx_runtime10 = __toESM(require_jsx_runtime(), 1);

// src/widgets/primitives/index.tsx
function SectionLabel({
  children,
  style
}) {
  return /* @__PURE__ */ import_react7.default.createElement("div", { className: "viz-section-label", style }, children);
}
function Btn({
  kind = "ghost",
  active,
  children,
  ...rest
}) {
  const cls = `viz-btn viz-btn-${kind}${active ? " viz-btn-active" : ""}`;
  return /* @__PURE__ */ import_react7.default.createElement("button", { className: cls, ...rest }, children);
}
function Slider2({
  label,
  unit,
  min,
  max,
  step = 1,
  value,
  onChange,
  format
}) {
  const fmt = format || ((v) => Number.isFinite(v) ? v.toFixed(2) : String(v));
  const labelId = import_react7.default.useId();
  return /* @__PURE__ */ import_react7.default.createElement("div", { className: "viz-slider-row" }, /* @__PURE__ */ import_react7.default.createElement("div", { className: "viz-slider-head" }, /* @__PURE__ */ import_react7.default.createElement("span", { id: labelId }, label), /* @__PURE__ */ import_react7.default.createElement("span", { className: "viz-slider-value" }, fmt(value), unit && /* @__PURE__ */ import_react7.default.createElement("span", { className: "viz-slider-unit" }, unit))), /* @__PURE__ */ import_react7.default.createElement(
    Slider,
    {
      min,
      max,
      step,
      value: [value],
      onValueChange: (values) => {
        const next = typeof values === "number" ? values : values[0];
        if (typeof next === "number") onChange(next);
      },
      "aria-labelledby": labelId
    }
  ));
}
function Tabs({
  value,
  onChange,
  items
}) {
  return /* @__PURE__ */ import_react7.default.createElement("div", { className: "viz-tabs" }, items.map((it) => /* @__PURE__ */ import_react7.default.createElement(
    "button",
    {
      key: it.id,
      className: `viz-tab${value === it.id ? " active" : ""}`,
      onClick: () => onChange(it.id)
    },
    it.label
  )));
}
function Stat({
  label,
  value,
  color
}) {
  return /* @__PURE__ */ import_react7.default.createElement("span", { className: "viz-stat" }, /* @__PURE__ */ import_react7.default.createElement("span", null, label), /* @__PURE__ */ import_react7.default.createElement("strong", { className: "viz-stat-value", style: color ? { color } : void 0 }, value));
}
function LegendDot({ color, label }) {
  return /* @__PURE__ */ import_react7.default.createElement("span", { className: "viz-legend-dot" }, /* @__PURE__ */ import_react7.default.createElement("span", { className: "viz-dot", style: { background: color } }), label);
}

// docs/.readrun/widgets/git-graph-explorer.tsx
var import_jsx_runtime11 = __toESM(require_jsx_runtime(), 1);
var BRANCHES = [
  { id: "main", label: "main", color: "var(--text)" },
  { id: "feature", label: "feature/login", color: "var(--viz-trace)" },
  { id: "release", label: "release/1.2", color: "var(--viz-positive)" },
  { id: "hotfix", label: "hotfix/payments", color: "var(--viz-warn)" }
];
var MODES = [
  { id: "history", label: "History" },
  { id: "ancestry", label: "Ancestry" },
  { id: "refs", label: "Refs" }
];
var COMMITS = [
  {
    id: "a1e4c9",
    title: "initial app shell",
    branch: "main",
    parents: [],
    x: 0,
    y: 360,
    refs: ["tag: v1.0"]
  },
  {
    id: "b62011",
    title: "data loader",
    branch: "main",
    parents: ["a1e4c9"],
    x: 0,
    y: 320
  },
  {
    id: "c83b7a",
    title: "dashboard frame",
    branch: "main",
    parents: ["b62011"],
    x: 0,
    y: 280
  },
  {
    id: "d337ad",
    title: "login branch",
    branch: "feature",
    parents: ["c83b7a"],
    x: -150,
    y: 240
  },
  {
    id: "e7c125",
    title: "oauth callback",
    branch: "feature",
    parents: ["d337ad"],
    x: -150,
    y: 200,
    refs: ["feature/login"]
  },
  {
    id: "f40d72",
    title: "release branch",
    branch: "release",
    parents: ["c83b7a"],
    x: 150,
    y: 240
  },
  {
    id: "g91ab0",
    title: "payment patch",
    branch: "hotfix",
    parents: ["f40d72"],
    x: 275,
    y: 200,
    refs: ["hotfix/payments"]
  },
  {
    id: "h23df8",
    title: "merge hotfix",
    branch: "release",
    parents: ["f40d72", "g91ab0"],
    x: 150,
    y: 160,
    refs: ["release/1.2"]
  },
  {
    id: "i45a0b",
    title: "copy updates",
    branch: "main",
    parents: ["c83b7a"],
    x: 0,
    y: 220
  },
  {
    id: "j8c9e1",
    title: "merge login",
    branch: "main",
    parents: ["i45a0b", "e7c125"],
    x: 0,
    y: 120
  },
  {
    id: "k135aa",
    title: "ship release",
    branch: "main",
    parents: ["j8c9e1", "h23df8"],
    x: 0,
    y: 80,
    refs: ["main", "HEAD"]
  }
];
var STEPS = [
  {
    label: "init",
    command: 'git init\ngit add .\ngit commit -m "initial app shell"\ngit tag v1.0',
    description: "Repository starts on main with a single root commit.",
    branch: "main",
    visibleCount: 1,
    focusCommit: "a1e4c9",
    changes: ["Created package.json", "Created src/app.tsx", "Tagged baseline as v1.0"],
    result: "main and tag v1.0 point at a1e4c9."
  },
  {
    label: "commit",
    command: 'git commit -m "data loader"',
    description: "main advances by one ordinary commit.",
    branch: "main",
    visibleCount: 2,
    focusCommit: "b62011",
    changes: ["Added src/data/loaders.ts", "Updated README usage notes"],
    result: "HEAD moves from a1e4c9 to b62011."
  },
  {
    label: "commit",
    command: 'git commit -m "dashboard frame"',
    description: "A shared UI frame lands before branch work begins.",
    branch: "main",
    visibleCount: 3,
    focusCommit: "c83b7a",
    changes: ["Added src/dashboard/frame.tsx", "Adjusted layout styles"],
    result: "c83b7a becomes the common ancestor for later branches."
  },
  {
    label: "branch",
    command: 'git switch -c feature/login\ngit add src/auth/login-form.tsx\ngit commit -m "login branch"',
    description: "A feature branch forks from main, then records its first feature commit.",
    branch: "feature",
    visibleCount: 4,
    focusCommit: "d337ad",
    changes: ["Added login form scaffold", "No main files changed after branch point"],
    result: "feature/login points at d337ad while main remains at c83b7a."
  },
  {
    label: "commit",
    command: 'git commit -m "oauth callback"',
    description: "More work is committed on feature/login.",
    branch: "feature",
    visibleCount: 5,
    focusCommit: "e7c125",
    changes: ["Added src/auth/oauth.ts", "Updated tests for callback parsing"],
    result: "feature/login advances to e7c125."
  },
  {
    label: "branch",
    command: 'git switch -c release/1.2 c83b7a\ngit add docs/release-notes.md src/dashboard/copy.ts\ngit commit -m "release branch"',
    description: "A release branch starts from the stable dashboard frame, then commits release prep.",
    branch: "release",
    visibleCount: 6,
    focusCommit: "f40d72",
    changes: ["Prepared release notes", "Pinned dashboard copy for release"],
    result: "release/1.2 diverges from main and feature/login."
  },
  {
    label: "hotfix",
    command: 'git switch -c hotfix/payments\ngit add src/payments/checkout.ts src/payments/checkout.test.ts\ngit commit -m "payment patch"',
    description: "A short hotfix branch fixes release-critical payment behavior.",
    branch: "hotfix",
    visibleCount: 7,
    focusCommit: "g91ab0",
    changes: ["Patched src/payments/checkout.ts", "Added regression test"],
    result: "hotfix/payments points at g91ab0."
  },
  {
    label: "merge",
    command: "git switch release/1.2 && git merge hotfix/payments",
    description: "The hotfix is merged into the release branch.",
    branch: "release",
    visibleCount: 8,
    focusCommit: "h23df8",
    changes: ["Merged checkout fix into release/1.2", "No feature/login files included"],
    result: "h23df8 has two parents: f40d72 and g91ab0."
  },
  {
    label: "commit",
    command: 'git switch main && git commit -m "copy updates"',
    description: "main continues independently while branches are open.",
    branch: "main",
    visibleCount: 9,
    focusCommit: "i45a0b",
    changes: ["Edited src/dashboard/copy.ts", "Updated docs/changelog.md"],
    result: "main advances to i45a0b without pulling in feature/login yet."
  },
  {
    label: "merge",
    command: "git merge feature/login",
    description: "The login feature branch is merged back into main.",
    branch: "main",
    visibleCount: 10,
    focusCommit: "j8c9e1",
    changes: ["Integrated src/auth/oauth.ts", "Resolved dashboard route conflict"],
    result: "j8c9e1 joins main history with feature/login history."
  },
  {
    label: "merge",
    command: "git merge release/1.2",
    description: "Release branch changes and hotfix history are brought into main.",
    branch: "main",
    visibleCount: 11,
    focusCommit: "k135aa",
    changes: ["Brought payment hotfix into main", "Moved main and HEAD to final merge"],
    result: "HEAD and main now point at k135aa."
  }
];
function branchColor(branch) {
  return BRANCHES.find((b) => b.id === branch)?.color ?? "var(--text-muted)";
}
function isBranch(value) {
  return value === "main" || value === "feature" || value === "release" || value === "hotfix";
}
function refsOf(node) {
  return Array.isArray(node.refs) ? node.refs.filter((ref) => typeof ref === "string") : [];
}
function buildEdges(commits) {
  const ids = new Set(commits.map((commit) => commit.id));
  return commits.flatMap(
    (commit) => commit.parents.filter((parent) => ids.has(parent)).map((parent) => ({
      id: `${commit.id}-${parent}`,
      from: commit.id,
      to: parent,
      branch: commit.branch
    }))
  );
}
function ancestryIds(selectedId, commits) {
  const byId = new Map(commits.map((commit) => [commit.id, commit]));
  const out = /* @__PURE__ */ new Set([selectedId]);
  const stack = [selectedId];
  while (stack.length > 0) {
    const current = byId.get(stack.pop() ?? "");
    if (!current) continue;
    for (const parent of current.parents) {
      if (out.has(parent)) continue;
      out.add(parent);
      stack.push(parent);
    }
  }
  return out;
}
function toNodes(commits) {
  return commits.map((commit) => ({
    ...commit,
    label: commit.id,
    width: commit.parents.length > 1 ? 88 : 78,
    height: commit.parents.length > 1 ? 32 : 28
  }));
}
function edgeBranch(edge2) {
  return isBranch(edge2.branch) ? edge2.branch : "main";
}
function mergeCount(commits) {
  return commits.filter((commit) => commit.parents.length > 1).length;
}
function GitNode({
  node,
  selected,
  dimmed,
  onSelect
}) {
  const branch = isBranch(node.branch) ? node.branch : "main";
  const refs = refsOf(node);
  const color = branchColor(branch);
  const isMerge = Array.isArray(node.parents) && node.parents.length > 1;
  return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
    "g",
    {
      transform: `translate(${node.x - node.width / 2}, ${node.y - node.height / 2})`,
      onClick: () => onSelect(node.id),
      style: { cursor: "pointer", opacity: dimmed ? 0.25 : 1 },
      children: [
        /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
          "rect",
          {
            width: node.width,
            height: node.height,
            fill: "var(--bg)",
            stroke: selected ? "var(--text)" : color,
            strokeWidth: selected ? 2.5 : 1.5,
            rx: 0
          }
        ),
        /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("rect", { width: 6, height: node.height, fill: color }),
        isMerge && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
          "path",
          {
            d: `M ${node.width - 13} 7 L ${node.width - 6} ${node.height / 2} L ${node.width - 13} ${node.height - 7} L ${node.width - 20} ${node.height / 2} Z`,
            fill: "none",
            stroke: color,
            strokeWidth: 1.2
          }
        ),
        /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
          "text",
          {
            x: 14,
            y: node.height / 2 + 4,
            fontSize: 11,
            fill: "var(--text)",
            fontFamily: "var(--font-mono, ui-monospace, monospace)",
            style: { userSelect: "none" },
            children: node.id
          }
        ),
        refs.map((ref, index) => {
          const refWidth = Math.max(42, ref.length * 7 + 10);
          const refX = node.x > 170 ? -refWidth - 8 : node.width + 8;
          return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("g", { transform: `translate(${refX}, ${index * 18 - 2})`, children: [
            /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
              "rect",
              {
                width: refWidth,
                height: 15,
                fill: "var(--input-bg)",
                stroke: "var(--border)"
              }
            ),
            /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
              "text",
              {
                x: 5,
                y: 11,
                fontSize: 11,
                fill: "var(--text-muted)",
                fontFamily: "var(--font-mono, ui-monospace, monospace)",
                style: { userSelect: "none" },
                children: ref
              }
            )
          ] }, ref);
        })
      ]
    }
  );
}
function DetailRow({ label, value }) {
  return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { style: { display: "flex", justifyContent: "space-between", gap: 12 }, children: [
    /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { style: { color: "var(--text-muted)" }, children: label }),
    /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("strong", { style: { fontFamily: "var(--font-mono, ui-monospace, monospace)", textAlign: "right" }, children: value })
  ] });
}
function StepBadge({ step }) {
  return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
    "span",
    {
      style: {
        display: "inline-flex",
        alignItems: "center",
        border: "1px solid var(--border)",
        background: "var(--input-bg)",
        padding: "3px 7px",
        fontSize: 11,
        fontFamily: "var(--font-mono, ui-monospace, monospace)",
        color: "var(--text-muted)"
      },
      children: step.label
    }
  );
}
function GitGraphExplorer() {
  const [stepIndex, setStepIndex] = (0, import_react8.useState)(STEPS.length - 1);
  const [mode, setMode] = (0, import_react8.useState)("history");
  const [selectedId, setSelectedId] = (0, import_react8.useState)(STEPS[STEPS.length - 1]?.focusCommit ?? "");
  const step = STEPS[stepIndex] ?? STEPS[STEPS.length - 1];
  const visibleCommits = (0, import_react8.useMemo)(() => COMMITS.slice(0, step.visibleCount), [step.visibleCount]);
  const visibleIds = (0, import_react8.useMemo)(
    () => new Set(visibleCommits.map((commit) => commit.id)),
    [visibleCommits]
  );
  const refIds = (0, import_react8.useMemo)(
    () => new Set(visibleCommits.filter((commit) => commit.refs?.length).map((commit) => commit.id)),
    [visibleCommits]
  );
  const activeId = visibleIds.has(selectedId) ? selectedId : step.focusCommit;
  const selectedCommit = visibleIds.has(activeId) ? visibleCommits.find((commit) => commit.id === activeId) : visibleCommits[visibleCommits.length - 1];
  const focusedId = selectedCommit?.id ?? step.focusCommit;
  const ancestry = (0, import_react8.useMemo)(
    () => ancestryIds(focusedId, visibleCommits),
    [focusedId, visibleCommits]
  );
  const edges = (0, import_react8.useMemo)(() => buildEdges(visibleCommits), [visibleCommits]);
  const stepCommit = visibleIds.has(step.focusCommit) ? visibleCommits.find((commit) => commit.id === step.focusCommit) : void 0;
  const dimForMode = (id) => mode === "ancestry" && !ancestry.has(id) || mode === "refs" && !refIds.has(id) && id !== focusedId;
  const visibleRefs = visibleCommits.flatMap((commit) => commit.refs ?? []);
  return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
    WidgetLayout,
    {
      arrangement: "visual-left",
      title: "Git Graph Explorer",
      subtitle: "Scrub through Git commands and watch branch refs, merge commits, and file changes accumulate.",
      headMeta: /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_jsx_runtime11.Fragment, { children: [
        /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(Stat, { label: "commits", value: visibleCommits.length }),
        /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(Stat, { label: "merges", value: mergeCount(visibleCommits) })
      ] }),
      children: [
        /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(WidgetLayout.Visual, { children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { style: { padding: 12 }, children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
          Flow,
          {
            nodes: toNodes(visibleCommits),
            edges,
            layout: "manual",
            edgeRouter: "curve",
            width: 720,
            height: 430,
            draggable: false,
            renderEdge: (_, edge2, fromNode, toNode) => {
              const selectedEdge = focusedId === edge2.from || focusedId === edge2.to;
              const ancestryEdge = mode === "ancestry" && ancestry.has(edge2.from) && ancestry.has(edge2.to);
              const refEdge = mode === "refs" && (refIds.has(edge2.from) || refIds.has(edge2.to));
              const highlighted = selectedEdge || ancestryEdge || refEdge;
              const dimmed = mode === "ancestry" && !highlighted || mode === "refs" && !highlighted;
              const color = branchColor(edgeBranch(edge2));
              const midY = (fromNode.y + toNode.y) / 2;
              const path = `M ${fromNode.x} ${fromNode.y} C ${fromNode.x} ${midY}, ${toNode.x} ${midY}, ${toNode.x} ${toNode.y}`;
              return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
                "path",
                {
                  d: path,
                  fill: "none",
                  stroke: color,
                  strokeWidth: highlighted ? 2.5 : 1.4,
                  opacity: dimmed ? 0.18 : 0.75
                },
                edge2.id
              );
            },
            renderNode: (node) => /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
              GitNode,
              {
                node,
                selected: node.id === focusedId,
                dimmed: dimForMode(node.id),
                onSelect: setSelectedId
              }
            )
          }
        ) }) }),
        /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(WidgetLayout.Controls, { children: [
          /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
            Slider2,
            {
              label: "command step",
              min: 1,
              max: STEPS.length,
              step: 1,
              value: stepIndex + 1,
              onChange: (value) => {
                const nextIndex = value - 1;
                setStepIndex(nextIndex);
                const next = STEPS[nextIndex];
                if (next) setSelectedId(next.focusCommit);
              },
              format: (value) => `${value.toFixed(0)} / ${STEPS.length}`
            }
          ),
          /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { style: { display: "flex", gap: 8, alignItems: "center", marginBottom: 12 }, children: [
            /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(StepBadge, { step }),
            /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("strong", { children: step.description })
          ] }),
          /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(SectionLabel, { children: "Commands run" }),
          /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
            "pre",
            {
              style: {
                margin: "0 0 12px",
                padding: 10,
                overflowX: "auto",
                background: "var(--input-bg)",
                border: "1px solid var(--border)",
                color: "var(--text)",
                fontSize: 11,
                lineHeight: 1.45
              },
              children: step.command
            }
          ),
          /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(SectionLabel, { children: "What changed" }),
          /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("ul", { style: { margin: "0 0 12px", paddingLeft: 18, lineHeight: 1.55, fontSize: 11 }, children: step.changes.map((change) => /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("li", { children: change }, change)) }),
          /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { style: { display: "grid", gap: 7, fontSize: 11, marginBottom: 14 }, children: [
            /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(DetailRow, { label: "active branch", value: step.branch }),
            /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(DetailRow, { label: "focused commit", value: step.focusCommit }),
            /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(DetailRow, { label: "result", value: step.result }),
            stepCommit && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
              DetailRow,
              {
                label: "parents",
                value: stepCommit.parents.length ? stepCommit.parents.join(" ") : "root"
              }
            )
          ] }),
          /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(Tabs, { value: mode, onChange: (id) => setMode(id), items: MODES }),
          /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(SectionLabel, { style: { marginTop: 14 }, children: "Branches" }),
          /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { style: { display: "flex", flexDirection: "column", gap: 7, marginBottom: 14 }, children: BRANCHES.map((branch) => /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(LegendDot, { color: branch.color, label: branch.label }, branch.id)) }),
          selectedCommit && selectedCommit.id !== step.focusCommit && /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { style: { display: "grid", gap: 7, fontSize: 11 }, children: [
            /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(SectionLabel, { children: "Clicked commit" }),
            /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(DetailRow, { label: "sha", value: selectedCommit.id }),
            /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(DetailRow, { label: "message", value: selectedCommit.title })
          ] }),
          /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { style: { display: "flex", gap: 8, flexWrap: "wrap", marginTop: 14 }, children: [
            /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(Btn, { kind: "ghost", onClick: () => setSelectedId(COMMITS[0]?.id ?? ""), children: "Root" }),
            /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
              Btn,
              {
                kind: "ghost",
                onClick: () => setSelectedId(step.focusCommit),
                children: "Step focus"
              }
            )
          ] })
        ] }),
        /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(WidgetLayout.Aside, { children: /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("ul", { style: { margin: 0, paddingLeft: 18, lineHeight: 1.55 }, children: [
          /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("li", { children: "The slider is the story spine: each stop is one command and the graph only shows the commits that exist after that command." }),
          /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("li", { children: "The right panel names changed files, moved branches, parent links, and merge effects." }),
          /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("li", { children: visibleRefs.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_jsx_runtime11.Fragment, { children: [
            "Current visible refs: ",
            /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("code", { children: visibleRefs.join(", ") }),
            "."
          ] }) : "Move the scrubber forward to reveal branch and tag refs." })
        ] }) })
      ]
    }
  );
}

// docs/.readrun/widgets/git-graph-explorer.readrun-entry.ts
render(<GitGraphExplorer />);

/*! Bundled license information:

use-sync-external-store/cjs/use-sync-external-store-shim.development.js:
  (**
   * @license React
   * use-sync-external-store-shim.development.js
   *
   * Copyright (c) Meta Platforms, Inc. and affiliates.
   *
   * This source code is licensed under the MIT license found in the
   * LICENSE file in the root directory of this source tree.
   *)
*/